diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java index abddb9ce0a9..ca209572c82 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java @@ -832,14 +832,14 @@ public class BodyResolver { assert functionDescriptor.getReturnType() != null; } - public void resolveConstructorParameterDefaultValuesAndAnnotations( + public void resolveConstructorParameterDefaultValues( @NotNull DataFlowInfo outerDataFlowInfo, @NotNull BindingTrace trace, - @NotNull KtClass klass, + @NotNull KtPrimaryConstructor constructor, @NotNull ConstructorDescriptor constructorDescriptor, @NotNull LexicalScope declaringScope ) { - List valueParameters = klass.getPrimaryConstructorParameters(); + List valueParameters = constructor.getValueParameters(); List valueParameterDescriptors = constructorDescriptor.getValueParameters(); LexicalScope scope = getPrimaryConstructorParametersScope(declaringScope, constructorDescriptor); diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt index 7d5b2d505fe..2239a8429eb 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt @@ -236,9 +236,9 @@ class ResolveElementCache( element, KtNamedFunction::class.java, KtAnonymousInitializer::class.java, + KtPrimaryConstructor::class.java, KtSecondaryConstructor::class.java, KtProperty::class.java, - KtParameter::class.java, KtSuperTypeList::class.java, KtInitializerList::class.java, KtImportList::class.java, @@ -265,15 +265,6 @@ class ResolveElementCache( is KtPackageDirective -> return element - is KtParameter -> { - val klass = elementOfAdditionalResolve.getParentOfType(strict = true) - if (klass != null && elementOfAdditionalResolve.getParent() == klass.getPrimaryConstructorParameterList()) { - return klass - } - - return elementOfAdditionalResolve - } - is KtDeclaration -> { if (element is KtParameter && !KtPsiUtil.isLocal(element)) { return null @@ -316,6 +307,8 @@ class ResolveElementCache( is KtAnonymousInitializer -> initializerAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter(), bodyResolveMode.bindingTraceFilter) + is KtPrimaryConstructor -> constructorAdditionalResolve(resolveSession, resolveElement.parent as KtClass, file, bodyResolveMode.bindingTraceFilter) + is KtSecondaryConstructor -> secondaryConstructorAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter(), bodyResolveMode.bindingTraceFilter) is KtProperty -> propertyAdditionalResolve(resolveSession, resolveElement, file, createStatementFilter(), bodyResolveMode.bindingTraceFilter) @@ -342,8 +335,6 @@ class ResolveElementCache( is KtAnnotationEntry -> annotationAdditionalResolve(resolveSession, resolveElement) - is KtClass -> constructorAdditionalResolve(resolveSession, resolveElement, file, bodyResolveMode.bindingTraceFilter) - is KtTypeAlias -> typealiasAdditionalResolve(resolveSession, resolveElement, bodyResolveMode.bindingTraceFilter) is KtTypeParameter -> typeParameterAdditionalResolve(resolveSession, resolveElement) @@ -548,8 +539,13 @@ class ResolveElementCache( ?: error("Can't get primary constructor for descriptor '$classDescriptor' " + "in from class '${klass.getElementTextWithContext()}'") - val bodyResolver = createBodyResolver(resolveSession, trace, file, StatementFilter.NONE) - bodyResolver.resolveConstructorParameterDefaultValuesAndAnnotations(DataFlowInfo.EMPTY, trace, klass, constructorDescriptor, scope) + val primaryConstructor = klass.getPrimaryConstructor() + if (primaryConstructor != null) { + val bodyResolver = createBodyResolver(resolveSession, trace, file, StatementFilter.NONE) + bodyResolver.resolveConstructorParameterDefaultValues(DataFlowInfo.EMPTY, trace, primaryConstructor, constructorDescriptor, scope) + + forceResolveAnnotationsInside(primaryConstructor) + } return trace } diff --git a/idea/idea-completion/testData/handlers/basic/annotation/KT12077.kt b/idea/idea-completion/testData/handlers/basic/annotation/KT12077.kt new file mode 100644 index 00000000000..5eaa3319e6c --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/annotation/KT12077.kt @@ -0,0 +1,7 @@ +package some + +annotation class SomeAnnotation + +class Complete(@set:Some var field: Int) + +// ELEMENT: SomeAnnotation \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/basic/annotation/KT12077.kt.after b/idea/idea-completion/testData/handlers/basic/annotation/KT12077.kt.after new file mode 100644 index 00000000000..04f7c6393e8 --- /dev/null +++ b/idea/idea-completion/testData/handlers/basic/annotation/KT12077.kt.after @@ -0,0 +1,7 @@ +package some + +annotation class SomeAnnotation + +class Complete(@set:SomeAnnotation var field: Int) + +// ELEMENT: SomeAnnotation \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/multifile/KT12077-1.kt b/idea/idea-completion/testData/handlers/multifile/KT12077-1.kt new file mode 100644 index 00000000000..e1dd78a140b --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/KT12077-1.kt @@ -0,0 +1,3 @@ +package some + +class Complete(@set:SomeAnn var field: Int) diff --git a/idea/idea-completion/testData/handlers/multifile/KT12077-2.kt b/idea/idea-completion/testData/handlers/multifile/KT12077-2.kt new file mode 100644 index 00000000000..b08ab96874d --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/KT12077-2.kt @@ -0,0 +1,3 @@ +package other + +annotation class SomeAnnotation diff --git a/idea/idea-completion/testData/handlers/multifile/KT12077.kt.after b/idea/idea-completion/testData/handlers/multifile/KT12077.kt.after new file mode 100644 index 00000000000..9bff4ea8689 --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/KT12077.kt.after @@ -0,0 +1,5 @@ +package some + +import other.SomeAnnotation + +class Complete(@set:SomeAnnotation var field: Int) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/AbstractCompletionHandlerTests.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/AbstractCompletionHandlerTests.kt index 08918cc4a60..33abbac5dd8 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/AbstractCompletionHandlerTests.kt +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/AbstractCompletionHandlerTests.kt @@ -42,6 +42,7 @@ abstract class AbstractCompletionHandlerTest(private val defaultCompletionType: settingManager.temporarySettings = tempSettings try { val fileText = FileUtil.loadFile(File(testPath)) + assertTrue("\"\" is missing in file \"$testPath\"", fileText.contains("")); val invocationCount = InTextDirectivesUtils.getPrefixedInt(fileText, INVOCATION_COUNT_PREFIX) ?: 1 val lookupString = InTextDirectivesUtils.findStringWithPrefixes(fileText, LOOKUP_STRING_PREFIX) val itemText = InTextDirectivesUtils.findStringWithPrefixes(fileText, ELEMENT_TEXT_PREFIX) diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java index fc1e8aeb129..3927779c982 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/BasicCompletionHandlerTestGenerated.java @@ -228,6 +228,12 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/annotation/AnnotationInCompanionObjectAddImport.kt"); doTest(fileName); } + + @TestMetadata("KT12077.kt") + public void testKT12077() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/annotation/KT12077.kt"); + doTest(fileName); + } } @TestMetadata("idea/idea-completion/testData/handlers/basic/callableReference") diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt index 032fbc2e4f0..0701e54e06c 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt @@ -105,6 +105,10 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() { doTest() } + fun testKT12077() { + doTest() + } + fun doTest(completionChar: Char = '\n', vararg extraFileNames: String) { val fileName = getTestName(false) diff --git a/idea/testData/quickfix/autoImports/constructorParameterAnnotation.test b/idea/testData/quickfix/autoImports/constructorParameterAnnotation.test new file mode 100644 index 00000000000..1a01db55947 --- /dev/null +++ b/idea/testData/quickfix/autoImports/constructorParameterAnnotation.test @@ -0,0 +1,24 @@ +// FILE: first.before.kt +// "Import" "true" +// ERROR: Unresolved reference: SomeAnnotation + +package some + +class X(@set:SomeAnnotation var field: Int) +//----------------------- +// FILE: second.kt + +package other + +annotation class SomeAnnotation +//----------------------- +// FILE: first.after.kt +// "Import" "true" +// ERROR: Unresolved reference: SomeAnnotation + +package some + +import other.SomeAnnotation + +class X(@set:SomeAnnotation var field: Int) +//----------------------- diff --git a/idea/testData/shortenRefs/annotation.kt b/idea/testData/shortenRefs/annotation.kt new file mode 100644 index 00000000000..f4a2e26fac9 --- /dev/null +++ b/idea/testData/shortenRefs/annotation.kt @@ -0,0 +1,5 @@ +package some + +annotation class SomeAnnotation + +class Complete(@set:some.SomeAnnotation var field: Int) diff --git a/idea/testData/shortenRefs/annotation.kt.after b/idea/testData/shortenRefs/annotation.kt.after new file mode 100644 index 00000000000..0a4e8eac937 --- /dev/null +++ b/idea/testData/shortenRefs/annotation.kt.after @@ -0,0 +1,5 @@ +package some + +annotation class SomeAnnotation + +class Complete(@set:SomeAnnotation var field: Int) diff --git a/idea/tests/org/jetbrains/kotlin/idea/ResolveElementCacheTest.kt b/idea/tests/org/jetbrains/kotlin/idea/ResolveElementCacheTest.kt index 7a1d1a1ad12..e0f55fd8002 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/ResolveElementCacheTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/ResolveElementCacheTest.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyzeFullyAndGetResult import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor +import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor import org.jetbrains.kotlin.idea.util.application.executeWriteCommand @@ -365,6 +366,69 @@ class C(param1: String = "", param2: Int = 0) { annotationArguments.analyzeFullyAndGetResult() } + fun testFunctionParameterAnnotation() { + val file = myFixture.configureByText("Test.kt", """ + annotation class Ann + fun foo(@Ann p: Int) { + bar() + } + """) as KtFile + + val function = (file.declarations[1]) as KtFunction + val annotationEntry = function.valueParameters[0].annotationEntries[0] + val typeRef = annotationEntry.typeReference!! + + val bindingContext = typeRef.analyze(BodyResolveMode.PARTIAL) + + val referenceExpr = (typeRef.typeElement as KtUserType).referenceExpression + val target = bindingContext[BindingContext.REFERENCE_TARGET, referenceExpr] + TestCase.assertEquals("Ann", target?.importableFqName?.asString()) + + val statement = (function.bodyExpression as KtBlockExpression).statements[0] + TestCase.assertEquals(null, bindingContext[BindingContext.PROCESSED, statement]) + } + + fun testPrimaryConstructorParameterAnnotation() { + val file = myFixture.configureByText("Test.kt", """ + annotation class Ann + class X(@set:Ann var p: Int) + """) as KtFile + + val constructor = ((file.declarations[1]) as KtClass).getPrimaryConstructor()!! + val annotationEntry = constructor.valueParameters[0].annotationEntries[0] + val typeRef = annotationEntry.typeReference!! + + val bindingContext = typeRef.analyze(BodyResolveMode.PARTIAL) + + val referenceExpr = (typeRef.typeElement as KtUserType).referenceExpression + val target = bindingContext[BindingContext.REFERENCE_TARGET, referenceExpr] + TestCase.assertEquals("Ann", target?.importableFqName?.asString()) + } + + fun testSecondaryConstructorParameterAnnotation() { + val file = myFixture.configureByText("Test.kt", """ + annotation class Ann + class X { + constructor(@Ann p: Int) { + foo() + } + } + """) as KtFile + + val constructor = ((file.declarations[1]) as KtClass).getSecondaryConstructors()[0] + val annotationEntry = constructor.valueParameters[0].annotationEntries[0] + val typeRef = annotationEntry.typeReference!! + + val bindingContext = typeRef.analyze(BodyResolveMode.PARTIAL) + + val referenceExpr = (typeRef.typeElement as KtUserType).referenceExpression + val target = bindingContext[BindingContext.REFERENCE_TARGET, referenceExpr] + TestCase.assertEquals("Ann", target?.importableFqName?.asString()) + + val statement = (constructor.bodyExpression as KtBlockExpression).statements[0] + TestCase.assertEquals(null, bindingContext[BindingContext.PROCESSED, statement]) + } + fun testFullResolveMultiple() { doTest { val aBody = (members[0] as KtFunction).bodyExpression as KtBlockExpression diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index abb6534502e..c40bea050d3 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -89,6 +89,12 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes doTestWithExtraFile(fileName); } + @TestMetadata("constructorParameterAnnotation.test") + public void testConstructorParameterAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/constructorParameterAnnotation.test"); + doTestWithExtraFile(fileName); + } + @TestMetadata("delegateExtensionBoth.test") public void testDelegateExtensionBoth() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/autoImports/delegateExtensionBoth.test"); diff --git a/idea/tests/org/jetbrains/kotlin/shortenRefs/ShortenRefsTestGenerated.java b/idea/tests/org/jetbrains/kotlin/shortenRefs/ShortenRefsTestGenerated.java index df84d686a4b..31b15f0da10 100644 --- a/idea/tests/org/jetbrains/kotlin/shortenRefs/ShortenRefsTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/shortenRefs/ShortenRefsTestGenerated.java @@ -35,6 +35,12 @@ public class ShortenRefsTestGenerated extends AbstractShortenRefsTest { KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/shortenRefs"), Pattern.compile("^([^.]+)\\.kt$"), true); } + @TestMetadata("annotation.kt") + public void testAnnotation() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/shortenRefs/annotation.kt"); + doTest(fileName); + } + @TestMetadata("ClassNameConflict.kt") public void testClassNameConflict() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/shortenRefs/ClassNameConflict.kt");