Test it's safe to call PsiElement methods on Kotlin light elements

This commit is contained in:
Nikolay Krasko
2015-11-05 16:16:22 +03:00
committed by Nikolay Krasko
parent 7c752c1463
commit 178aba54dd
9 changed files with 186 additions and 10 deletions
@@ -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? = ""
}
@@ -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
@@ -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)
@@ -135,4 +135,9 @@ public class KtLightParameter extends LightParameter implements KtLightElement<K
public KtLightMethod getMethod() {
return method;
}
@Override
public String getText() {
return "";
}
}
@@ -80,6 +80,11 @@ public class KtLightTypeParameter
}
}
@Override
public String getText() {
return "";
}
@Nullable
@Override
public String getName() {
@@ -155,7 +155,7 @@ public abstract class KtWrappingLightClass extends AbstractLightClass implements
@Override
public String getText() {
KtClassOrObject origin = getOrigin();
return origin == null ? null : origin.getText();
return origin == null ? "" : origin.getText();
}
@NotNull
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescrip
import java.io.File
abstract class AbstractIdeLightClassTest : KotlinLightCodeInsightFixtureTestCase() {
fun doTest(testDataPath: String) {
myFixture.configureByFile(testDataPath)
@@ -32,15 +31,23 @@ abstract class AbstractIdeLightClassTest : KotlinLightCodeInsightFixtureTestCase
LightClassTestCommon.testLightClass(
File(testDataPath),
findLightClass = {
JavaPsiFacade.getInstance(project).findClass(it, GlobalSearchScope.allScope(project))
val clazz = JavaPsiFacade.getInstance(project).findClass(it, GlobalSearchScope.allScope(project))
if (clazz != null) {
PsiElementChecker.checkPsiElementStructure(clazz)
}
clazz
},
normalizeText = {
//NOTE: ide and compiler differ in names generated for parameters with unspecified names
it.replace("java.lang.String s,", "java.lang.String p,").replace("java.lang.String s)", "java.lang.String p)")
.replace("java.lang.String s1", "java.lang.String p1").replace("java.lang.String s2", "java.lang.String p2")
it
.replace("java.lang.String s,", "java.lang.String p,")
.replace("java.lang.String s)", "java.lang.String p)")
.replace("java.lang.String s1", "java.lang.String p1")
.replace("java.lang.String s2", "java.lang.String p2")
}
)
}
override fun getProjectDescriptor() = KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2015 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.kotlin.idea.caches.resolve;
public class AssertionErrorWithCause extends AssertionError {
public AssertionErrorWithCause(String detailMessage, Throwable cause) {
super(detailMessage);
initCause(cause);
}
}
@@ -0,0 +1,129 @@
/*
* Copyright 2010-2015 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.kotlin.idea.caches.resolve
import com.intellij.openapi.util.Key
import com.intellij.psi.*
import org.jetbrains.kotlin.asJava.KtLightElement
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.junit.Assert
object PsiElementChecker {
val TEST_DATA_KEY = Key.create<Int>("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)
}
}
}
}