diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index a2091ed4ecc..81021a64f0c 100755 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -24,9 +24,9 @@ import org.jetbrains.kotlin.allopen.AbstractBytecodeListingTestForAllOpen import org.jetbrains.kotlin.android.* import org.jetbrains.kotlin.android.configure.AbstractConfigureProjectTest import org.jetbrains.kotlin.android.folding.AbstractAndroidResourceFoldingTest -import org.jetbrains.kotlin.android.quickfix.AbstractAndroidLintQuickfixTest import org.jetbrains.kotlin.android.intention.AbstractAndroidResourceIntentionTest import org.jetbrains.kotlin.android.lint.AbstractKotlinLintTest +import org.jetbrains.kotlin.android.quickfix.AbstractAndroidLintQuickfixTest import org.jetbrains.kotlin.android.quickfix.AbstractAndroidQuickFixMultiFileTest import org.jetbrains.kotlin.annotation.AbstractAnnotationProcessorBoxTest import org.jetbrains.kotlin.annotation.processing.test.sourceRetention.AbstractBytecodeListingTestForSourceRetention @@ -104,10 +104,7 @@ import org.jetbrains.kotlin.idea.kdoc.AbstractKDocHighlightingTest import org.jetbrains.kotlin.idea.kdoc.AbstractKDocTypingTest import org.jetbrains.kotlin.idea.maven.AbstractKotlinMavenInspectionTest import org.jetbrains.kotlin.idea.maven.configuration.AbstractMavenConfigureProjectByChangingFileTest -import org.jetbrains.kotlin.idea.navigation.AbstractGotoSuperTest -import org.jetbrains.kotlin.idea.navigation.AbstractGotoTypeDeclarationTest -import org.jetbrains.kotlin.idea.navigation.AbstractKotlinGotoImplementationTest -import org.jetbrains.kotlin.idea.navigation.AbstractKotlinGotoTest +import org.jetbrains.kotlin.idea.navigation.* import org.jetbrains.kotlin.idea.parameterInfo.AbstractParameterInfoTest import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixMultiFileTest import org.jetbrains.kotlin.idea.quickfix.AbstractQuickFixTest @@ -506,6 +503,10 @@ fun main(args: Array) { model("navigation/gotoTypeDeclaration", extension = "test") } + testClass { + model("navigation/gotoDeclaration", extension = "test") + } + testClass { model("parameterInfo", recursive = true, excludeDirs = listOf("withLib1/sharedLib", "withLib2/sharedLib", "withLib3/sharedLib")) } diff --git a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt index 913a14e01c5..630f2282e2e 100644 --- a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinTargetElementEvaluator.kt @@ -22,16 +22,39 @@ import com.intellij.codeInsight.TargetElementUtil import com.intellij.psi.PsiElement import com.intellij.psi.PsiFile import com.intellij.psi.PsiReference +import com.intellij.util.BitUtil +import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource +import org.jetbrains.kotlin.idea.intentions.isAutoCreatedItUsage import org.jetbrains.kotlin.idea.references.KtDestructuringDeclarationReference +import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject +import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch +import org.jetbrains.kotlin.psi.psiUtil.isAbstract +import org.jetbrains.kotlin.resolve.source.getPsi class KotlinTargetElementEvaluator : TargetElementEvaluatorEx { + companion object { + // Place caret after the open curly brace in lambda for generated 'it' + fun findLambdaOpenLBraceForGeneratedIt(ref: PsiReference): PsiElement? { + val element: PsiElement = ref.element + if (element.text != "it") return null + + if (element !is KtNameReferenceExpression || !isAutoCreatedItUsage(element)) return null + + val itDescriptor = element.resolveMainReferenceToDescriptors().singleOrNull() ?: return null + val descriptorWithSource = itDescriptor.containingDeclaration as? DeclarationDescriptorWithSource ?: return null + val lambdaExpression = descriptorWithSource.source.getPsi()?.parent as? KtLambdaExpression ?: return null + return lambdaExpression.leftCurlyBrace.treeNext?.psi + } + } + override fun includeSelfInGotoImplementation(element: PsiElement): Boolean = !(element is KtClass && element.isAbstract()) override fun getElementByReference(ref: PsiReference, flags: Int): PsiElement? { // prefer destructing declaration entry to its target if element name is accepted - if (ref is KtDestructuringDeclarationReference && flags.and(TargetElementUtil.ELEMENT_NAME_ACCEPTED) != 0) { + if (ref is KtDestructuringDeclarationReference && BitUtil.isSet(flags, TargetElementUtil.ELEMENT_NAME_ACCEPTED)) { return ref.element } @@ -43,6 +66,10 @@ class KotlinTargetElementEvaluator : TargetElementEvaluatorEx { } } + if (BitUtil.isSet(flags, TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED)) { + return findLambdaOpenLBraceForGeneratedIt(ref) + } + return null } diff --git a/idea/testData/navigation/gotoDeclaration/itExtensionLambda.test b/idea/testData/navigation/gotoDeclaration/itExtensionLambda.test new file mode 100644 index 00000000000..ee58624db7a --- /dev/null +++ b/idea/testData/navigation/gotoDeclaration/itExtensionLambda.test @@ -0,0 +1,23 @@ +// FILE: before.kt +interface Foo +interface Bar + +fun foo(a: Foo.(Bar) -> Unit) {} + +fun bar() { + foo { + it + } +} + +// FILE: after.kt +interface Foo +interface Bar + +fun foo(a: Foo.(Bar) -> Unit) {} + +fun bar() { + foo { + it + } +} \ No newline at end of file diff --git a/idea/testData/navigation/gotoDeclaration/itExtensionLambdaInBrackets.test b/idea/testData/navigation/gotoDeclaration/itExtensionLambdaInBrackets.test new file mode 100644 index 00000000000..e737811e687 --- /dev/null +++ b/idea/testData/navigation/gotoDeclaration/itExtensionLambdaInBrackets.test @@ -0,0 +1,23 @@ +// FILE: before.kt +interface Foo +interface Bar + +fun foo(b: Int, a: Foo.(Bar) -> Unit) {} + +fun bar() { + foo(12, { + it + }) +} + +// FILE: after.kt +interface Foo +interface Bar + +fun foo(b: Int, a: Foo.(Bar) -> Unit) {} + +fun bar() { + foo(12, { + it + }) +} \ No newline at end of file diff --git a/idea/testData/navigation/gotoDeclaration/itInLambdaAsDefaultArgument.test b/idea/testData/navigation/gotoDeclaration/itInLambdaAsDefaultArgument.test new file mode 100644 index 00000000000..df9ba4b1b76 --- /dev/null +++ b/idea/testData/navigation/gotoDeclaration/itInLambdaAsDefaultArgument.test @@ -0,0 +1,5 @@ +// FILE: before.kt +fun test(a: (Int) -> Unit = { it }) {} + +// FILE: after.kt +fun test(a: (Int) -> Unit = { it }) {} \ No newline at end of file diff --git a/idea/testData/navigation/gotoDeclaration/itInLambdaWithoutCall.test b/idea/testData/navigation/gotoDeclaration/itInLambdaWithoutCall.test new file mode 100644 index 00000000000..1e421a62776 --- /dev/null +++ b/idea/testData/navigation/gotoDeclaration/itInLambdaWithoutCall.test @@ -0,0 +1,5 @@ +// FILE: before.kt +val a: (Int) -> Unit = { it } + +// FILE: after.kt +val a: (Int) -> Unit = { it } \ No newline at end of file diff --git a/idea/testData/navigation/gotoDeclaration/itParameterInLambda.test b/idea/testData/navigation/gotoDeclaration/itParameterInLambda.test new file mode 100644 index 00000000000..353aa738559 --- /dev/null +++ b/idea/testData/navigation/gotoDeclaration/itParameterInLambda.test @@ -0,0 +1,23 @@ +// FILE: before.kt +class Foo + +fun some(a: T, f: (T) -> Unit) {} +fun foo(a: Any) {} + +fun baz() { + some(Foo()) { + foo(it) + } +} + +// FILE: after.kt +class Foo + +fun some(a: T, f: (T) -> Unit) {} +fun foo(a: Any) {} + +fun baz() { + some(Foo()) { + foo(it) + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/navigation/AbstractGotoDeclarationTest.kt b/idea/tests/org/jetbrains/kotlin/idea/navigation/AbstractGotoDeclarationTest.kt new file mode 100644 index 00000000000..c2674df97c5 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/navigation/AbstractGotoDeclarationTest.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2017 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.navigation + +abstract class AbstractGotoDeclarationTest : AbstractGotoActionTest() { + override val actionName: String get() = "GotoDeclaration" +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoDeclarationTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoDeclarationTestGenerated.java new file mode 100644 index 00000000000..a9491d2cc80 --- /dev/null +++ b/idea/tests/org/jetbrains/kotlin/idea/navigation/GotoDeclarationTestGenerated.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2017 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.navigation; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("idea/testData/navigation/gotoDeclaration") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class GotoDeclarationTestGenerated extends AbstractGotoDeclarationTest { + public void testAllFilesPresentInGotoDeclaration() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/navigation/gotoDeclaration"), Pattern.compile("^(.+)\\.test$"), TargetBackend.ANY, true); + } + + @TestMetadata("itExtensionLambda.test") + public void testItExtensionLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/itExtensionLambda.test"); + doTest(fileName); + } + + @TestMetadata("itExtensionLambdaInBrackets.test") + public void testItExtensionLambdaInBrackets() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/itExtensionLambdaInBrackets.test"); + doTest(fileName); + } + + @TestMetadata("itInLambdaAsDefaultArgument.test") + public void testItInLambdaAsDefaultArgument() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/itInLambdaAsDefaultArgument.test"); + doTest(fileName); + } + + @TestMetadata("itInLambdaWithoutCall.test") + public void testItInLambdaWithoutCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/itInLambdaWithoutCall.test"); + doTest(fileName); + } + + @TestMetadata("itParameterInLambda.test") + public void testItParameterInLambda() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/navigation/gotoDeclaration/itParameterInLambda.test"); + doTest(fileName); + } +}