KT-2724 No completion in class initializers

#KT-2724 Fixed
This commit is contained in:
Nikolay Krasko
2012-09-04 15:36:30 +04:00
parent a0c2cee754
commit 138373c94c
8 changed files with 123 additions and 35 deletions
@@ -112,8 +112,6 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite implement
return primaryConstructor;
}
@NotNull
public Set<SimpleFunctionDescriptor> getFunctions() {
return functions;
@@ -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();
@@ -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<? extends PsiElement>... 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;
}
}
@@ -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<JetClassInitializer> 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);
}
@@ -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.<PsiFile>alwaysTrue(), false, true, Collections.<AnalyzerScriptParameter>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.<PsiFile>alwaysTrue(), false, true, Collections.<AnalyzerScriptParameter>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<? extends DeclarationDescriptor> 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();
}
@@ -0,0 +1,12 @@
val testExternal
class Some(testParam : Int) {
private val myVal : Int
{
val testing = 12
myVal = test<caret>
}
}
// EXIST: testParam, testExternal, testing
@@ -0,0 +1,11 @@
val some = 12
class Some(someParam : Int) {
{
fun internalFun(someInternal : Int) : Int {
return some<caret>
}
}
}
// EXIST: some, someInternal, someParam
@@ -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();
}