From 12a460a1450bb37d0817f2f44529d1d571e0ed25 Mon Sep 17 00:00:00 2001 From: Alexey Sedunov Date: Wed, 16 Oct 2013 17:59:13 +0400 Subject: [PATCH] KT-4043 "Find usages ignores class names usages as class objects" --- .../jet/lang/resolve/BodyResolver.java | 39 ++++++++++++++++--- .../plugin/project/ResolveElementCache.java | 24 ++++++++++++ .../findClassUsages/kotlinClassAllUsages.1.kt | 4 +- .../kotlinClassAllUsages.results.txt | 6 ++- .../kotlinClassNonConstructorUsages.1.kt | 4 +- ...otlinClassNonConstructorUsages.results.txt | 6 ++- 6 files changed, 69 insertions(+), 14 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index ecfd1908cd0..b9d3242579b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -377,18 +377,29 @@ public class BodyResolver { annotationResolver.resolveAnnotationsArguments(classDescriptor.getScopeForSupertypeResolution(), klass.getPrimaryConstructorModifierList(), trace); if (unsubstitutedPrimaryConstructor != null) { - WritableScope parameterScope = new WritableScopeImpl(classDescriptor.getScopeForSupertypeResolution(), unsubstitutedPrimaryConstructor, - RedeclarationHandler.DO_NOTHING, "Scope with value parameters of a constructor"); - for (ValueParameterDescriptor valueParameterDescriptor : unsubstitutedPrimaryConstructor.getValueParameters()) { - parameterScope.addVariableDescriptor(valueParameterDescriptor); - } - parameterScope.changeLockLevel(WritableScope.LockLevel.READING); + WritableScope parameterScope = getPrimaryConstructorParametersScope(classDescriptor.getScopeForSupertypeResolution(), unsubstitutedPrimaryConstructor); expressionTypingServices.resolveValueParameters(klass.getPrimaryConstructorParameters(), unsubstitutedPrimaryConstructor.getValueParameters(), parameterScope, context.getOuterDataFlowInfo(), trace); } } } + private static WritableScope getPrimaryConstructorParametersScope( + JetScope originalScope, + ConstructorDescriptor unsubstitutedPrimaryConstructor + ) { + WritableScope parameterScope = new WritableScopeImpl( + originalScope, + unsubstitutedPrimaryConstructor, + RedeclarationHandler.DO_NOTHING, "Scope with value parameters of a constructor" + ); + for (ValueParameterDescriptor valueParameterDescriptor : unsubstitutedPrimaryConstructor.getValueParameters()) { + parameterScope.addVariableDescriptor(valueParameterDescriptor); + } + parameterScope.changeLockLevel(WritableScope.LockLevel.READING); + return parameterScope; + } + private void resolvePropertyDeclarationBodies() { // Member properties @@ -595,6 +606,22 @@ public class BodyResolver { assert functionDescriptor.getReturnType() != null; } + public void resolveConstructorParameterDefaultValuesAndAnnotations( + @NotNull BindingTrace trace, + @NotNull JetClass klass, + @NotNull ConstructorDescriptor constructorDescriptor, + @NotNull JetScope declaringScope + ) { + if (!context.completeAnalysisNeeded(klass)) return; + + List valueParameters = klass.getPrimaryConstructorParameters(); + List valueParameterDescriptors = constructorDescriptor.getValueParameters(); + + JetScope scope = getPrimaryConstructorParametersScope(declaringScope, constructorDescriptor); + + expressionTypingServices.resolveValueParameters(valueParameters, valueParameterDescriptors, scope, context.getOuterDataFlowInfo(), trace); + } + private void resolveAnnotationArguments(@NotNull JetScope scope, @NotNull JetModifierListOwner owner) { annotationResolver.resolveAnnotationsArguments(scope, owner.getModifierList(), trace); } diff --git a/idea/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java b/idea/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java index d56edc9ac8f..47cf7e99734 100644 --- a/idea/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java +++ b/idea/src/org/jetbrains/jet/plugin/project/ResolveElementCache.java @@ -105,6 +105,11 @@ public class ResolveElementCache { JetParameter parameter = PsiTreeUtil.getTopmostParentOfType(jetElement, JetParameter.class); if (parameter != null) { + JetClass klass = PsiTreeUtil.getParentOfType(parameter, JetClass.class); + if (klass != null && parameter.getParent() == klass.getPrimaryConstructorParameterList()) { + return additionalResolveCache.getValue().invoke(klass); + } + // Parameters for function literal could be met inside other parameters. We can't make resolveToDescriptors for internal elements. jetElement = parameter; } @@ -148,6 +153,9 @@ public class ResolveElementCache { else if (resolveElement instanceof JetAnnotationEntry) { annotationAdditionalResolve(resolveSession, (JetAnnotationEntry) resolveElement); } + else if (resolveElement instanceof JetClass) { + constructorAdditionalResolve(resolveSession, (JetClass) resolveElement, trace, file); + } else if (resolveElement instanceof JetTypeParameter) { typeParameterAdditionalResolve(resolveSession, (JetTypeParameter) resolveElement); } @@ -276,6 +284,22 @@ public class ResolveElementCache { bodyResolver.resolveFunctionBody(trace, namedFunction, functionDescriptor, scope); } + private static void constructorAdditionalResolve( + ResolveSession resolveSession, + JetClass klass, + BindingTrace trace, + JetFile file + ) { + BodyResolver bodyResolver = createBodyResolverWithEmptyContext(trace, file, resolveSession.getRootModuleDescriptor()); + JetScope scope = resolveSession.getInjector().getScopeProvider().getResolutionScopeForDeclaration(klass); + + ClassDescriptor classDescriptor = (ClassDescriptor) resolveSession.resolveToDescriptor(klass); + ConstructorDescriptor constructorDescriptor = classDescriptor.getUnsubstitutedPrimaryConstructor(); + assert constructorDescriptor != null; + + bodyResolver.resolveConstructorParameterDefaultValuesAndAnnotations(trace, klass, constructorDescriptor, scope); + } + private static boolean initializerAdditionalResolve( KotlinCodeAnalyzer analyzer, JetClassInitializer classInitializer, diff --git a/idea/testData/findUsages/findClassUsages/kotlinClassAllUsages.1.kt b/idea/testData/findUsages/findClassUsages/kotlinClassAllUsages.1.kt index 7195e473204..49d6d15a4ec 100644 --- a/idea/testData/findUsages/findClassUsages/kotlinClassAllUsages.1.kt +++ b/idea/testData/findUsages/findClassUsages/kotlinClassAllUsages.1.kt @@ -2,7 +2,7 @@ package client import server.Server -class Client: Server() { +class Client(name: String = Server.NAME): Server() { var nextServer: Server? = new Server() val name = Server.NAME @@ -25,7 +25,7 @@ object ClientObject: Server() { } -fun Client.bar(s: Server) { +fun Client.bar(s: Server = Server.NAME) { foo(s) } diff --git a/idea/testData/findUsages/findClassUsages/kotlinClassAllUsages.results.txt b/idea/testData/findUsages/findClassUsages/kotlinClassAllUsages.results.txt index 43de735ee5f..52cabd4e262 100644 --- a/idea/testData/findUsages/findClassUsages/kotlinClassAllUsages.results.txt +++ b/idea/testData/findUsages/findClassUsages/kotlinClassAllUsages.results.txt @@ -3,11 +3,13 @@ Function return types (14: 26) fun getNextServer(): Server? { Function return types (36: 21) fun Any.asServer(): Server? { Import directive (3: 15) import server.Server Local variable type (10: 21) val server: Server = s +Nested class/object (28: 28) fun Client.bar(s: Server = Server.NAME) { +Nested class/object (5: 29) class Client(name: String = Server.NAME): Server() { Nested class/object (7: 16) val name = Server.NAME -Parameter type (28: 19) fun Client.bar(s: Server) { +Parameter type (28: 19) fun Client.bar(s: Server = Server.NAME) { Parameter type (9: 16) fun foo(s: Server) { Super type qualifier (19: 15) super.work() Target type of 'as' operation (37: 40) return if (this is Server) this as Server else null Target type of 'is' operation (37: 24) return if (this is Server) this as Server else null Unclassified usage (24: 22) object ClientObject: Server() { -Unclassified usage (5: 15) class Client: Server() { \ No newline at end of file +Unclassified usage (5: 43) class Client(name: String = Server.NAME): Server() { diff --git a/idea/testData/findUsages/findClassUsages/kotlinClassNonConstructorUsages.1.kt b/idea/testData/findUsages/findClassUsages/kotlinClassNonConstructorUsages.1.kt index 7195e473204..49d6d15a4ec 100644 --- a/idea/testData/findUsages/findClassUsages/kotlinClassNonConstructorUsages.1.kt +++ b/idea/testData/findUsages/findClassUsages/kotlinClassNonConstructorUsages.1.kt @@ -2,7 +2,7 @@ package client import server.Server -class Client: Server() { +class Client(name: String = Server.NAME): Server() { var nextServer: Server? = new Server() val name = Server.NAME @@ -25,7 +25,7 @@ object ClientObject: Server() { } -fun Client.bar(s: Server) { +fun Client.bar(s: Server = Server.NAME) { foo(s) } diff --git a/idea/testData/findUsages/findClassUsages/kotlinClassNonConstructorUsages.results.txt b/idea/testData/findUsages/findClassUsages/kotlinClassNonConstructorUsages.results.txt index 5b7dc62aeed..f42cfb6ce8e 100644 --- a/idea/testData/findUsages/findClassUsages/kotlinClassNonConstructorUsages.results.txt +++ b/idea/testData/findUsages/findClassUsages/kotlinClassNonConstructorUsages.results.txt @@ -3,9 +3,11 @@ Function return types (14: 26) fun getNextServer(): Server? { Function return types (36: 21) fun Any.asServer(): Server? { Import directive (3: 15) import server.Server Local variable type (10: 21) val server: Server = s +Nested class/object (28: 28) fun Client.bar(s: Server = Server.NAME) { +Nested class/object (5: 29) class Client(name: String = Server.NAME): Server() { Nested class/object (7: 16) val name = Server.NAME -Parameter type (28: 19) fun Client.bar(s: Server) { +Parameter type (28: 19) fun Client.bar(s: Server = Server.NAME) { Parameter type (9: 16) fun foo(s: Server) { Super type qualifier (19: 15) super.work() Target type of 'as' operation (37: 40) return if (this is Server) this as Server else null -Target type of 'is' operation (37: 24) return if (this is Server) this as Server else null \ No newline at end of file +Target type of 'is' operation (37: 24) return if (this is Server) this as Server else null