KT-758 Show completion of namespaces in import statement

This commit is contained in:
Nikolay Krasko
2012-01-10 18:59:42 +04:00
parent e50e3f8ec8
commit fb5771505b
5 changed files with 63 additions and 15 deletions
@@ -8,8 +8,10 @@ import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor; import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.psi.JetExpression; import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetImportDirective;
import org.jetbrains.jet.lang.psi.JetQualifiedExpression; import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression; import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.BindingContext;
@@ -42,12 +44,14 @@ public final class TipsManager {
@NotNull @NotNull
public static Collection<DeclarationDescriptor> getReferenceVariants(JetSimpleNameExpression expression, BindingContext context) { public static Collection<DeclarationDescriptor> getReferenceVariants(JetSimpleNameExpression expression, BindingContext context) {
PsiElement parent = expression.getParent(); PsiElement parent = expression.getParent();
if (parent instanceof JetQualifiedExpression) {
if (parent instanceof JetQualifiedExpression && !(parent.getParent() instanceof JetImportDirective)) {
// Process as call expression
JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent; JetQualifiedExpression qualifiedExpression = (JetQualifiedExpression) parent;
JetExpression receiverExpression = qualifiedExpression.getReceiverExpression(); JetExpression receiverExpression = qualifiedExpression.getReceiverExpression();
final JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
final JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, receiverExpression); final JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, receiverExpression);
final JetType expressionType = context.get(BindingContext.EXPRESSION_TYPE, receiverExpression);
if (expressionType != null && resolutionScope != null) { if (expressionType != null && resolutionScope != null) {
return includeExternalCallableExtensions( return includeExternalCallableExtensions(
@@ -58,7 +62,12 @@ public final class TipsManager {
else { else {
JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression); JetScope resolutionScope = context.get(BindingContext.RESOLUTION_SCOPE, expression);
if (resolutionScope != null) { if (resolutionScope != null) {
return excludeNotCallableExtensions(resolutionScope.getAllDescriptors(), resolutionScope); if (parent instanceof JetImportDirective) {
return excludeNonPackageDescriptors(resolutionScope.getAllDescriptors());
}
else {
return excludeNotCallableExtensions(resolutionScope.getAllDescriptors(), resolutionScope);
}
} }
} }
@@ -80,6 +89,16 @@ public final class TipsManager {
return Lists.newArrayList(descriptorsSet); return Lists.newArrayList(descriptorsSet);
} }
private static Collection<DeclarationDescriptor> excludeNonPackageDescriptors(
@NotNull Collection<DeclarationDescriptor> descriptors) {
return Collections2.filter(descriptors, new Predicate<DeclarationDescriptor>() {
@Override
public boolean apply(DeclarationDescriptor declarationDescriptor) {
return declarationDescriptor instanceof NamespaceDescriptor;
}
});
}
private static Collection<DeclarationDescriptor> includeExternalCallableExtensions( private static Collection<DeclarationDescriptor> includeExternalCallableExtensions(
@NotNull Collection<DeclarationDescriptor> descriptors, @NotNull Collection<DeclarationDescriptor> descriptors,
@@ -26,7 +26,7 @@ public class StandardConfiguration implements Configuration {
@Override @Override
public void addDefaultImports(@NotNull BindingTrace trace, @NotNull WritableScope rootScope) { public void addDefaultImports(@NotNull BindingTrace trace, @NotNull WritableScope rootScope) {
JetImportDirective importDirective = JetPsiFactory.createImportDirective(project, "std.*"); JetImportDirective importDirective = JetPsiFactory.createImportDirective(project, "std.*");
new ImportsResolver.ImportResolver(trace, true).processImportReference(importDirective, rootScope, rootScope); new ImportsResolver.ImportResolver(trace, true).processImportReference(importDirective, rootScope);
} }
@Override @Override
@@ -46,7 +46,7 @@ public class ImportsResolver {
List<JetImportDirective> importDirectives = file.getImportDirectives(); List<JetImportDirective> importDirectives = file.getImportDirectives();
for (JetImportDirective importDirective : importDirectives) { for (JetImportDirective importDirective : importDirectives) {
importResolver.processImportReference(importDirective, namespaceScope, JetScope.EMPTY); importResolver.processImportReference(importDirective, namespaceScope);
} }
} }
} }
@@ -60,7 +60,7 @@ public class ImportsResolver {
this.firstPhase = firstPhase; this.firstPhase = firstPhase;
} }
public void processImportReference(JetImportDirective importDirective, WritableScope namespaceScope, JetScope outerScope) { public void processImportReference(JetImportDirective importDirective, WritableScope namespaceScope) {
if (importDirective.isAbsoluteInRootNamespace()) { if (importDirective.isAbsoluteInRootNamespace()) {
trace.report(UNSUPPORTED.on(importDirective, "TypeHierarchyResolver")); // TODO trace.report(UNSUPPORTED.on(importDirective, "TypeHierarchyResolver")); // TODO
return; return;
@@ -73,8 +73,17 @@ public class ImportsResolver {
} }
else { else {
assert importedReference instanceof JetSimpleNameExpression; assert importedReference instanceof JetSimpleNameExpression;
JetScope scope = importDirective.isAllUnder() ? namespaceScope : outerScope;
descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, scope); if (importDirective.isAllUnder()) {
// Example: import java.*
descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, namespaceScope);
}
else {
// Example: import IDENTIFIER
// Should be unresolved error
descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, JetScope.EMPTY);
trace.record(BindingContext.RESOLUTION_SCOPE, importedReference, namespaceScope);
}
} }
JetSimpleNameExpression referenceExpression = getLastReference(importedReference); JetSimpleNameExpression referenceExpression = getLastReference(importedReference);
if (importDirective.isAllUnder()) { if (importDirective.isAllUnder()) {
@@ -88,9 +97,7 @@ public class ImportsResolver {
} }
if (descriptor instanceof VariableDescriptor) { if (descriptor instanceof VariableDescriptor) {
JetType type = ((VariableDescriptor) descriptor).getOutType(); JetType type = ((VariableDescriptor) descriptor).getOutType();
if (type != null) { namespaceScope.importScope(ScopeBoundToReceiver.create(descriptor, type.getMemberScope()));
namespaceScope.importScope(ScopeBoundToReceiver.create(descriptor, type.getMemberScope()));
}
} }
else if (descriptor instanceof ClassDescriptor) { else if (descriptor instanceof ClassDescriptor) {
namespaceScope.importScope(ScopeBoundToReceiver.create(descriptor, ((ClassDescriptor) descriptor).getDefaultType().getMemberScope())); namespaceScope.importScope(ScopeBoundToReceiver.create(descriptor, ((ClassDescriptor) descriptor).getDefaultType().getMemberScope()));
@@ -159,12 +166,13 @@ public class ImportsResolver {
return lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope()); return lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope());
} }
if (declarationDescriptor instanceof ClassDescriptor) { if (declarationDescriptor instanceof ClassDescriptor) {
return lookupObjectMembers(selector, lastReference, (ClassDescriptor) declarationDescriptor); return lookupObjectMembers(selector, (ClassDescriptor) declarationDescriptor);
} }
if (declarationDescriptor instanceof VariableDescriptor) { if (declarationDescriptor instanceof VariableDescriptor) {
return lookupVariableMembers(selector, (VariableDescriptor) declarationDescriptor); return lookupVariableMembers(selector, (VariableDescriptor) declarationDescriptor);
} }
} }
return Collections.emptyList(); return Collections.emptyList();
} }
@@ -206,7 +214,8 @@ public class ImportsResolver {
} }
@NotNull @NotNull
private Collection<DeclarationDescriptor> lookupObjectMembers(@NotNull JetSimpleNameExpression memberReference, @NotNull JetSimpleNameExpression classReference, @NotNull ClassDescriptor classDescriptor) { private Collection<DeclarationDescriptor> lookupObjectMembers(@NotNull JetSimpleNameExpression memberReference,
@NotNull ClassDescriptor classDescriptor) {
if (firstPhase) return Collections.emptyList(); if (firstPhase) return Collections.emptyList();
JetType classObjectType = classDescriptor.getClassObjectType(); JetType classObjectType = classDescriptor.getClassObjectType();
assert classObjectType != null; assert classObjectType != null;
@@ -230,6 +239,7 @@ public class ImportsResolver {
@NotNull @NotNull
private Collection<DeclarationDescriptor> lookupDescriptorsForSimpleNameReference(@NotNull JetSimpleNameExpression referenceExpression, @NotNull JetScope outerScope) { private Collection<DeclarationDescriptor> lookupDescriptorsForSimpleNameReference(@NotNull JetSimpleNameExpression referenceExpression, @NotNull JetScope outerScope) {
List<DeclarationDescriptor> descriptors = Lists.newArrayList(); List<DeclarationDescriptor> descriptors = Lists.newArrayList();
String referencedName = referenceExpression.getReferencedName(); String referencedName = referenceExpression.getReferencedName();
if (referencedName != null) { if (referencedName != null) {
@@ -242,11 +252,10 @@ public class ImportsResolver {
descriptors.addAll(outerScope.getFunctions(referencedName)); descriptors.addAll(outerScope.getFunctions(referencedName));
descriptors.addAll(outerScope.getProperties(referencedName)); descriptors.addAll(outerScope.getProperties(referencedName));
} }
if (!firstPhase) { if (!firstPhase) {
if (descriptors.size() == 1) { if (descriptors.size() == 1) {
trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptors.iterator().next()); trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptors.get(0));
} }
else if (descriptors.size() > 1) { else if (descriptors.size() > 1) {
trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, descriptors); trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, descriptors);
@@ -254,6 +263,11 @@ public class ImportsResolver {
else { else {
trace.report(UNRESOLVED_REFERENCE.on(referenceExpression)); trace.report(UNRESOLVED_REFERENCE.on(referenceExpression));
} }
// If it's not an ambiguous case - store resolution scope
if (descriptors.size() <= 1 && outerScope != JetScope.EMPTY) {
trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, outerScope);
}
} }
return descriptors; return descriptors;
} }
@@ -0,0 +1,6 @@
package Test
import <caret>
// EXIST: java, javax, reflect
// ABSENT: Array, Integer
@@ -0,0 +1,9 @@
package Test
import java.util.<caret>
class Test {
}
// EXIST: AbstractList, Date, Random, concurrent