1
+ package me.hydos.fukkitdevelopment
2
+
3
+ import com.google.gson.JsonDeserializationContext
4
+ import com.google.gson.JsonDeserializer
5
+ import com.google.gson.JsonElement
6
+ import com.intellij.openapi.project.Project
7
+ import com.intellij.psi.PsiClass
8
+ import com.intellij.psi.PsiField
9
+ import com.intellij.psi.PsiMember
10
+ import com.intellij.psi.PsiMethod
11
+ import com.intellij.psi.search.GlobalSearchScope
12
+ import com.intellij.util.containers.stream
13
+ import java.io.Serializable
14
+ import java.lang.reflect.Type
15
+ import java.util.stream.Stream
16
+
17
+ /* *
18
+ * Represents a reference to a class member (a method or a field). It may
19
+ * resolve to multiple members if [matchAll] is set or if the member is
20
+ * not full qualified.
21
+ */
22
+ data class MemberReference (
23
+ val name : String ,
24
+ val descriptor : String? = null ,
25
+ val owner : String? = null ,
26
+ val matchAll : Boolean = false
27
+ ) : Serializable {
28
+
29
+ val qualified
30
+ get() = this .owner != null
31
+
32
+ val withoutOwner
33
+ get() = if (this .owner == null ) this else MemberReference (this .name, this .descriptor, null , this .matchAll)
34
+
35
+ fun matchOwner (psiClass : PsiClass ): Boolean {
36
+ return this .owner == null || this .owner == psiClass.fullQualifiedName
37
+ }
38
+
39
+ fun match (method : PsiMethod , qualifier : PsiClass ): Boolean {
40
+ return this .name == method.internalName && matchOwner(qualifier) &&
41
+ (this .descriptor == null || this .descriptor == method.descriptor)
42
+ }
43
+
44
+ fun match (field : PsiField , qualifier : PsiClass ): Boolean {
45
+ return this .name == field.name && matchOwner(qualifier) &&
46
+ (this .descriptor == null || this .descriptor == field.descriptor)
47
+ }
48
+
49
+ fun resolve (
50
+ project : Project ,
51
+ scope : GlobalSearchScope = GlobalSearchScope .allScope(project)
52
+ ): Pair <PsiClass , PsiMember >? {
53
+ return resolve(project, scope, ::Pair )
54
+ }
55
+
56
+ fun resolveMember (project : Project , scope : GlobalSearchScope = GlobalSearchScope .allScope(project)): PsiMember ? {
57
+ return resolve(project, scope) { _, member -> member }
58
+ }
59
+
60
+ private inline fun <R > resolve (project : Project , scope : GlobalSearchScope , ret : (PsiClass , PsiMember ) -> R ): R ? {
61
+ if (this .owner == null ) {
62
+ throw IllegalStateException (" Cannot resolve unqualified member reference (owner == null)" )
63
+ }
64
+
65
+ val psiClass = findQualifiedClass(project, this .owner, scope) ? : return null
66
+
67
+ val member: PsiMember ? = if (descriptor != null && descriptor.startsWith(' (' )) {
68
+ // Method, we assume there is only one (since this member descriptor is full qualified)
69
+ psiClass.findMethods(this , checkBases = true ).findAny().orElse(null )
70
+ } else {
71
+ // Field
72
+ psiClass.findField(this , checkBases = true )
73
+ }
74
+
75
+ return member?.let { ret(psiClass, member) }
76
+ }
77
+
78
+ object Deserializer : JsonDeserializer<MemberReference> {
79
+ override fun deserialize (json : JsonElement , type : Type , ctx : JsonDeserializationContext ): MemberReference {
80
+ val ref = json.asString
81
+ val className = ref.substringBefore(' #' )
82
+ val methodName = ref.substring(className.length + 1 , ref.indexOf(" (" ))
83
+ val methodDesc = ref.substring(className.length + methodName.length + 1 )
84
+ return MemberReference (methodName, methodDesc, className)
85
+ }
86
+ }
87
+ }
88
+
89
+ // Class
90
+
91
+ fun PsiClass.findMethods (member : MemberReference , checkBases : Boolean = false): Stream <PsiMethod > {
92
+ if (! member.matchOwner(this )) {
93
+ return Stream .empty()
94
+ }
95
+
96
+ val result = findMethodsByInternalName(member.name, checkBases)
97
+ return if (member.descriptor != null ) {
98
+ result.stream().filter { it.descriptor == member.descriptor }
99
+ } else {
100
+ result.stream()
101
+ }
102
+ }
103
+
104
+ fun PsiClass.findField (member : MemberReference , checkBases : Boolean = false): PsiField ? {
105
+ if (! member.matchOwner(this )) {
106
+ return null
107
+ }
108
+
109
+ val field = findFieldByName(member.name, checkBases) ? : return null
110
+ if (member.descriptor != null && member.descriptor != field.descriptor) {
111
+ return null
112
+ }
113
+
114
+ return field
115
+ }
116
+
117
+ // Method
118
+
119
+ val PsiMethod .memberReference
120
+ get() = MemberReference (internalName, descriptor)
121
+
122
+ val PsiMethod .qualifiedMemberReference
123
+ get() = MemberReference (internalName, descriptor, containingClass!! .fullQualifiedName)
124
+
125
+ fun PsiMethod.getQualifiedMemberReference (owner : PsiClass ): MemberReference {
126
+ return MemberReference (internalName, descriptor, owner.fullQualifiedName)
127
+ }
128
+
129
+ fun PsiMethod?.isSameReference (reference : PsiMethod ? ): Boolean =
130
+ this != null && (this == = reference || qualifiedMemberReference == reference?.qualifiedMemberReference)
131
+
132
+ // Field
133
+ val PsiField .simpleMemberReference
134
+ get() = MemberReference (name)
135
+
136
+ val PsiField .memberReference
137
+ get() = MemberReference (name, descriptor)
138
+
139
+ val PsiField .simpleQualifiedMemberReference
140
+ get() = MemberReference (name, null , containingClass!! .fullQualifiedName)
141
+
142
+ val PsiField .qualifiedMemberReference
143
+ get() = MemberReference (name, descriptor, containingClass!! .fullQualifiedName)
144
+
145
+ fun PsiField.getQualifiedMemberReference (owner : PsiClass ): MemberReference {
146
+ return MemberReference (name, descriptor, owner.fullQualifiedName)
147
+ }
0 commit comments