Reference resolve from synthetic extension usages to get/set-methods
This commit is contained in:
@@ -130,7 +130,7 @@ public fun JetElement.getQualifiedExpressionForSelector(): JetQualifiedExpressio
|
|||||||
return if (parent is JetQualifiedExpression && parent.getSelectorExpression() == this) parent else null
|
return if (parent is JetQualifiedExpression && parent.getSelectorExpression() == this) parent else null
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun JetElement.getQualifiedExpressionForSelectorOrThis(): JetElement {
|
public fun JetExpression.getQualifiedExpressionForSelectorOrThis(): JetExpression {
|
||||||
return getQualifiedExpressionForSelector() ?: this
|
return getQualifiedExpressionForSelector() ?: this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+64
-17
@@ -16,34 +16,81 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.references
|
package org.jetbrains.kotlin.idea.references
|
||||||
|
|
||||||
|
import com.intellij.openapi.extensions.Extensions
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.lexer.JetTokens
|
|
||||||
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.fqName.changeQualifiedName
|
|
||||||
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
|
||||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
|
||||||
import org.jetbrains.kotlin.lexer.JetToken
|
|
||||||
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
|
||||||
import com.intellij.util.IncorrectOperationException
|
import com.intellij.util.IncorrectOperationException
|
||||||
import org.jetbrains.kotlin.name.Name
|
import com.intellij.util.SmartList
|
||||||
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
|
||||||
import com.intellij.psi.impl.light.LightElement
|
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
|
||||||
import com.intellij.openapi.extensions.Extensions
|
import org.jetbrains.kotlin.idea.refactoring.fqName.changeQualifiedName
|
||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
|
||||||
|
import org.jetbrains.kotlin.idea.util.ShortenReferences
|
||||||
|
import org.jetbrains.kotlin.lexer.JetToken
|
||||||
|
import org.jetbrains.kotlin.lexer.JetTokens
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension
|
import org.jetbrains.kotlin.plugin.references.SimpleNameReferenceExtension
|
||||||
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
|
||||||
|
import org.jetbrains.kotlin.synthetic.SyntheticExtensionPropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.constant
|
||||||
|
|
||||||
public class JetSimpleNameReference(
|
public class JetSimpleNameReference(
|
||||||
jetSimpleNameExpression: JetSimpleNameExpression
|
jetSimpleNameExpression: JetSimpleNameExpression
|
||||||
) : JetSimpleReference<JetSimpleNameExpression>(jetSimpleNameExpression) {
|
) : JetSimpleReference<JetSimpleNameExpression>(jetSimpleNameExpression) {
|
||||||
|
|
||||||
|
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
|
||||||
|
val targets = super.getTargetDescriptors(context)
|
||||||
|
if (targets.none { it is SyntheticExtensionPropertyDescriptor }) return targets
|
||||||
|
|
||||||
|
val newTargets = SmartList<DeclarationDescriptor>()
|
||||||
|
for (target in targets) {
|
||||||
|
if (!(target !is SyntheticExtensionPropertyDescriptor)) {
|
||||||
|
val access = access()
|
||||||
|
if (access == Access.READ || access == Access.READ_WRITE) {
|
||||||
|
newTargets.add(target.getMethod)
|
||||||
|
}
|
||||||
|
if (access == Access.WRITE || access == Access.READ_WRITE) {
|
||||||
|
newTargets.addIfNotNull(target.setMethod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
newTargets.add(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newTargets
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: there should be some common util for that
|
||||||
|
private enum class Access {
|
||||||
|
READ, WRITE, READ_WRITE
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun access(): Access {
|
||||||
|
var expression = myElement.getQualifiedExpressionForSelectorOrThis()
|
||||||
|
while (expression.getParent() is JetParenthesizedExpression) {
|
||||||
|
expression = expression.getParent() as JetParenthesizedExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
val assignment = expression.getAssignmentByLHS()
|
||||||
|
if (assignment != null) {
|
||||||
|
return if (assignment.getOperationToken() == JetTokens.EQ) Access.WRITE else Access.READ_WRITE
|
||||||
|
}
|
||||||
|
|
||||||
|
return if ((expression.getParent() as? JetUnaryExpression)?.getOperationToken() in constant { setOf(JetTokens.PLUSPLUS, JetTokens.MINUSMINUS) })
|
||||||
|
Access.READ_WRITE
|
||||||
|
else
|
||||||
|
Access.READ
|
||||||
|
}
|
||||||
|
|
||||||
override fun isReferenceTo(element: PsiElement?): Boolean {
|
override fun isReferenceTo(element: PsiElement?): Boolean {
|
||||||
if (element != null) {
|
if (element != null) {
|
||||||
if (!canBeReferenceTo(element)) return false
|
if (!canBeReferenceTo(element)) return false
|
||||||
|
|||||||
+2
-1
@@ -41,6 +41,7 @@ import org.jetbrains.kotlin.idea.util.psi.patternMatching.JetPsiRange
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
@@ -82,7 +83,7 @@ class RenameReplacement(override val parameter: Parameter): ParameterReplacement
|
|||||||
override fun copy(parameter: Parameter) = RenameReplacement(parameter)
|
override fun copy(parameter: Parameter) = RenameReplacement(parameter)
|
||||||
|
|
||||||
override fun invoke(e: JetElement): JetElement {
|
override fun invoke(e: JetElement): JetElement {
|
||||||
var expressionToReplace = (e.getParent() as? JetThisExpression ?: e).getQualifiedExpressionForSelectorOrThis()
|
var expressionToReplace = (e.getParent() as? JetThisExpression ?: e).let { it.getQualifiedExpressionForSelector() ?: it }
|
||||||
val parameterName = JetPsiUtil.unquoteIdentifier(parameter.nameForRef)
|
val parameterName = JetPsiUtil.unquoteIdentifier(parameter.nameForRef)
|
||||||
val replacingName =
|
val replacingName =
|
||||||
if (e.getText().startsWith('`') || !KotlinNameSuggester.isIdentifier(parameterName)) "`$parameterName`" else parameterName
|
if (e.getText().startsWith('`') || !KotlinNameSuggester.isIdentifier(parameterName)) "`$parameterName`" else parameterName
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
class JavaClass {
|
||||||
|
public int getSomething() { return 1; }
|
||||||
|
public void setSomething(int value) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
fun JavaClass.foo(javaClass: JavaClass) {
|
||||||
|
print(javaClass.<caret>something)
|
||||||
|
javaClass.<caret>something = 1
|
||||||
|
javaClass.<caret>something += 1
|
||||||
|
javaClass.<caret>something++
|
||||||
|
--javaClass.<caret>something
|
||||||
|
|
||||||
|
<caret>something++
|
||||||
|
(<caret>something)++
|
||||||
|
(<caret>something) = 1
|
||||||
|
(javaClass.<caret>something) = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// MULTIRESOLVE
|
||||||
|
// REF1: (in JavaClass).getSomething()
|
||||||
|
// REF2: (in JavaClass).setSomething(int)
|
||||||
|
// REF3: (in JavaClass).getSomething()
|
||||||
|
// REF3: (in JavaClass).setSomething(int)
|
||||||
|
// REF4: (in JavaClass).getSomething()
|
||||||
|
// REF4: (in JavaClass).setSomething(int)
|
||||||
|
// REF5: (in JavaClass).getSomething()
|
||||||
|
// REF5: (in JavaClass).setSomething(int)
|
||||||
|
// REF6: (in JavaClass).getSomething()
|
||||||
|
// REF6: (in JavaClass).setSomething(int)
|
||||||
|
// REF7: (in JavaClass).getSomething()
|
||||||
|
// REF7: (in JavaClass).setSomething(int)
|
||||||
|
// REF8: (in JavaClass).setSomething(int)
|
||||||
|
// REF9: (in JavaClass).setSomething(int)
|
||||||
+1
-1
@@ -34,7 +34,7 @@ public abstract class AbstractReferenceResolveInLibrarySourcesTest : JetLightCod
|
|||||||
|
|
||||||
fixture.configureByFile(path)
|
fixture.configureByFile(path)
|
||||||
|
|
||||||
val expectedResolveData = AbstractReferenceResolveTest.readResolveData(fixture.getFile()!!.getText())
|
val expectedResolveData = AbstractReferenceResolveTest.readResolveData(fixture.getFile()!!.getText(), 0)
|
||||||
|
|
||||||
val gotoData = NavigationTestUtils.invokeGotoImplementations(fixture.getEditor(), fixture.getFile())!!
|
val gotoData = NavigationTestUtils.invokeGotoImplementations(fixture.getEditor(), fixture.getFile())!!
|
||||||
Assert.assertEquals("Single target expected for origianl file", 1, gotoData.targets.size())
|
Assert.assertEquals("Single target expected for origianl file", 1, gotoData.targets.size())
|
||||||
|
|||||||
@@ -1,164 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.resolve;
|
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Ordering;
|
|
||||||
import com.intellij.psi.PsiElement;
|
|
||||||
import com.intellij.psi.PsiPolyVariantReference;
|
|
||||||
import com.intellij.psi.PsiReference;
|
|
||||||
import com.intellij.psi.ResolveResult;
|
|
||||||
import com.intellij.testFramework.LightProjectDescriptor;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor;
|
|
||||||
import org.jetbrains.kotlin.idea.test.KotlinLightPlatformCodeInsightFixtureTestCase;
|
|
||||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils;
|
|
||||||
import org.jetbrains.kotlin.test.ReferenceUtils;
|
|
||||||
import org.jetbrains.kotlin.test.util.UtilPackage;
|
|
||||||
import org.junit.Assert;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public abstract class AbstractReferenceResolveTest extends KotlinLightPlatformCodeInsightFixtureTestCase {
|
|
||||||
public static class ExpectedResolveData {
|
|
||||||
private final Boolean shouldBeUnresolved;
|
|
||||||
private final String referenceToString;
|
|
||||||
|
|
||||||
public ExpectedResolveData(Boolean shouldBeUnresolved, String referenceToString) {
|
|
||||||
this.shouldBeUnresolved = shouldBeUnresolved;
|
|
||||||
this.referenceToString = referenceToString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean shouldBeUnresolved() {
|
|
||||||
return shouldBeUnresolved;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getReferenceString() {
|
|
||||||
return referenceToString;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String MULTIRESOLVE = "MULTIRESOLVE";
|
|
||||||
public static final String REF_EMPTY = "REF_EMPTY";
|
|
||||||
|
|
||||||
protected void doTest(@NotNull String path) {
|
|
||||||
assert path.endsWith(".kt") : path;
|
|
||||||
UtilPackage.configureWithExtraFile(myFixture, path, ".Data");
|
|
||||||
performChecks();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void performChecks() {
|
|
||||||
if (InTextDirectivesUtils.isDirectiveDefined(myFixture.getFile().getText(), MULTIRESOLVE)) {
|
|
||||||
doMultiResolveTest();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
doSingleResolveTest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void doSingleResolveTest() {
|
|
||||||
ExpectedResolveData expectedResolveData = readResolveData(myFixture.getFile().getText());
|
|
||||||
|
|
||||||
int offset = myFixture.getEditor().getCaretModel().getOffset();
|
|
||||||
PsiReference psiReference = myFixture.getFile().findReferenceAt(offset);
|
|
||||||
|
|
||||||
checkReferenceResolve(expectedResolveData, offset, psiReference);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void doMultiResolveTest() {
|
|
||||||
List<String> expectedReferences = ReferenceUtils.getExpectedReferences(myFixture.getFile().getText());
|
|
||||||
|
|
||||||
PsiReference psiReference = myFixture.getFile().findReferenceAt(myFixture.getEditor().getCaretModel().getOffset());
|
|
||||||
|
|
||||||
assertTrue(psiReference instanceof PsiPolyVariantReference);
|
|
||||||
|
|
||||||
PsiPolyVariantReference variantReference = (PsiPolyVariantReference) psiReference;
|
|
||||||
|
|
||||||
ResolveResult[] results = variantReference.multiResolve(true);
|
|
||||||
|
|
||||||
List<String> actualResolvedTo = Lists.newArrayList();
|
|
||||||
for (ResolveResult result : results) {
|
|
||||||
PsiElement resolvedToElement = result.getElement();
|
|
||||||
assertNotNull(resolvedToElement);
|
|
||||||
|
|
||||||
actualResolvedTo.add(ReferenceUtils.renderAsGotoImplementation(resolvedToElement));
|
|
||||||
}
|
|
||||||
|
|
||||||
assertOrderedEquals(Ordering.natural().sortedCopy(actualResolvedTo), Ordering.natural().sortedCopy(expectedReferences));
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
public static ExpectedResolveData readResolveData(String fileText) {
|
|
||||||
boolean shouldBeUnresolved = InTextDirectivesUtils.isDirectiveDefined(fileText, REF_EMPTY);
|
|
||||||
List<String> refs = ReferenceUtils.getExpectedReferences(fileText);
|
|
||||||
|
|
||||||
String referenceToString;
|
|
||||||
if (shouldBeUnresolved) {
|
|
||||||
Assert.assertTrue("REF: directives will be ignored for " + REF_EMPTY + " test: " + refs, refs.isEmpty());
|
|
||||||
referenceToString = "<empty>";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
assertTrue("Must be a single ref: " + refs + ".\n" +
|
|
||||||
"Use " + MULTIRESOLVE + " if you need multiple refs\n" +
|
|
||||||
"Use "+ REF_EMPTY + " for an unresolved reference",
|
|
||||||
refs.size() == 1);
|
|
||||||
referenceToString = refs.get(0);
|
|
||||||
Assert.assertNotNull("Test data wasn't found, use \"// REF: \" directive", referenceToString);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ExpectedResolveData(shouldBeUnresolved, referenceToString);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void checkReferenceResolve(ExpectedResolveData expectedResolveData, int offset, PsiReference psiReference) {
|
|
||||||
if (psiReference != null) {
|
|
||||||
PsiElement resolvedTo = psiReference.resolve();
|
|
||||||
if (resolvedTo != null) {
|
|
||||||
String resolvedToElementStr = ReferenceUtils.renderAsGotoImplementation(resolvedTo);
|
|
||||||
String notEqualMessage = String.format("Found reference to '%s', but '%s' was expected",
|
|
||||||
resolvedToElementStr, expectedResolveData.getReferenceString());
|
|
||||||
assertEquals(notEqualMessage, expectedResolveData.getReferenceString(), resolvedToElementStr);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!expectedResolveData.shouldBeUnresolved()) {
|
|
||||||
Assert.assertNull(
|
|
||||||
String.format("Element %s wasn't resolved to anything, but %s was expected",
|
|
||||||
psiReference, expectedResolveData.getReferenceString()),
|
|
||||||
expectedResolveData.getReferenceString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Assert.assertNull(
|
|
||||||
String.format("No reference found at offset: %s, but one resolved to %s was expected",
|
|
||||||
offset, expectedResolveData.getReferenceString()),
|
|
||||||
expectedResolveData.getReferenceString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
protected LightProjectDescriptor getProjectDescriptor() {
|
|
||||||
return JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
protected String getTestDataPath() {
|
|
||||||
return "./";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* 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.resolve
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists
|
||||||
|
import com.google.common.collect.Ordering
|
||||||
|
import com.intellij.psi.PsiPolyVariantReference
|
||||||
|
import com.intellij.psi.PsiReference
|
||||||
|
import com.intellij.testFramework.LightProjectDescriptor
|
||||||
|
import com.intellij.testFramework.UsefulTestCase
|
||||||
|
import com.intellij.util.PathUtil
|
||||||
|
import org.jetbrains.kotlin.idea.test.JetWithJdkAndRuntimeLightProjectDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.test.KotlinLightPlatformCodeInsightFixtureTestCase
|
||||||
|
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
|
||||||
|
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||||
|
import org.jetbrains.kotlin.test.ReferenceUtils
|
||||||
|
import org.jetbrains.kotlin.test.util.configureWithExtraFile
|
||||||
|
import org.junit.Assert
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
public abstract class AbstractReferenceResolveTest : KotlinLightPlatformCodeInsightFixtureTestCase() {
|
||||||
|
public class ExpectedResolveData(private val shouldBeUnresolved: Boolean?, public val referenceString: String) {
|
||||||
|
|
||||||
|
public fun shouldBeUnresolved(): Boolean {
|
||||||
|
return shouldBeUnresolved!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun doTest(path: String) {
|
||||||
|
assert(path.endsWith(".kt")) { path }
|
||||||
|
myFixture.configureWithExtraFile(path, ".Data")
|
||||||
|
performChecks()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun performChecks() {
|
||||||
|
if (InTextDirectivesUtils.isDirectiveDefined(myFixture.getFile().getText(), MULTIRESOLVE)) {
|
||||||
|
doMultiResolveTest()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
doSingleResolveTest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun doSingleResolveTest() {
|
||||||
|
forEachCaret { index, offset ->
|
||||||
|
val expectedResolveData = readResolveData(myFixture.getFile().getText(), index)
|
||||||
|
val psiReference = myFixture.getFile().findReferenceAt(offset)
|
||||||
|
checkReferenceResolve(expectedResolveData, offset, psiReference)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun doMultiResolveTest() {
|
||||||
|
forEachCaret { index, offset ->
|
||||||
|
val expectedReferences = getExpectedReferences(myFixture.getFile().getText(), index)
|
||||||
|
|
||||||
|
val psiReference = myFixture.getFile().findReferenceAt(offset)
|
||||||
|
assertTrue(psiReference is PsiPolyVariantReference)
|
||||||
|
psiReference as PsiPolyVariantReference
|
||||||
|
|
||||||
|
val results = psiReference.multiResolve(true)
|
||||||
|
|
||||||
|
val actualResolvedTo = Lists.newArrayList<String>()
|
||||||
|
for (result in results) {
|
||||||
|
actualResolvedTo.add(ReferenceUtils.renderAsGotoImplementation(result.getElement()!!))
|
||||||
|
}
|
||||||
|
|
||||||
|
UsefulTestCase.assertOrderedEquals("Not matching for reference #$index", actualResolvedTo.sort(), expectedReferences.sort())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun forEachCaret(action: (index: Int, offset: Int) -> Unit) {
|
||||||
|
val offsets = myFixture.getEditor().getCaretModel().getAllCarets().map { it.getOffset() }
|
||||||
|
val singleCaret = offsets.size() == 1
|
||||||
|
for ((index, offset) in offsets.withIndex()) {
|
||||||
|
action(if (singleCaret) -1 else index + 1, offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getProjectDescriptor(): LightProjectDescriptor? = JetWithJdkAndRuntimeLightProjectDescriptor.INSTANCE
|
||||||
|
|
||||||
|
override fun getTestDataPath() = "./"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
public val MULTIRESOLVE: String = "MULTIRESOLVE"
|
||||||
|
public val REF_EMPTY: String = "REF_EMPTY"
|
||||||
|
|
||||||
|
public fun readResolveData(fileText: String, index: Int): ExpectedResolveData {
|
||||||
|
val shouldBeUnresolved = InTextDirectivesUtils.isDirectiveDefined(fileText, REF_EMPTY)
|
||||||
|
val refs = getExpectedReferences(fileText, index)
|
||||||
|
|
||||||
|
val referenceToString: String
|
||||||
|
if (shouldBeUnresolved) {
|
||||||
|
Assert.assertTrue("REF: directives will be ignored for $REF_EMPTY test: $refs", refs.isEmpty())
|
||||||
|
referenceToString = "<empty>"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertTrue(refs.size() == 1, "Must be a single ref: $refs.\nUse $MULTIRESOLVE if you need multiple refs\nUse $REF_EMPTY for an unresolved reference")
|
||||||
|
referenceToString = refs.get(0)
|
||||||
|
Assert.assertNotNull("Test data wasn't found, use \"// REF: \" directive", referenceToString)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ExpectedResolveData(shouldBeUnresolved, referenceToString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// purpose of this helper is to deal with the case when navigation element is a file
|
||||||
|
// see ReferenceResolveInJavaTestGenerated.testPackageFacade()
|
||||||
|
private fun getExpectedReferences(text: String, index: Int): List<String> {
|
||||||
|
val prefix = if (index > 0) "// REF$index:" else "// REF:"
|
||||||
|
val prefixes = InTextDirectivesUtils.findLinesWithPrefixesRemoved(text, prefix)
|
||||||
|
return prefixes.map {
|
||||||
|
val replaced = it.replace("<test dir>", PluginTestCaseBase.getTestDataPathBase())
|
||||||
|
PathUtil.toSystemDependentName(replaced).replace("//", "/") //happens on Unix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun checkReferenceResolve(expectedResolveData: ExpectedResolveData, offset: Int, psiReference: PsiReference?) {
|
||||||
|
if (psiReference != null) {
|
||||||
|
val resolvedTo = psiReference.resolve()
|
||||||
|
if (resolvedTo != null) {
|
||||||
|
val resolvedToElementStr = ReferenceUtils.renderAsGotoImplementation(resolvedTo)
|
||||||
|
assertEquals(expectedResolveData.referenceString, resolvedToElementStr, "Found reference to '$resolvedToElementStr', but '${expectedResolveData.referenceString}' was expected")
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!expectedResolveData.shouldBeUnresolved()) {
|
||||||
|
assertNull(expectedResolveData.referenceString, "Element $psiReference wasn't resolved to anything, but ${expectedResolveData.referenceString} was expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assertNull(expectedResolveData.referenceString, "No reference found at offset: $offset, but one resolved to ${expectedResolveData.referenceString} was expected")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -347,6 +347,12 @@ public class ReferenceResolveTestGenerated extends AbstractReferenceResolveTest
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("SyntheticProperty.kt")
|
||||||
|
public void testSyntheticProperty() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/references/SyntheticProperty.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("TypeParameterInAnonymousObject.kt")
|
@TestMetadata("TypeParameterInAnonymousObject.kt")
|
||||||
public void testTypeParameterInAnonymousObject() throws Exception {
|
public void testTypeParameterInAnonymousObject() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/references/TypeParameterInAnonymousObject.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/resolve/references/TypeParameterInAnonymousObject.kt");
|
||||||
|
|||||||
@@ -21,17 +21,11 @@ import com.intellij.navigation.NavigationItem;
|
|||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiPackage;
|
import com.intellij.psi.PsiPackage;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import com.intellij.util.PathUtil;
|
|
||||||
import kotlin.KotlinPackage;
|
|
||||||
import kotlin.jvm.functions.Function1;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
|
|
||||||
import org.jetbrains.kotlin.psi.JetClass;
|
import org.jetbrains.kotlin.psi.JetClass;
|
||||||
import org.jetbrains.kotlin.psi.JetObjectDeclaration;
|
import org.jetbrains.kotlin.psi.JetObjectDeclaration;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public final class ReferenceUtils {
|
public final class ReferenceUtils {
|
||||||
private ReferenceUtils() {
|
private ReferenceUtils() {
|
||||||
}
|
}
|
||||||
@@ -60,18 +54,4 @@ public final class ReferenceUtils {
|
|||||||
? presentableText
|
? presentableText
|
||||||
: locationString + "." + presentableText;
|
: locationString + "." + presentableText;
|
||||||
}
|
}
|
||||||
|
|
||||||
// purpose of this helper is to deal with the case when navigation element is a file
|
|
||||||
// see ReferenceResolveInJavaTestGenerated.testPackageFacade()
|
|
||||||
@NotNull
|
|
||||||
public static List<String> getExpectedReferences(@NotNull String text) {
|
|
||||||
List<String> prefixes = InTextDirectivesUtils.findLinesWithPrefixesRemoved(text, "// REF:");
|
|
||||||
return KotlinPackage.map(prefixes, new Function1<String, String>() {
|
|
||||||
@Override
|
|
||||||
public String invoke(String s) {
|
|
||||||
String replaced = s.replace("<test dir>", PluginTestCaseBase.getTestDataPathBase());
|
|
||||||
return PathUtil.toSystemDependentName(replaced).replace("//", "/"); //happens on Unix
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user