From 178aba54dd3a952d32078451588e8db05afd7329 Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Thu, 5 Nov 2015 16:16:22 +0300 Subject: [PATCH] Test it's safe to call PsiElement methods on Kotlin light elements --- .../KotlinLightTypeParameterListBuilder.kt | 2 + .../jetbrains/kotlin/asJava/KtLightField.kt | 6 +- .../jetbrains/kotlin/asJava/KtLightMethod.kt | 5 +- .../kotlin/asJava/KtLightParameter.java | 5 + .../kotlin/asJava/KtLightTypeParameter.java | 5 + .../kotlin/asJava/KtWrappingLightClass.java | 2 +- .../resolve/AbstractIdeLightClassTest.kt | 17 ++- .../resolve/AssertionErrorWithCause.java | 25 ++++ .../idea/caches/resolve/PsiElementChecker.kt | 129 ++++++++++++++++++ 9 files changed, 186 insertions(+), 10 deletions(-) create mode 100644 idea/tests/org/jetbrains/kotlin/idea/caches/resolve/AssertionErrorWithCause.java create mode 100644 idea/tests/org/jetbrains/kotlin/idea/caches/resolve/PsiElementChecker.kt diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KotlinLightTypeParameterListBuilder.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KotlinLightTypeParameterListBuilder.kt index e2a461a3d7a..15e8bb1a88d 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KotlinLightTypeParameterListBuilder.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KotlinLightTypeParameterListBuilder.kt @@ -27,4 +27,6 @@ public class KotlinLightTypeParameterListBuilder(manager: PsiManager): LightType override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement): Boolean { return getTypeParameters().all { processor.execute(it, state) } } + + override fun getText(): String? = "" } diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightField.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightField.kt index d5a495d86c2..5e941d96fa5 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightField.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightField.kt @@ -69,9 +69,9 @@ sealed class KtLightFieldImpl( override fun hasModifierProperty(@NonNls name: String) = delegate.hasModifierProperty(name) - override fun getText() = delegate.text + override fun getText() = origin?.text ?: "" - override fun getTextRange() = TextRange(-1, -1) + override fun getTextRange() = origin?.textRange ?: TextRange.EMPTY_RANGE override fun isValid() = containingClass.isValid @@ -82,7 +82,7 @@ sealed class KtLightFieldImpl( override fun getDelegate() = delegate override fun getNavigationElement() = origin ?: super.getNavigationElement() - + override fun isEquivalentTo(another: PsiElement?): Boolean { if (another is KtLightField && origin == another.getOrigin() && delegate == another.getDelegate()) { return true diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightMethod.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightMethod.kt index 13fa0720708..43e3554f3d0 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightMethod.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightMethod.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.asJava import com.intellij.core.JavaCoreBundle +import com.intellij.openapi.util.TextRange import com.intellij.psi.* import com.intellij.psi.impl.light.LightMethod import com.intellij.psi.scope.PsiScopeProcessor @@ -68,6 +69,8 @@ sealed class KtLightMethodImpl( override fun getDelegate() = delegate override fun getOrigin() = origin override fun getParent(): PsiElement? = containingClass + override fun getText() = origin?.text ?: "" + override fun getTextRange() = origin?.textRange ?: TextRange.EMPTY_RANGE override fun accept(visitor: PsiElementVisitor) { if (visitor is JavaElementVisitor) { @@ -140,7 +143,7 @@ sealed class KtLightMethodImpl( override fun hashCode(): Int = ((name.hashCode() * 31 + (origin?.hashCode() ?: 0)) * 31 + containingClass.hashCode()) * 31 + delegate.hashCode() override fun toString(): String = "${this.javaClass.simpleName}:$name" - + private class KtLightMethodForDeclaration( delegate: PsiMethod, origin: KtDeclaration?, containingClass: KtLightClass ) : KtLightMethodImpl(delegate, origin, containingClass) diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightParameter.java b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightParameter.java index a2f4b60b742..d05681eb32e 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightParameter.java +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/KtLightParameter.java @@ -135,4 +135,9 @@ public class KtLightParameter extends LightParameter implements KtLightElement("Test Key") + + public fun checkPsiElementStructure(lightClass: PsiClass) { + checkPsiElement(lightClass) + + lightClass.innerClasses.forEach { checkPsiElementStructure(it) } + + lightClass.methods.forEach { + it.parameterList.parameters.forEach { checkPsiElement(it) } + checkPsiElement(it) + } + + lightClass.fields.forEach { checkPsiElement(it) } + } + + private fun checkPsiElement(element: PsiElement) { + if (element !is KtLightElement<*, *>) return + + if (element is PsiModifierListOwner) { + val modifierList = element.modifierList + if (modifierList != null) { + checkPsiElement(modifierList) + } + } + + if (element is PsiTypeParameterListOwner) { + val typeParameterList = element.typeParameterList + if (typeParameterList != null) { + checkPsiElement(typeParameterList) + typeParameterList.typeParameters.forEach { checkPsiElement(it) } + } + } + + with(element) { + try { + Assert.assertEquals("Number of methods has changed. Please update test.", 54, PsiElement::class.java.methods.size) + + project + Assert.assertTrue(language == KotlinLanguage.INSTANCE) + manager + children + parent + firstChild + lastChild + nextSibling + prevSibling + containingFile + textRange + startOffsetInParent + textLength + findElementAt(0) + findReferenceAt(0) + textOffset + text + textToCharArray() + navigationElement + originalElement + textMatches("") + Assert.assertTrue(textMatches(this)) + textContains('a') + accept(PsiElementVisitor.EMPTY_VISITOR) + acceptChildren(PsiElementVisitor.EMPTY_VISITOR) + + val copy = copy() + Assert.assertTrue(copy == null || copy.javaClass == this.javaClass) + + // Modify methods: + // add(this) + // addBefore(this, lastChild) + // addAfter(firstChild, this) + // checkAdd(this) + // addRange(firstChild, lastChild) + // addRangeBefore(firstChild, lastChild, lastChild) + // addRangeAfter(firstChild, lastChild, firstChild) + // delete() + // checkDelete() + // deleteChildRange(firstChild, lastChild) + // replace(this) + + Assert.assertTrue(isValid) + isWritable + reference + references + putCopyableUserData(TEST_DATA_KEY, 12) + + Assert.assertTrue(getCopyableUserData(TEST_DATA_KEY) == 12) + // Assert.assertTrue(copy().getCopyableUserData(TEST_DATA_KEY) == 12) { this } Doesn't work + + // processDeclarations(...) + + context + isPhysical + resolveScope + useScope + node + toString() + Assert.assertTrue(isEquivalentTo(this)) + } + catch (t: Throwable) { + throw AssertionErrorWithCause("Failed for ${this.javaClass} ${this}", t) + } + } + } +} \ No newline at end of file