Skip to content

Commit 0b58959

Browse files
committed
Fix full qualified name for local classes
1 parent 63e48f8 commit 0b58959

File tree

3 files changed

+146
-32
lines changed

3 files changed

+146
-32
lines changed

src/main/kotlin/platform/mcp/at/completion/AtCompletionContributor.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import com.demonwav.mcdev.platform.mcp.at.gen.psi.AtTypes
3131
import com.demonwav.mcdev.util.anonymousElements
3232
import com.demonwav.mcdev.util.fullQualifiedName
3333
import com.demonwav.mcdev.util.getSimilarity
34+
import com.demonwav.mcdev.util.localClasses
3435
import com.demonwav.mcdev.util.nameAndParameterTypes
3536
import com.demonwav.mcdev.util.qualifiedMemberReference
3637
import com.demonwav.mcdev.util.simpleQualifiedMemberReference
@@ -157,6 +158,17 @@ class AtCompletionContributor : CompletionContributor() {
157158
),
158159
)
159160
}
161+
162+
for (localClass in currentClass.localClasses) {
163+
val name = localClass.fullQualifiedName ?: continue
164+
result.addElement(
165+
PrioritizedLookupElement.withPriority(
166+
LookupElementBuilder.create(name).withIcon(PlatformIcons.CLASS_ICON),
167+
1.0,
168+
),
169+
)
170+
}
171+
160172
return
161173
}
162174

src/main/kotlin/platform/mixin/util/AsmUtil.kt

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ import com.demonwav.mcdev.util.findModule
3131
import com.demonwav.mcdev.util.findQualifiedClass
3232
import com.demonwav.mcdev.util.fullQualifiedName
3333
import com.demonwav.mcdev.util.hasSyntheticMethod
34+
import com.demonwav.mcdev.util.innerIndexAndName
3435
import com.demonwav.mcdev.util.isErasureEquivalentTo
36+
import com.demonwav.mcdev.util.localClasses
3537
import com.demonwav.mcdev.util.lockedCached
3638
import com.demonwav.mcdev.util.loggerForTopLevel
3739
import com.demonwav.mcdev.util.mapToArray
@@ -285,29 +287,65 @@ private fun ClassNode.constructClass(project: Project, body: String): PsiClass?
285287
append(outerClassSimpleName)
286288
append(" {\n")
287289
var indent = " "
290+
val closingBraces = mutableListOf("}")
288291
for ((index, innerClass) in innerClasses.withIndex()) {
289-
val anonymousIndex = innerClass.toIntOrNull()
290-
if (anonymousIndex != null) {
291-
// add anonymous classes make the anonymous class index correct
292-
if (anonymousIndex in 1..999) {
293-
repeat(anonymousIndex - 1) { i ->
294-
append(indent)
295-
append("Object inner")
296-
append(i)
297-
append(" = new Object() {};\n")
292+
val innerIndexAndName = innerIndexAndName(innerClass)
293+
if (innerIndexAndName != null) {
294+
val (innerIndex, innerName) = innerIndexAndName
295+
if (innerIndex in 1..999) {
296+
if (innerName != null) {
297+
// add local classes to make the local class index correct
298+
repeat(innerIndex - 1) { i ->
299+
append(indent)
300+
append("static void method")
301+
append(i)
302+
append("() {\n")
303+
append(indent)
304+
append(" class ")
305+
append(innerName)
306+
append(" {}\n")
307+
append(indent)
308+
append("}\n")
309+
}
310+
} else {
311+
// add anonymous classes to make the anonymous class index correct
312+
repeat(innerIndex - 1) { i ->
313+
append(indent)
314+
append("Object inner")
315+
append(i)
316+
append(" = new Object() {};\n")
317+
}
298318
}
299319
}
320+
300321
append(indent)
301-
append("Object inner")
302-
append(anonymousIndex)
303-
append(" = new ")
304-
if (index == innerClasses.lastIndex) {
305-
val superName = superName ?: "java/lang/Object"
306-
append(superName.replace('/', '.').replace('$', '.'))
322+
if (innerName != null) {
323+
append("static void method")
324+
append(innerIndex)
325+
append("() {\n")
326+
closingBraces += "}"
327+
indent += " "
328+
append(indent)
329+
append("class ")
330+
append(innerName)
331+
if (index == innerClasses.lastIndex) {
332+
append("<T>")
333+
}
334+
append(" {\n")
335+
closingBraces += "}"
307336
} else {
308-
append("Object")
337+
append("Object inner")
338+
append(innerIndex)
339+
append(" = new ")
340+
if (index == innerClasses.lastIndex) {
341+
val superName = superName ?: "java/lang/Object"
342+
append(superName.replace('/', '.').replace('$', '.'))
343+
} else {
344+
append("Object")
345+
}
346+
append("() {\n")
347+
closingBraces += ");"
309348
}
310-
append("() {} {\n")
311349
} else {
312350
append(indent)
313351
if (index != innerClasses.lastIndex || hasAccess(Opcodes.ACC_STATIC)) {
@@ -319,18 +357,15 @@ private fun ClassNode.constructClass(project: Project, body: String): PsiClass?
319357
append("<T>")
320358
}
321359
append(" {\n")
360+
closingBraces += "}"
322361
}
323362
indent += " "
324363
}
325364
append(body.prependIndent(indent))
326-
repeat(innerClasses.size + 1) { i ->
365+
for (i in closingBraces.lastIndex downTo 0) {
327366
append("\n")
328-
append(" ".repeat(innerClasses.size - i))
329-
append("}")
330-
// append ; after anonymous class declarations
331-
if (i < innerClasses.size && innerClasses[innerClasses.size - 1 - i].toIntOrNull() != null) {
332-
append(";")
333-
}
367+
append(" ".repeat(i))
368+
append(closingBraces[i])
334369
}
335370
}
336371
val file = PsiFileFactory.getInstance(project).createFileFromText(
@@ -355,6 +390,7 @@ private fun ClassNode.constructClass(project: Project, body: String): PsiClass?
355390
while (true) {
356391
clazz = clazz.innerClasses.firstOrNull()
357392
?: clazz.anonymousElements.lastOrNull { it !== clazz && it is PsiClass } as? PsiClass
393+
?: clazz.localClasses.lastOrNull()
358394
?: break
359395
}
360396

src/main/kotlin/util/class-utils.kt

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ import com.intellij.navigation.AnonymousElementProvider
2525
import com.intellij.openapi.project.Project
2626
import com.intellij.psi.CommonClassNames
2727
import com.intellij.psi.JavaPsiFacade
28+
import com.intellij.psi.JavaRecursiveElementWalkingVisitor
29+
import com.intellij.psi.PsiAnonymousClass
2830
import com.intellij.psi.PsiClass
2931
import com.intellij.psi.PsiClassType
32+
import com.intellij.psi.PsiCompiledElement
3033
import com.intellij.psi.PsiElement
3134
import com.intellij.psi.PsiField
3235
import com.intellij.psi.PsiInvalidElementAccessException
@@ -36,6 +39,7 @@ import com.intellij.psi.PsiParameterList
3639
import com.intellij.psi.PsiPrimitiveType
3740
import com.intellij.psi.PsiTypeParameter
3841
import com.intellij.psi.search.GlobalSearchScope
42+
import com.intellij.psi.util.PsiUtil
3943

4044
val PsiClass.packageName
4145
get() = (containingFile as? PsiJavaFile)?.packageName
@@ -101,8 +105,14 @@ inline fun PsiClass.buildInnerName(builder: StringBuilder, getName: (PsiClass) -
101105
} else {
102106
parentClass = currentClass.parent.findContainingClass() ?: throw ClassNameResolutionFailedException()
103107

104-
// Add index of anonymous class to list
105-
list.add(parentClass.getAnonymousIndex(currentClass).toString())
108+
if (currentClass is PsiAnonymousClass) {
109+
// Add index of anonymous class to list
110+
list.add(parentClass.getAnonymousIndex(currentClass).toString())
111+
} else {
112+
// Add index and name of local class to list
113+
val currentName = currentClass.name ?: throw ClassNameResolutionFailedException()
114+
list.add(parentClass.getLocalIndex(currentClass).toString() + currentName)
115+
}
106116
}
107117

108118
currentClass = parentClass
@@ -157,21 +167,32 @@ fun findQualifiedClass(
157167
}
158168

159169
private fun PsiClass.findInnerClass(name: String): PsiClass? {
160-
val anonymousIndex = name.toIntOrNull()
161-
return if (anonymousIndex == null) {
170+
val innerIndexAndName = innerIndexAndName(name)
171+
return if (innerIndexAndName == null) {
162172
// Named inner class
163173
findInnerClassByName(name, false)
164174
} else {
165-
if (anonymousIndex > 0 && anonymousIndex <= anonymousElements.size) {
166-
anonymousElements[anonymousIndex - 1] as PsiClass
175+
val (innerIndex, innerName) = innerIndexAndName
176+
if (innerName != null) {
177+
val localClasses = this.localClasses.filter { it.name == innerName }
178+
if (innerIndex > 0 && innerIndex <= localClasses.size) {
179+
localClasses[innerIndex - 1]
180+
} else {
181+
null
182+
}
167183
} else {
168-
null
184+
if (innerIndex > 0 && innerIndex <= anonymousElements.size) {
185+
anonymousElements[innerIndex - 1] as PsiClass
186+
} else {
187+
null
188+
}
169189
}
170190
}
171191
}
172192

173193
@Throws(ClassNameResolutionFailedException::class)
174-
fun PsiElement.getAnonymousIndex(anonymousElement: PsiElement): Int {
194+
@PublishedApi
195+
internal fun PsiElement.getAnonymousIndex(anonymousElement: PsiElement): Int {
175196
// Attempt to find name for anonymous class
176197
for ((i, element) in anonymousElements.withIndex()) {
177198
if (element equivalentTo anonymousElement) {
@@ -194,6 +215,51 @@ val PsiElement.anonymousElements: Array<PsiElement>
194215
return emptyArray()
195216
}
196217

218+
@Throws(ClassNameResolutionFailedException::class)
219+
@PublishedApi
220+
internal fun PsiElement.getLocalIndex(localClass: PsiClass): Int {
221+
// Attempt to find index for local class
222+
var index = 0
223+
for (aLocalClass in localClasses) {
224+
if (aLocalClass.name == localClass.name) {
225+
index++
226+
if (aLocalClass equivalentTo localClass) {
227+
return index
228+
}
229+
}
230+
}
231+
232+
throw ClassNameResolutionFailedException("Failed to determine local class index for $localClass")
233+
}
234+
235+
val PsiElement.localClasses: List<PsiClass>
236+
get() {
237+
if (this is PsiCompiledElement) {
238+
return emptyList()
239+
}
240+
241+
val list = mutableListOf<PsiClass>()
242+
accept(object : JavaRecursiveElementWalkingVisitor() {
243+
override fun visitClass(clazz: PsiClass) {
244+
if (clazz === this@localClasses) {
245+
super.visitClass(clazz)
246+
} else {
247+
if (PsiUtil.isLocalClass(clazz)) {
248+
list += clazz
249+
}
250+
}
251+
}
252+
})
253+
return list
254+
}
255+
256+
private val INNER_INDEX_AND_NAME_REGEX = "(\\d+)(\\w*)".toRegex()
257+
fun innerIndexAndName(className: String): Pair<Int, String?>? {
258+
val (indexStr, name) = INNER_INDEX_AND_NAME_REGEX.matchEntire(className)?.destructured ?: return null
259+
val index = indexStr.toIntOrNull() ?: return null
260+
return index to name.ifEmpty { null }
261+
}
262+
197263
// Inheritance
198264

199265
fun PsiClass.extendsOrImplements(qualifiedClassName: String): Boolean {

0 commit comments

Comments
 (0)