diff --git a/analysis/symbol-light-classes/testData/structure/NestedClasses.lib.txt b/analysis/symbol-light-classes/testData/structure/NestedClasses.lib.txt new file mode 100644 index 00000000000..a8a7007d72e --- /dev/null +++ b/analysis/symbol-light-classes/testData/structure/NestedClasses.lib.txt @@ -0,0 +1,145 @@ +B.class: + KtClass: + line: 5 + name: NestedInB + qualifier: B.NestedInB + light: KtLightClassForDecompiledDeclaration + name: NestedInB + qualifier: B.NestedInB + superTypes: [ + PsiType:NestedInNestedInA + ] + superClass: KtLightClassForDecompiledDeclaration: NestedInNestedInA (A.NestedInA.NestedInNestedInA) + interfaces: [] + supers: [ + KtLightClassForDecompiledDeclaration: NestedInNestedInA (A.NestedInA.NestedInNestedInA) + ] + + KtClass: + line: 8 + name: InnerInB + qualifier: B.InnerInB + light: KtLightClassForDecompiledDeclaration + name: InnerInB + qualifier: B.InnerInB + superTypes: [ + PsiType:Object + ] + superClass: ClsClassImpl: Object (java.lang.Object) + interfaces: [] + supers: [ + ClsClassImpl: Object (java.lang.Object) + ] + + KtClass: + line: 4 + name: B + qualifier: B + light: KtLightClassForDecompiledDeclaration + name: B + qualifier: B + superTypes: [ + PsiType:A + ] + superClass: KtLightClassForDecompiledDeclaration: A (A) + interfaces: [] + supers: [ + KtLightClassForDecompiledDeclaration: A (A) + ] + +A.class: + KtClass: + line: 6 + name: NestedInNestedInA + qualifier: A.NestedInA.NestedInNestedInA + light: KtLightClassForDecompiledDeclaration + name: NestedInNestedInA + qualifier: A.NestedInA.NestedInNestedInA + superTypes: [ + PsiType:Object + ] + superClass: ClsClassImpl: Object (java.lang.Object) + interfaces: [] + supers: [ + ClsClassImpl: Object (java.lang.Object) + ] + + KtClass: + line: 9 + name: InnerInNestedInA + qualifier: A.NestedInA.InnerInNestedInA + light: KtLightClassForDecompiledDeclaration + name: InnerInNestedInA + qualifier: A.NestedInA.InnerInNestedInA + superTypes: [ + PsiType:Object + ] + superClass: ClsClassImpl: Object (java.lang.Object) + interfaces: [] + supers: [ + ClsClassImpl: Object (java.lang.Object) + ] + + KtClass: + line: 5 + name: NestedInA + qualifier: A.NestedInA + light: KtLightClassForDecompiledDeclaration + name: NestedInA + qualifier: A.NestedInA + superTypes: [ + PsiType:Object + ] + superClass: ClsClassImpl: Object (java.lang.Object) + interfaces: [] + supers: [ + ClsClassImpl: Object (java.lang.Object) + ] + + KtClass: + line: 14 + name: InnerInInnerInA + qualifier: A.InnerInA.InnerInInnerInA + light: KtLightClassForDecompiledDeclaration + name: InnerInInnerInA + qualifier: A.InnerInA.InnerInInnerInA + superTypes: [ + PsiType:Object + ] + superClass: ClsClassImpl: Object (java.lang.Object) + interfaces: [] + supers: [ + ClsClassImpl: Object (java.lang.Object) + ] + + KtClass: + line: 13 + name: InnerInA + qualifier: A.InnerInA + light: KtLightClassForDecompiledDeclaration + name: InnerInA + qualifier: A.InnerInA + superTypes: [ + PsiType:Object + ] + superClass: ClsClassImpl: Object (java.lang.Object) + interfaces: [] + supers: [ + ClsClassImpl: Object (java.lang.Object) + ] + + KtClass: + line: 4 + name: A + qualifier: A + light: KtLightClassForDecompiledDeclaration + name: A + qualifier: A + superTypes: [ + PsiType:Object + ] + superClass: ClsClassImpl: Object (java.lang.Object) + interfaces: [] + supers: [ + ClsClassImpl: Object (java.lang.Object) + ] diff --git a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesStructureTestBase.kt b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesStructureTestBase.kt index 4dd0882db27..0af090b806e 100644 --- a/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesStructureTestBase.kt +++ b/analysis/symbol-light-classes/tests/org/jetbrains/kotlin/light/classes/symbol/base/AbstractSymbolLightClassesStructureTestBase.kt @@ -12,7 +12,6 @@ import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator import org.jetbrains.kotlin.analysis.utils.printer.PrettyPrinter import org.jetbrains.kotlin.asJava.toLightClass -import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtEnumEntry import org.jetbrains.kotlin.psi.KtFile @@ -101,24 +100,14 @@ open class AbstractSymbolLightClassesStructureTestBase( }.toSet() private fun wrongInheritorStructure(line: String): Nothing = error("Can't parse '$line' line correctly") + protected fun PrettyPrinter.handleFile(ktFile: KtFile) { val text = ktFile.text if (ktFile.isCompiled) { - ktFile.declarations.forEach { classOrObject -> - if (classOrObject is KtClassOrObject) { - if (classOrObject is KtClass && classOrObject.isEnum()) { - classOrObject.declarations.forEach { declaration -> - if (declaration is KtEnumEntry) { - handleClassDeclaration(declaration, text) - appendLine() - } - } - } - - handleClassDeclaration(classOrObject, text) - appendLine() - } - } + // A compiled file for a class should only contain a single class declaration. `*Kt.class` files on the other hand may contain + // top-level callables and need to be skipped. + val classOrObject = ktFile.declarations.singleOrNull() as? KtClassOrObject ?: return + handleCompiledClassDeclaration(classOrObject, text) } else { ktFile.forEachDescendantOfType { classOrObject -> handleClassDeclaration(classOrObject, text) @@ -127,6 +116,26 @@ open class AbstractSymbolLightClassesStructureTestBase( } } + /** + * [handleCompiledClassDeclaration] uses a custom traversal instead of [forEachDescendantOfType] because trying to access the PSI of + * compiled code in this test results in exceptions. Hence, we have to traverse nested classes and enum entries manually. + */ + private fun PrettyPrinter.handleCompiledClassDeclaration(classOrObject: KtClassOrObject, text: String) { + classOrObject.declarations.forEach { declaration -> + when (declaration) { + is KtEnumEntry -> { + // We don't call `handleCompiledClassDeclaration` to avoid printing class declarations inside enum entry initializers. + handleClassDeclaration(declaration, text) + appendLine() + } + is KtClassOrObject -> handleCompiledClassDeclaration(declaration, text) + } + } + + handleClassDeclaration(classOrObject, text) + appendLine() + } + private fun PrettyPrinter.handleClassDeclaration(declaration: KtClassOrObject, fileText: String) { appendLine("${declaration::class.simpleName}:") withIndent {