From 138373c94c3a8783a1d908cf7917ae489077ec6b Mon Sep 17 00:00:00 2001 From: Nikolay Krasko Date: Tue, 4 Sep 2012 15:36:30 +0400 Subject: [PATCH] KT-2724 No completion in class initializers #KT-2724 Fixed --- .../descriptors/MutableClassDescriptor.java | 2 - .../jet/lang/psi/JetClassOrObject.java | 2 +- .../jetbrains/jet/lang/psi/JetPsiUtil.java | 18 ++++ .../jet/lang/resolve/BodyResolver.java | 17 ++-- .../resolve/lazy/ResolveSessionUtils.java | 87 +++++++++++++------ .../completion/basic/InClassInitializer.kt | 12 +++ .../basic/InFunInClassInitializer.kt | 11 +++ .../completion/JetBasicCompletionTest.java | 9 +- 8 files changed, 123 insertions(+), 35 deletions(-) create mode 100644 idea/testData/completion/basic/InClassInitializer.kt create mode 100644 idea/testData/completion/basic/InFunInClassInitializer.kt diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java index b78abecaf32..70d0ace556c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/MutableClassDescriptor.java @@ -112,8 +112,6 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite implement return primaryConstructor; } - - @NotNull public Set getFunctions() { return functions; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java index 633a4da507c..0a0336f8f55 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetClassOrObject.java @@ -26,7 +26,7 @@ import java.util.List; /** * @author max */ -public interface JetClassOrObject extends PsiNameIdentifierOwner, JetDeclarationContainer, JetElement, JetModifierListOwner { +public interface JetClassOrObject extends PsiNameIdentifierOwner, JetDeclarationContainer, JetElement, JetModifierListOwner, JetDeclaration { @Nullable JetDelegationSpecifierList getDelegationSpecifierList(); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index d93a3481107..235b25501af 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -352,4 +352,22 @@ public class JetPsiUtil { JetMultiDeclarationEntry multiDeclarationEntry = (JetMultiDeclarationEntry) declaration; return !(multiDeclarationEntry.getParent().getParent() instanceof JetForExpression); } + + public static PsiElement getTopmostParentOfTypes(@Nullable PsiElement element, @NotNull Class... parentTypes) { + if (element == null) { + return null; + } + + PsiElement result = null; + PsiElement parent = element.getParent(); + while (parent != null) { + if (PsiTreeUtil.instanceOf(parent, parentTypes)) { + result = parent; + } + + parent = parent.getParent(); + } + + return result; + } } 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 7858fe95bac..34064c579ba 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -21,6 +21,7 @@ import com.google.common.collect.Sets; import com.intellij.psi.PsiElement; import com.intellij.util.containers.Queue; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.calls.CallMaker; @@ -322,12 +323,18 @@ public class BodyResolver { } private void resolveAnonymousInitializers(JetClassOrObject jetClassOrObject, MutableClassDescriptor classDescriptor) { - if (!context.completeAnalysisNeeded(jetClassOrObject)) return; + resolveAnonymousInitializers(jetClassOrObject, classDescriptor.getUnsubstitutedPrimaryConstructor(), + classDescriptor.getScopeForInitializers()); + } + + public void resolveAnonymousInitializers(JetClassOrObject jetClassOrObject, + @Nullable ConstructorDescriptor primaryConstructor, + @NotNull JetScope scopeForInitializers) { + if (!context.completeAnalysisNeeded(jetClassOrObject)) { + return; + } List anonymousInitializers = jetClassOrObject.getAnonymousInitializers(); - if (classDescriptor.getUnsubstitutedPrimaryConstructor() != null) { - ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor(); - assert primaryConstructor != null; - final JetScope scopeForInitializers = classDescriptor.getScopeForInitializers(); + if (primaryConstructor != null) { for (JetClassInitializer anonymousInitializer : anonymousInitializers) { expressionTypingServices.getType(scopeForInitializers, anonymousInitializer.getBody(), NO_EXPECTED_TYPE, DataFlowInfo.EMPTY, trace); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSessionUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSessionUtils.java index 92d1807cec3..2863d7d2e15 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSessionUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/ResolveSessionUtils.java @@ -18,7 +18,6 @@ package org.jetbrains.jet.lang.resolve.lazy; import com.google.common.base.Predicates; import com.google.common.collect.Lists; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.util.PsiTreeUtil; @@ -39,8 +38,6 @@ import java.util.*; * @author Nikolay Krasko */ public class ResolveSessionUtils { - private static final Logger LOG = Logger.getInstance("#" + ResolveSessionUtils.class.getName()); - private ResolveSessionUtils() { } @@ -90,34 +87,33 @@ public class ResolveSessionUtils { } } - public static @NotNull BindingContext resolveToExpression(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) { + public static + @NotNull + BindingContext resolveToExpression( + @NotNull final ResolveSession resolveSession, + @NotNull JetExpression expression + ) { final DelegatingBindingTrace trace = new DelegatingBindingTrace(resolveSession.getBindingContext()); - JetFile file = (JetFile) expression.getContainingFile(); - // Resolve enclosing function body - JetNamedFunction namedFunction = PsiTreeUtil.getTopmostParentOfType(expression, JetNamedFunction.class); - if (namedFunction != null) { - TopDownAnalysisParameters parameters = new TopDownAnalysisParameters( - Predicates.alwaysTrue(), false, true, Collections.emptyList()); + @SuppressWarnings("unchecked") PsiElement topmostCandidateForAdditionalResolve = JetPsiUtil.getTopmostParentOfTypes(expression, + JetNamedFunction.class, JetClassInitializer.class); - InjectorForBodyResolve bodyResolve = new InjectorForBodyResolve(file.getProject(), parameters, trace, new EmptyBodyResolveContext()); - - final BodyResolver bodyResolver = bodyResolve.getBodyResolver(); - - if (namedFunction.getParent() instanceof JetFile || - namedFunction.getParent() instanceof JetClassBody || - namedFunction.getParent() instanceof JetClassObject) { - JetScope scope = resolveSession.getResolutionScope(namedFunction); - FunctionDescriptor functionDescriptor = (FunctionDescriptor) resolveSession.resolveToDescriptor(namedFunction); - bodyResolver.resolveFunctionBody(trace, namedFunction, functionDescriptor, scope); + if (topmostCandidateForAdditionalResolve != null) { + if (topmostCandidateForAdditionalResolve instanceof JetNamedFunction) { + functionAdditionalResolve(resolveSession, (JetNamedFunction) topmostCandidateForAdditionalResolve, trace, file); + } + else if (topmostCandidateForAdditionalResolve instanceof JetClassInitializer) { + initializerAdditionalResolve(resolveSession, (JetClassInitializer) topmostCandidateForAdditionalResolve, trace, file); } else { - LOG.warn(String.format("Not expected parent for function: %s in %s", - namedFunction.getName(), namedFunction.getContainingFile())); + assert false : "Invalid type of the topmost parent"; } + + return trace.getBindingContext(); } + // Setup resolution scope explicitly if (trace.getBindingContext().get(BindingContext.RESOLUTION_SCOPE, expression) == null) { JetScope scope = getExpressionMemberScope(resolveSession, expression); if (scope != null) { @@ -128,7 +124,45 @@ public class ResolveSessionUtils { return trace.getBindingContext(); } - private static JetScope getExpressionOuterScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) { + private static void functionAdditionalResolve( + ResolveSession resolveSession, + JetNamedFunction namedFunction, + DelegatingBindingTrace trace, + JetFile file + ) { + BodyResolver bodyResolver = createBodyResolver(trace, file); + JetScope scope = resolveSession.getResolutionScope(namedFunction); + FunctionDescriptor functionDescriptor = (FunctionDescriptor) resolveSession.resolveToDescriptor(namedFunction); + bodyResolver.resolveFunctionBody(trace, namedFunction, functionDescriptor, scope); + } + + private static boolean initializerAdditionalResolve( + ResolveSession resolveSession, + JetClassInitializer classInitializer, + DelegatingBindingTrace trace, + JetFile file + ) { + BodyResolver bodyResolver = createBodyResolver(trace, file); + JetClassOrObject classOrObject = PsiTreeUtil.getParentOfType(classInitializer, JetClassOrObject.class); + LazyClassDescriptor classOrObjectDescriptor = (LazyClassDescriptor) resolveSession.resolveToDescriptor(classOrObject); + bodyResolver.resolveAnonymousInitializers(classOrObject, classOrObjectDescriptor.getUnsubstitutedPrimaryConstructor(), + classOrObjectDescriptor.getScopeForPropertyInitializerResolution()); + + return true; + } + + private static BodyResolver createBodyResolver(DelegatingBindingTrace trace, JetFile file, EmptyBodyResolveContext bodyResolveContext) { + TopDownAnalysisParameters parameters = new TopDownAnalysisParameters( + Predicates.alwaysTrue(), false, true, Collections.emptyList()); + InjectorForBodyResolve bodyResolve = new InjectorForBodyResolve(file.getProject(), parameters, trace, bodyResolveContext); + return bodyResolve.getBodyResolver(); + } + + private static BodyResolver createBodyResolver(DelegatingBindingTrace trace, JetFile file) { + return createBodyResolver(trace, file, new EmptyBodyResolveContext()); + } + + private static JetScope getExpressionResolutionScope(@NotNull ResolveSession resolveSession, @NotNull JetExpression expression) { JetDeclaration parentDeclaration = PsiTreeUtil.getParentOfType(expression, JetDeclaration.class); // DeclarationDescriptor descriptor = resolveToDescriptor(parentDeclaration); return resolveSession.getResolutionScope(parentDeclaration); @@ -145,7 +179,7 @@ public class ResolveSessionUtils { JetUserType qualifier = ((JetUserType) expression.getParent()).getQualifier(); if (qualifier != null) { Collection descriptors = qualifiedExpressionResolver - .lookupDescriptorsForUserType(qualifier, getExpressionOuterScope(resolveSession, expression), trace); + .lookupDescriptorsForUserType(qualifier, getExpressionResolutionScope(resolveSession, expression), trace); for (DeclarationDescriptor descriptor : descriptors) { if (descriptor instanceof LazyPackageDescriptor) { @@ -164,7 +198,8 @@ public class ResolveSessionUtils { JetExpression element = ((JetDotQualifiedExpression) expression.getParent()).getReceiverExpression(); String name = ((JetFile) expression.getContainingFile()).getPackageName(); - NamespaceDescriptor filePackage = name != null ? resolveSession.getPackageDescriptorByFqName(new FqName(name)) : rootPackage; + NamespaceDescriptor filePackage = + name != null ? resolveSession.getPackageDescriptorByFqName(new FqName(name)) : rootPackage; assert filePackage != null : "File package should be already resolved and be found"; JetScope scope = filePackage.getMemberScope(); @@ -194,7 +229,7 @@ public class ResolveSessionUtils { JetNamespaceHeader namespaceHeader = PsiTreeUtil.getParentOfType(expression, JetNamespaceHeader.class, false); if (namespaceHeader != null) { NamespaceDescriptor packageDescriptor = resolveSession.getPackageDescriptorByFqName( - namespaceHeader.getParentFqName((JetReferenceExpression)expression)); + namespaceHeader.getParentFqName((JetReferenceExpression) expression)); if (packageDescriptor != null) { return packageDescriptor.getMemberScope(); } diff --git a/idea/testData/completion/basic/InClassInitializer.kt b/idea/testData/completion/basic/InClassInitializer.kt new file mode 100644 index 00000000000..8ae9a21e7df --- /dev/null +++ b/idea/testData/completion/basic/InClassInitializer.kt @@ -0,0 +1,12 @@ +val testExternal + +class Some(testParam : Int) { + private val myVal : Int + + { + val testing = 12 + myVal = test + } +} + +// EXIST: testParam, testExternal, testing diff --git a/idea/testData/completion/basic/InFunInClassInitializer.kt b/idea/testData/completion/basic/InFunInClassInitializer.kt new file mode 100644 index 00000000000..bbe187f97e4 --- /dev/null +++ b/idea/testData/completion/basic/InFunInClassInitializer.kt @@ -0,0 +1,11 @@ +val some = 12 +class Some(someParam : Int) { + { + fun internalFun(someInternal : Int) : Int { + return some + } + } +} + +// EXIST: some, someInternal, someParam + diff --git a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java index 1a21c8beafc..8cec57bb2e2 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java +++ b/idea/tests/org/jetbrains/jet/completion/JetBasicCompletionTest.java @@ -88,10 +88,18 @@ public class JetBasicCompletionTest extends JetCompletionTestBase { doTest(); } + public void testInClassInitializer() { + doTest(); + } + public void testInEmptyImport() { doTest(); } + public void testInFunInClassInitializer() { + doTest(); + } + public void testInImport() { doTest(); } @@ -100,7 +108,6 @@ public class JetBasicCompletionTest extends JetCompletionTestBase { doTest(); } - public void testInMiddleOfNamespace() { doTest(); }