From ef4c15a2c8c9073b413c4a7a59524f9a1ba11a2c Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Fri, 25 Apr 2014 16:26:36 +0400 Subject: [PATCH] Implement getDebugText() which should be used instead of getText() for debug purposes --- .../jetbrains/jet/lang/psi/DebugTextUtil.kt | 344 ++++++++++++++++++ .../jetbrains/jet/lang/psi/JetEnumEntry.java | 9 +- .../psi/JetTypeParameterListOwnerStub.java | 2 +- .../jet/plugin/stubs/DebugTextByStubTest.kt | 226 ++++++++++++ 4 files changed, 578 insertions(+), 3 deletions(-) create mode 100644 compiler/frontend/src/org/jetbrains/jet/lang/psi/DebugTextUtil.kt create mode 100644 idea/tests/org/jetbrains/jet/plugin/stubs/DebugTextByStubTest.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/DebugTextUtil.kt b/compiler/frontend/src/org/jetbrains/jet/lang/psi/DebugTextUtil.kt new file mode 100644 index 00000000000..6f0c144970d --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/DebugTextUtil.kt @@ -0,0 +1,344 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.psi.debugText + +import org.jetbrains.jet.lang.psi.JetElementImplStub +import org.jetbrains.jet.lang.psi.JetElement +import org.jetbrains.jet.lang.psi.JetClass +import org.jetbrains.jet.lang.psi.JetVisitor +import org.jetbrains.jet.lang.psi.JetModifierList +import org.jetbrains.jet.lang.psi.JetTypeParameterList +import org.jetbrains.jet.lang.psi.JetParameterList +import org.jetbrains.jet.lang.psi.JetDelegationSpecifierList +import org.jetbrains.jet.lang.psi.JetClassBody +import org.jetbrains.jet.lang.psi.JetStubbedPsiUtil +import org.jetbrains.jet.lang.psi.JetAnnotation +import org.jetbrains.jet.lang.psi.JetAnnotationEntry +import org.jetbrains.jet.lang.psi.JetClassInitializer +import org.jetbrains.jet.lang.psi.JetClassObject +import org.jetbrains.jet.lang.psi.JetConstructorCalleeExpression +import org.jetbrains.jet.lang.psi.JetDelegationSpecifier +import org.jetbrains.jet.lang.psi.JetDotQualifiedExpression +import org.jetbrains.jet.lang.psi.JetEnumEntry +import org.jetbrains.jet.lang.psi.JetInitializerList +import org.jetbrains.jet.lang.psi.JetFunctionType +import org.jetbrains.jet.lang.psi.JetTypeReference +import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.lang.psi.JetNamedFunction +import org.jetbrains.jet.lang.psi.JetTypeConstraintList +import org.jetbrains.jet.lang.psi.JetSimpleNameExpression +import org.jetbrains.jet.lang.psi.JetNullableType +import org.jetbrains.jet.lang.psi.JetObjectDeclaration +import org.jetbrains.jet.lang.psi.JetParameter +import org.jetbrains.jet.lang.psi.JetProperty +import org.jetbrains.jet.lang.psi.JetPropertyAccessor +import org.jetbrains.jet.lang.psi.JetTypeArgumentList +import org.jetbrains.jet.lang.psi.JetTypeConstraint +import org.jetbrains.jet.lang.psi.JetTypeParameter +import org.jetbrains.jet.lang.psi.JetTypeProjection +import org.jetbrains.jet.lang.psi.JetUserType +import com.intellij.openapi.diagnostic.Logger +import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.lang.psi.JetPackageDirective +import org.jetbrains.jet.lang.psi.JetImportDirective +import org.jetbrains.jet.lang.psi.JetImportList + +// invoke this instead of getText() when you need debug text to identify some place in PSI without storing the element itself +// this is need to avoid unnecessary file parses +// this defaults to get text if the element is not stubbed +public fun JetElement.getDebugText(): String? { + if (this !is JetElementImplStub<*> || this.getStub() == null) { + return getText() + } + if (this is JetPackageDirective) { + val fqName = getFqName() + if (fqName.isRoot()) { + return "" + } + return "package " + fqName.asString() + } + return accept(DebugTextBuildingVisitor, Unit.VALUE) +} + + +private object DebugTextBuildingVisitor : JetVisitor() { + + private val LOG = Logger.getInstance(this.javaClass) + + override fun visitJetFile(file: JetFile, data: Unit?): String? { + return "STUB file: ${file.getName()}" + } + + override fun visitJetElement(element: JetElement, data: Unit?): String? { + if (element is JetElementImplStub<*>) { + LOG.error("getDebugText() is not defined for ${element.getClass()}") + } + return element.getText() + } + + override fun visitImportDirective(importDirective: JetImportDirective, data: Unit?): String? { + val importPath = importDirective.getImportPath() + if (importPath == null) { + return "import " + } + val aliasStr = if (importPath.hasAlias()) " as " + importPath.getAlias()!!.asString() else "" + return "import ${importPath.getPathStr()}" + aliasStr + } + + override fun visitImportList(importList: JetImportList, data: Unit?): String? { + return renderChildren(importList, separator = "\n") + } + + override fun visitAnnotationEntry(annotationEntry: JetAnnotationEntry, data: Unit?): String? { + return render(annotationEntry, annotationEntry.getCalleeExpression(), annotationEntry.getTypeArgumentList()) + } + + override fun visitTypeReference(typeReference: JetTypeReference, data: Unit?): String? { + return renderChildren(typeReference, " ") + } + + override fun visitTypeArgumentList(typeArgumentList: JetTypeArgumentList, data: Unit?): String? { + return renderChildren(typeArgumentList, ", ", "<", ">") + } + + override fun visitTypeConstraintList(list: JetTypeConstraintList, data: Unit?): String? { + return renderChildren(list, ", ", "where ", "") + } + + override fun visitUserType(userType: JetUserType, data: Unit?): String? { + return render(userType, userType.getQualifier(), userType.getReferenceExpression(), userType.getTypeArgumentList()) + } + + override fun visitAnnotation(annotation: JetAnnotation, data: Unit?): String? { + return renderChildren(annotation, " ", "[", "]") + } + + override fun visitConstructorCalleeExpression(constructorCalleeExpression: JetConstructorCalleeExpression, data: Unit?): String? { + return render(constructorCalleeExpression, constructorCalleeExpression.getConstructorReferenceExpression()) + } + + override fun visitDelegationSpecifier(specifier: JetDelegationSpecifier, data: Unit?): String? { + return render(specifier, specifier.getTypeReference()) + } + + override fun visitDelegationSpecifierList(list: JetDelegationSpecifierList, data: Unit?): String? { + return renderChildren(list, ", ") + } + + override fun visitTypeParameterList(list: JetTypeParameterList, data: Unit?): String? { + return renderChildren(list, ", ", "<", ">") + } + + override fun visitDotQualifiedExpression(expression: JetDotQualifiedExpression, data: Unit?): String? { + return renderChildren(expression, ".") + } + + override fun visitInitializerList(list: JetInitializerList, data: Unit?): String? { + return renderChildren(list, ", ") + } + + override fun visitParameterList(list: JetParameterList, data: Unit?): String? { + return renderChildren(list, ", ", "(", ")") + } + + override fun visitEnumEntry(enumEntry: JetEnumEntry, data: Unit?): String? { + return buildText { + append("STUB: ") + appendInn(enumEntry.getModifierList(), suffix = " ") + append("enum entry ") + appendInn(enumEntry.getNameAsName()) + appendInn(enumEntry.getInitializerList(), prefix = " : ") + } + } + + override fun visitFunctionType(functionType: JetFunctionType, data: Unit?): String? { + return buildText { + appendInn(functionType.getReceiverTypeRef(), suffix = ".") + appendInn(functionType.getParameterList()) + appendInn(functionType.getReturnTypeRef(), prefix = " -> ") + } + } + + override fun visitTypeParameter(parameter: JetTypeParameter, data: Unit?): String? { + return buildText { + appendInn(parameter.getModifierList(), suffix = " ") + appendInn(parameter.getNameAsName()) + appendInn(parameter.getExtendsBound(), prefix = " : ") + } + } + + override fun visitTypeProjection(typeProjection: JetTypeProjection, data: Unit?): String? { + return buildText { + val token = typeProjection.getProjectionKind().getToken() + appendInn(token?.getValue()) + val typeReference = typeProjection.getTypeReference() + if (token != null && typeReference != null) { + append(" ") + } + appendInn(typeReference) + } + } + + override fun visitModifierList(list: JetModifierList, data: Unit?): String? { + return buildText { + var first = true + for (modifierKeywordToken in JetTokens.MODIFIER_KEYWORDS_ARRAY) { + if (list.hasModifier(modifierKeywordToken)) { + if (!first) { + append(" ") + } + append(modifierKeywordToken.getValue()) + first = false + } + } + } + } + + override fun visitSimpleNameExpression(expression: JetSimpleNameExpression, data: Unit?): String? { + return expression.getReferencedName() + } + + override fun visitNullableType(nullableType: JetNullableType, data: Unit?): String? { + return renderChildren(nullableType, "", "", "?") + } + + override fun visitAnonymousInitializer(initializer: JetClassInitializer, data: Unit?): String? { + val containingDeclaration = JetStubbedPsiUtil.getContainingDeclaration(initializer) + return "initializer in " + (containingDeclaration?.getDebugText() ?: "...") + } + + override fun visitClassObject(classObject: JetClassObject, data: Unit?): String? { + val containingDeclaration = JetStubbedPsiUtil.getContainingDeclaration(classObject) + return "class object in " + (containingDeclaration?.getDebugText() ?: "...") + } + + override fun visitClassBody(classBody: JetClassBody, data: Unit?): String? { + val containingDeclaration = JetStubbedPsiUtil.getContainingDeclaration(classBody) + return "class body for " + (containingDeclaration?.getDebugText() ?: "...") + } + + override fun visitPropertyAccessor(accessor: JetPropertyAccessor, data: Unit?): String? { + val containingProperty = JetStubbedPsiUtil.getContainingDeclaration(accessor, javaClass()) + val what = (if (accessor.isGetter()) "getter" else "setter") + return what + " for " + (if (containingProperty != null) containingProperty.getDebugText() else "...") + } + + override fun visitClass(klass: JetClass, data: Unit?): String? { + return buildText { + append("STUB: ") + appendInn(klass.getModifierList(), suffix = " ") + append("class ") + appendInn(klass.getNameAsName()) + appendInn(klass.getTypeParameterList()) + appendInn(klass.getPrimaryConstructorModifierList(), prefix = " ", suffix = " ") + appendInn(klass.getPrimaryConstructorParameterList()) + appendInn(klass.getDelegationSpecifierList(), prefix = " : ") + } + } + + override fun visitNamedFunction(function: JetNamedFunction, data: Unit?): String? { + return buildText { + append("STUB: ") + appendInn(function.getModifierList(), suffix = " ") + append("fun ") + + val typeParameterList = function.getTypeParameterList() + if (function.hasTypeParameterListBeforeFunctionName()) { + appendInn(typeParameterList, suffix = " ") + } + appendInn(function.getReceiverTypeRef(), suffix = ".") + appendInn(function.getNameAsName()) + if (!function.hasTypeParameterListBeforeFunctionName()) { + appendInn(typeParameterList) + } + appendInn(function.getValueParameterList()) + appendInn(function.getReturnTypeRef(), prefix = ": ") + appendInn(function.getTypeConstraintList(), prefix = " ") + } + } + + override fun visitObjectDeclaration(declaration: JetObjectDeclaration, data: Unit?): String? { + return buildText { + append("STUB: ") + appendInn(declaration.getModifierList(), suffix = " ") + append("object ") + appendInn(declaration.getNameAsName()) + appendInn(declaration.getDelegationSpecifierList(), prefix = " : ") + } + } + + override fun visitParameter(parameter: JetParameter, data: Unit?): String? { + return buildText { + if (parameter.hasValOrVarNode()) { + if (parameter.isMutable()) append("var ") else append("val ") + } + val name = parameter.getNameAsName() + appendInn(name) + val typeReference = parameter.getTypeReference() + if (typeReference != null && name != null) { + append(": ") + } + appendInn(typeReference) + } + } + + override fun visitProperty(property: JetProperty, data: Unit?): String? { + return buildText { + append("STUB: ") + appendInn(property.getModifierList(), suffix = " ") + append(if (property.isVar()) "var " else "val ") + appendInn(property.getNameAsName()) + appendInn(property.getTypeRef(), prefix = ": ") + } + } + + override fun visitTypeConstraint(constraint: JetTypeConstraint, data: Unit?): String? { + return buildText { + if (constraint.isClassObjectConstraint()) { + append("class object ") + } + appendInn(constraint.getSubjectTypeParameterName()) + appendInn(constraint.getBoundTypeReference(), prefix = " : ") + } + } + + fun buildText(body: StringBuilder.() -> Unit): String? { + val sb = StringBuilder() + sb.body() + return sb.toString() + } + + fun renderChildren(element: JetElementImplStub<*>, separator: String, prefix: String = "", postfix: String = ""): String? { + val childrenTexts = element.getStub()?.getChildrenStubs()?.map { (it?.getPsi() as? JetElement)?.getDebugText() } + return childrenTexts?.filterNotNull()?.makeString(separator, prefix, postfix) ?: element.getText() + } + + fun render(element: JetElementImplStub<*>, vararg relevantChildren: JetElement?): String? { + if (element.getStub() == null) return element.getText() + return relevantChildren.filterNotNull().map { it.getDebugText() }.makeString("", "", "") + } +} + +private fun StringBuilder.appendInn(target: Any?, prefix: String = "", suffix: String = "") { + if (target == null) return + append(prefix) + append(when (target) { + is JetElement -> target.getDebugText() + else -> target.toString() + }) + append(suffix) +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetEnumEntry.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetEnumEntry.java index 509ac45a95d..af8f378264c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetEnumEntry.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetEnumEntry.java @@ -21,7 +21,7 @@ import com.intellij.psi.PsiElement; import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub; import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes; @@ -63,13 +63,18 @@ public class JetEnumEntry extends JetClass { @NotNull @Override public List getDelegationSpecifiers() { - JetInitializerList initializerList = getStubOrPsiChild(JetStubElementTypes.INITIALIZER_LIST); + JetInitializerList initializerList = getInitializerList(); if (initializerList == null) { return Collections.emptyList(); } return initializerList.getInitializers(); } + @Nullable + public JetInitializerList getInitializerList() { + return getStubOrPsiChild(JetStubElementTypes.INITIALIZER_LIST); + } + @Override public R accept(@NotNull JetVisitor visitor, D data) { return visitor.visitEnumEntry(this, data); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTypeParameterListOwnerStub.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTypeParameterListOwnerStub.java index 4b8c712512c..259154c03e9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTypeParameterListOwnerStub.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetTypeParameterListOwnerStub.java @@ -41,7 +41,7 @@ abstract class JetTypeParameterListOwnerStub ext } @Nullable - JetTypeConstraintList getTypeConstraintList() { + public JetTypeConstraintList getTypeConstraintList() { return getStubOrPsiChild(JetStubElementTypes.TYPE_CONSTRAINT_LIST); } diff --git a/idea/tests/org/jetbrains/jet/plugin/stubs/DebugTextByStubTest.kt b/idea/tests/org/jetbrains/jet/plugin/stubs/DebugTextByStubTest.kt new file mode 100644 index 00000000000..ec54bf4decd --- /dev/null +++ b/idea/tests/org/jetbrains/jet/plugin/stubs/DebugTextByStubTest.kt @@ -0,0 +1,226 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.stubs + +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase +import org.jetbrains.jet.lang.psi.JetFile +import org.jetbrains.jet.lang.psi.stubs.elements.JetFileStubBuilder +import com.intellij.psi.stubs.StubElement +import org.jetbrains.jet.lang.psi.stubs.elements.JetStubElementTypes +import org.junit.Assert +import org.jetbrains.jet.lang.psi.JetPackageDirective +import org.jetbrains.jet.lang.psi.stubs.PsiJetPlaceHolderStub +import org.jetbrains.jet.lang.psi.JetImportList +import org.jetbrains.jet.lang.psi.JetNamedFunction +import org.jetbrains.jet.lang.psi.stubs.PsiJetFunctionStub +import org.jetbrains.jet.lang.psi.JetTypeReference +import org.jetbrains.jet.lang.psi.stubs.PsiJetClassStub +import org.jetbrains.jet.lang.psi.JetClass +import org.jetbrains.jet.lang.psi.stubs.PsiJetObjectStub +import org.jetbrains.jet.lang.psi.JetObjectDeclaration +import org.jetbrains.jet.lang.psi.JetProperty +import org.jetbrains.jet.lang.psi.stubs.PsiJetPropertyStub +import kotlin.test.assertEquals +import org.jetbrains.jet.lang.psi.JetClassBody +import org.jetbrains.jet.lang.psi.JetClassInitializer +import org.jetbrains.jet.lang.psi.JetClassObject +import org.jetbrains.jet.lang.psi.debugText.getDebugText + +public class DebugTextByStubTest : LightCodeInsightFixtureTestCase() { + private fun createFileAndStubTree(text: String): Pair> { + val file = myFixture.configureByText("test.kt", text) as JetFile + val stub = JetFileStubBuilder().buildStubTree(file)!! + return Pair(file, stub) + } + + private fun createStubTree(text: String) = createFileAndStubTree(text).second + + fun packageDirective(text: String) { + val (file, tree) = createFileAndStubTree(text) + val packageDirective = tree.findChildStubByType(JetStubElementTypes.PACKAGE_DIRECTIVE) + val psi = JetPackageDirective(packageDirective as PsiJetPlaceHolderStub) + Assert.assertEquals(file.getPackageDirective()!!.getText(), psi.getDebugText()) + } + + fun function(text: String) { + val (file, tree) = createFileAndStubTree(text) + val function = tree.findChildStubByType(JetStubElementTypes.FUNCTION) + val psi = JetNamedFunction(function as PsiJetFunctionStub) + Assert.assertEquals("STUB: " + file.findChildByClass(javaClass())!!.getText(), psi.getDebugText()) + } + + fun typeReference(text: String) { + val (file, tree) = createFileAndStubTree("fun foo(i: $text)") + val function = tree.findChildStubByType(JetStubElementTypes.FUNCTION)!! + val parameterList = function.findChildStubByType(JetStubElementTypes.VALUE_PARAMETER_LIST)!! + val valueParameter = parameterList.findChildStubByType(JetStubElementTypes.VALUE_PARAMETER)!! + val typeReferenceStub = valueParameter.findChildStubByType(JetStubElementTypes.TYPE_REFERENCE) + val psiFromStub = JetTypeReference(typeReferenceStub as PsiJetPlaceHolderStub) + val typeReferenceByPsi = file.findChildByClass(javaClass())!!.getValueParameters()[0].getTypeReference() + Assert.assertEquals(typeReferenceByPsi!!.getText(), psiFromStub.getDebugText()) + } + + fun clazz(text: String, expectedText: String? = null) { + val (file, tree) = createFileAndStubTree(text) + val clazz = tree.findChildStubByType(JetStubElementTypes.CLASS)!! + val psiFromStub = JetClass(clazz as PsiJetClassStub) + val classByPsi = file.findChildByClass(javaClass()) + val toCheckAgainst = "STUB: " + (expectedText ?: classByPsi!!.getText()) + Assert.assertEquals(toCheckAgainst, psiFromStub.getDebugText()) + if (expectedText != null) { + Assert.assertNotEquals("Expected text should not be specified", classByPsi.getDebugText(), psiFromStub.getDebugText()) + } + } + + fun obj(text: String, expectedText: String? = null) { + val (file, tree) = createFileAndStubTree(text) + val obj = tree.findChildStubByType(JetStubElementTypes.OBJECT_DECLARATION)!! + val psiFromStub = JetObjectDeclaration(obj as PsiJetObjectStub) + val objectByPsi = file.findChildByClass(javaClass()) + val toCheckAgainst = "STUB: " + (expectedText ?: objectByPsi!!.getText()) + Assert.assertEquals(toCheckAgainst, psiFromStub.getDebugText()) + } + + fun property(text: String, expectedText: String? = null) { + val (file, tree) = createFileAndStubTree(text) + val property = tree.findChildStubByType(JetStubElementTypes.PROPERTY)!! + val psiFromStub = JetProperty(property as PsiJetPropertyStub) + val propertyByPsi = file.findChildByClass(javaClass()) + val toCheckAgainst = "STUB: " + (expectedText ?: propertyByPsi!!.getText()) + Assert.assertEquals(toCheckAgainst, psiFromStub.getDebugText()) + } + + fun importList(text: String) { + val (file, tree) = createFileAndStubTree(text) + val importList = tree.findChildStubByType(JetStubElementTypes.IMPORT_LIST) + val psi = JetImportList(importList as PsiJetPlaceHolderStub) + Assert.assertEquals(file.getImportList()!!.getText(), psi.getDebugText()) + } + + fun testPackageDirective() { + packageDirective("package a.b.c") + packageDirective("") + packageDirective("package b") + } + + fun testImportList() { + importList("import a\nimport b.c.d") + importList("import a.*") + importList("import a.c as Alias") + } + + fun testFunction() { + function("fun foo()") + function("fun foo()") + function("fun foo()") + function("fun foo()") + function("fun foo(a: Int, b: String)") + function("fun Int.foo()") + function("fun foo(): String") + function("fun T.foo(b: T): List") + function("fun f() where T : G") + function("fun f() where T : G, G : T") + function("fun f() where class object T : G") + function("private final fun f()") + } + + fun testTypeReference() { + typeReference("T") + typeReference("T") + typeReference("T") + typeReference("T") + typeReference("T") + typeReference("T<*>") + typeReference("T<*, in G>") + typeReference("T?") + typeReference("T") + typeReference("() -> T") + typeReference("(G?, H) -> T?") + typeReference("L.(G?, H) -> T?") + typeReference("L?.(G?, H) -> T?") + } + + fun testClass() { + clazz("class A") + clazz("open private class A") + clazz("public class private A") + clazz("class A()") + clazz("class A() : B()", expectedText = "class A() : B") + clazz("class A() : B") + clazz("class A() : B(), C()", expectedText = "class A() : B, C") + clazz("class A() : B by g", expectedText = "class A() : B") + clazz("class A() : B by g, C(), T", expectedText = "class A() : B, C, T") + clazz("class A(i: Int, g: String)") + clazz("class A(val i: Int, var g: String)") + } + + fun testObject() { + obj("object Foo") + obj("public final object Foo") + obj("object Foo : A()", expectedText = "object Foo : A") + obj("object Foo : A by foo", expectedText = "object Foo : A") + obj("object Foo : A, T, C by g, B()", expectedText = "object Foo : A, T, C, B") + } + + fun testProperty() { + property("val c: Int") + property("var c: Int") + property("var : Int") + property("private final var c: Int") + property("val g") + property("val g = 3", expectedText = "val g") + property("val g by z", expectedText = "val g") + property("val g: Int by z", expectedText = "val g: Int") + } + + fun testClassBody() { + val tree = createStubTree("class A {\n {} fun f(): Int val c: Int}") + val classBody = tree.findChildStubByType(JetStubElementTypes.CLASS)!!.findChildStubByType(JetStubElementTypes.CLASS_BODY) + assertEquals("class body for STUB: class A", JetClassBody(classBody as PsiJetPlaceHolderStub).getDebugText()) + } + + fun testClassInitializer() { + val tree = createStubTree("class A {\n {} }") + val initializer = tree.findChildStubByType(JetStubElementTypes.CLASS)!!.findChildStubByType(JetStubElementTypes.CLASS_BODY)!! + .findChildStubByType(JetStubElementTypes.ANONYMOUS_INITIALIZER) + assertEquals("initializer in STUB: class A", JetClassInitializer(initializer as PsiJetPlaceHolderStub).getDebugText()) + } + + fun testClassObject() { + val tree = createStubTree("class A { class object {} }") + val classObject = tree.findChildStubByType(JetStubElementTypes.CLASS)!!.findChildStubByType(JetStubElementTypes.CLASS_BODY)!! + .findChildStubByType(JetStubElementTypes.CLASS_OBJECT) + assertEquals("class object in STUB: class A", JetClassObject(classObject as PsiJetPlaceHolderStub).getDebugText()) + } + + fun testPropertyAccessors() { + val tree = createStubTree("var c: Int\nget() = 3\nset(i: Int) {}") + val propertyStub = tree.findChildStubByType(JetStubElementTypes.PROPERTY)!! + val accessors = propertyStub.getChildrenByType(JetStubElementTypes.PROPERTY_ACCESSOR, JetStubElementTypes.PROPERTY_ACCESSOR.getArrayFactory())!! + assertEquals("getter for STUB: var c: Int", accessors[0].getDebugText()) + assertEquals("setter for STUB: var c: Int", accessors[1].getDebugText()) + } + + fun testEnumEntry() { + val tree = createStubTree("enum class Enum { E1 E2: Enum() E3: Enum(1, 2)}") + val enumClass = tree.findChildStubByType(JetStubElementTypes.CLASS)!!.findChildStubByType(JetStubElementTypes.CLASS_BODY)!! + val entries = enumClass.getChildrenByType(JetStubElementTypes.ENUM_ENTRY, JetStubElementTypes.ENUM_ENTRY.getArrayFactory())!! + assertEquals("STUB: enum entry E1", entries[0].getDebugText()) + assertEquals("STUB: enum entry E2 : Enum", entries[1].getDebugText()) + assertEquals("STUB: enum entry E3 : Enum", entries[2].getDebugText()) + } +} \ No newline at end of file