diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index e90a6889c11..b1cc74fdea5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -85,7 +85,8 @@ public interface Errors { ParameterizedDiagnosticFactory1 CANNOT_IMPORT_FROM_ELEMENT = ParameterizedDiagnosticFactory1.create(ERROR, "Cannot import from ''{0}''", NAME); ParameterizedDiagnosticFactory1 CANNOT_BE_IMPORTED = ParameterizedDiagnosticFactory1.create(ERROR, "Cannot import ''{0}'', functions and properties can be imported only from packages", NAME); - SimpleDiagnosticFactory USELESS_IMPORT = SimpleDiagnosticFactory.create(ERROR, "Useless import"); + SimpleDiagnosticFactory USELESS_HIDDEN_IMPORT = SimpleDiagnosticFactory.create(WARNING, "Useless import, it is hidden further"); + SimpleDiagnosticFactory USELESS_SIMPLE_IMPORT = SimpleDiagnosticFactory.create(WARNING, "Useless import, does nothing"); SimpleDiagnosticFactory CANNOT_INFER_PARAMETER_TYPE = SimpleDiagnosticFactory.create(ERROR, "Cannot infer a type for this parameter. To specify it explicitly use the {(p : Type) => ...} notation"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java index 806cf734515..514e8d92968 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/ImportsResolver.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.resolve; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; +import com.google.common.collect.Maps; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.*; @@ -11,9 +12,7 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope; import org.jetbrains.jet.lang.resolve.scopes.WritableScope; import org.jetbrains.jet.lang.types.JetType; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; import static org.jetbrains.jet.lang.diagnostics.Errors.*; @@ -44,11 +43,71 @@ public class ImportsResolver { namespaceScope.clearImports(); } context.getConfiguration().addDefaultImports(context.getTrace(), namespaceScope); + Map resolvedDirectives = Maps.newHashMap(); List importDirectives = file.getImportDirectives(); for (JetImportDirective importDirective : importDirectives) { - importResolver.processImportReference(importDirective, namespaceScope); + Collection descriptors = importResolver.processImportReference(importDirective, namespaceScope); + if (descriptors != null && descriptors.size() == 1) { + resolvedDirectives.put(importDirective, descriptors.iterator().next()); + } } + + if (firstPhase) continue; + for (JetImportDirective importDirective : importDirectives) { + reportUselessImport(importDirective, namespaceScope, resolvedDirectives); + } + } + } + @Nullable + private static JetSimpleNameExpression getLastReference(@NotNull JetExpression importedReference) { + if (importedReference instanceof JetDotQualifiedExpression) { + JetDotQualifiedExpression reference = (JetDotQualifiedExpression) importedReference; + JetExpression selectorExpression = reference.getSelectorExpression(); + return (selectorExpression != null) ? (JetSimpleNameExpression) selectorExpression : null; + } + assert importedReference instanceof JetSimpleNameExpression; + return (JetSimpleNameExpression) importedReference; + } + + + @Nullable + private static String getAliasName(@NotNull JetImportDirective importDirective) { + String aliasName = importDirective.getAliasName(); + JetExpression importedReference = importDirective.getImportedReference(); + if (importedReference == null) return null; + JetSimpleNameExpression referenceExpression = getLastReference(importedReference); + if (aliasName == null) { + aliasName = referenceExpression != null ? referenceExpression.getReferencedName() : null; + } + return aliasName; + } + + private void reportUselessImport(@NotNull JetImportDirective importDirective, + @NotNull WritableScope namespaceScope, + @NotNull Map resolvedDirectives) { + + JetExpression importedReference = importDirective.getImportedReference(); + if (importedReference == null || !resolvedDirectives.containsKey(importDirective)) return; + String aliasName = getAliasName(importDirective); + if (aliasName == null) return; + + DeclarationDescriptor wasResolved = resolvedDirectives.get(importDirective); + DeclarationDescriptor isResolved = null; + if (wasResolved instanceof ClassDescriptor) { + isResolved = namespaceScope.getClassifier(aliasName); + } + else if (wasResolved instanceof VariableDescriptor) { + isResolved = namespaceScope.getLocalVariable(aliasName); + } + else if (wasResolved instanceof NamespaceDescriptor) { + isResolved = namespaceScope.getNamespace(aliasName); + } + if (isResolved != null && isResolved != wasResolved) { + context.getTrace().report(USELESS_HIDDEN_IMPORT.on(importedReference)); + } + if (!importDirective.isAllUnder() && importedReference instanceof JetSimpleNameExpression && importDirective.getAliasName() == null) { + context.getTrace().report(USELESS_SIMPLE_IMPORT.on(importedReference)); } } @@ -63,75 +122,78 @@ public class ImportsResolver { this.firstPhase = firstPhase; } - public void processImportReference(JetImportDirective importDirective, WritableScope namespaceScope) { + @Nullable + public Collection processImportReference(@NotNull JetImportDirective importDirective, @NotNull WritableScope namespaceScope) { if (importDirective.isAbsoluteInRootNamespace()) { trace.report(UNSUPPORTED.on(importDirective, "TypeHierarchyResolver")); // TODO - return; + return null; } JetExpression importedReference = importDirective.getImportedReference(); - if (importedReference == null) return; + if (importedReference == null) return null; Collection descriptors; if (importedReference instanceof JetQualifiedExpression) { - descriptors = lookupDescriptorsForQualifiedExpression((JetQualifiedExpression) importedReference, - namespaceScope, !importDirective.isAllUnder()); + descriptors = lookupDescriptorsForQualifiedExpression((JetQualifiedExpression) importedReference, namespaceScope); } else { assert importedReference instanceof JetSimpleNameExpression; - descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, - namespaceScope, true, !importDirective.isAllUnder()); + descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, namespaceScope, true); } JetSimpleNameExpression referenceExpression = getLastReference(importedReference); if (importDirective.isAllUnder()) { - if (referenceExpression == null || !canImportMembersFrom(descriptors, referenceExpression)) return; + if (referenceExpression == null || !canImportMembersFrom(descriptors, referenceExpression)) return null; for (DeclarationDescriptor descriptor : descriptors) { - if (firstPhase) { - if (descriptor instanceof NamespaceDescriptor) { - namespaceScope.importScope(((NamespaceDescriptor) descriptor).getMemberScope()); - } - if (descriptor instanceof ClassDescriptor) { - ClassDescriptor objectDescriptor; - if (((ClassDescriptor) descriptor).getKind() == ClassKind.OBJECT) { - objectDescriptor = (ClassDescriptor) descriptor; - } - else { - objectDescriptor = ((ClassDescriptor)descriptor).getClassObjectDescriptor(); - } - if (objectDescriptor != null) { - Collection innerClassesAndObjects = objectDescriptor.getInnerClassesAndObjects(); - for (DeclarationDescriptor innerClassOrObject : innerClassesAndObjects) { - namespaceScope.importClassifierAlias(innerClassOrObject.getName(), (ClassifierDescriptor) innerClassOrObject); - } - } - } - continue; - } - if (descriptor instanceof NamespaceDescriptor) { - namespaceScope.importScope(((NamespaceDescriptor) descriptor).getMemberScope()); - } - if (descriptor instanceof VariableDescriptor) { - JetType type = ((VariableDescriptor) descriptor).getOutType(); - namespaceScope.importScope(type.getMemberScope()); - } - else if (descriptor instanceof ClassDescriptor) { - JetType classObjectType = ((ClassDescriptor) descriptor).getClassObjectType(); - if (classObjectType != null) { - namespaceScope.importScope(classObjectType.getMemberScope()); + importAllUnderDeclaration(descriptor, namespaceScope); + } + return null; + } + + String aliasName = getAliasName(importDirective); + if (aliasName == null) return null; + + for (DeclarationDescriptor descriptor : descriptors) { + importDeclarationAlias(namespaceScope, aliasName, descriptor); + } + return descriptors; + } + + private void importAllUnderDeclaration(@NotNull DeclarationDescriptor descriptor, @NotNull WritableScope namespaceScope) { + if (firstPhase) { + if (descriptor instanceof NamespaceDescriptor) { + namespaceScope.importScope(((NamespaceDescriptor) descriptor).getMemberScope()); + } + if (descriptor instanceof ClassDescriptor) { + ClassDescriptor objectDescriptor = getObjectIfObjectOrClassObjectDescriptor((ClassDescriptor) descriptor); + if (objectDescriptor != null) { + Collection innerClassesAndObjects = objectDescriptor.getInnerClassesAndObjects(); + for (DeclarationDescriptor innerClassOrObject : innerClassesAndObjects) { + namespaceScope.importClassifierAlias(innerClassOrObject.getName(), (ClassifierDescriptor) innerClassOrObject); } } } return; } - - String aliasName = importDirective.getAliasName(); - if (aliasName == null) { - aliasName = referenceExpression != null ? referenceExpression.getReferencedName() : null; + if (descriptor instanceof NamespaceDescriptor) { + namespaceScope.importScope(((NamespaceDescriptor) descriptor).getMemberScope()); } - if (aliasName == null) return; - - for (DeclarationDescriptor descriptor : descriptors) { - importDeclarationAlias(namespaceScope, aliasName, descriptor); + if (descriptor instanceof VariableDescriptor) { + JetType type = ((VariableDescriptor) descriptor).getOutType(); + namespaceScope.importScope(type.getMemberScope()); } + else if (descriptor instanceof ClassDescriptor) { + JetType classObjectType = ((ClassDescriptor) descriptor).getClassObjectType(); + if (classObjectType != null) { + namespaceScope.importScope(classObjectType.getMemberScope()); + } + } + } + + @Nullable + private static ClassDescriptor getObjectIfObjectOrClassObjectDescriptor(ClassDescriptor descriptor) { + if ((descriptor).getKind() == ClassKind.OBJECT) { + return descriptor; + } + return descriptor.getClassObjectDescriptor(); } private static void importDeclarationAlias(WritableScope namespaceScope, String aliasName, DeclarationDescriptor descriptor) { @@ -149,29 +211,18 @@ public class ImportsResolver { } } - @Nullable - private static JetSimpleNameExpression getLastReference(JetExpression importedReference) { - if (importedReference instanceof JetDotQualifiedExpression) { - JetDotQualifiedExpression reference = (JetDotQualifiedExpression) importedReference; - JetExpression selectorExpression = reference.getSelectorExpression(); - return (selectorExpression != null) ? (JetSimpleNameExpression) selectorExpression : null; - } - assert importedReference instanceof JetSimpleNameExpression; - return (JetSimpleNameExpression) importedReference; - } - @NotNull private Collection lookupDescriptorsForQualifiedExpression( - @NotNull JetQualifiedExpression importedReference, @NotNull JetScope outerScope, boolean isForLastPart) { + @NotNull JetQualifiedExpression importedReference, @NotNull JetScope outerScope) { JetExpression receiverExpression = importedReference.getReceiverExpression(); Collection declarationDescriptors; if (receiverExpression instanceof JetQualifiedExpression) { - declarationDescriptors = lookupDescriptorsForQualifiedExpression((JetQualifiedExpression) receiverExpression, outerScope, false); + declarationDescriptors = lookupDescriptorsForQualifiedExpression((JetQualifiedExpression) receiverExpression, outerScope); } else { assert receiverExpression instanceof JetSimpleNameExpression; - declarationDescriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) receiverExpression, outerScope, true, false); + declarationDescriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) receiverExpression, outerScope, true); } JetExpression selectorExpression = importedReference.getSelectorExpression(); @@ -184,26 +235,18 @@ public class ImportsResolver { Collection result; for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) { if (declarationDescriptor instanceof NamespaceDescriptor) { - result = lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope(), true, isForLastPart); + result = lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope(), true); if (!result.isEmpty()) return result; } if (declarationDescriptor instanceof ClassDescriptor) { - if (firstPhase) { - result = lookupInnerClassesAndObjectsInObject(selector, (ClassDescriptor) declarationDescriptor); - } - else { - result = lookupObjectMembers(selector, (ClassDescriptor) declarationDescriptor); - } + result = lookupObjectMembers((ClassDescriptor) declarationDescriptor, selector); if (!result.isEmpty()) return result; } - if (!firstPhase) { - if (declarationDescriptor instanceof VariableDescriptor) { - result = lookupVariableMembers(selector, (VariableDescriptor) declarationDescriptor); - if (!result.isEmpty()) return result; - } + if (declarationDescriptor instanceof VariableDescriptor) { + result = lookupVariableMembers((VariableDescriptor) declarationDescriptor, selector); + if (!result.isEmpty()) return result; } } - return Collections.emptyList(); } @@ -247,80 +290,72 @@ public class ImportsResolver { } @NotNull - private Collection lookupInnerClassesAndObjectsInObject(@NotNull JetSimpleNameExpression objectReference, - @NotNull ClassDescriptor classDescriptor) { - assert firstPhase; - if (classDescriptor.getKind() == ClassKind.OBJECT) { - return getInnerClassesAndObjectsByName(classDescriptor, objectReference); + private Collection lookupObjectMembers(@NotNull ClassDescriptor classDescriptor, @NotNull JetSimpleNameExpression memberReference) { + if (firstPhase) { + ClassDescriptor objectDescriptor = getObjectIfObjectOrClassObjectDescriptor(classDescriptor); + if (objectDescriptor == null) return Collections.emptyList(); + return getInnerClassesAndObjectsByName(objectDescriptor, memberReference); } - MutableClassDescriptor classObjectDescriptor = ((MutableClassDescriptor) classDescriptor).getClassObjectDescriptor(); - assert classObjectDescriptor != null; - return getInnerClassesAndObjectsByName(classObjectDescriptor, objectReference); - } - - @NotNull - private Collection lookupObjectMembers(@NotNull JetSimpleNameExpression memberReference, - @NotNull ClassDescriptor classDescriptor) { - assert !firstPhase; //on second phase class descriptor is only a descriptor for class object JetType classObjectType = classDescriptor.getClassObjectType(); if (classObjectType == null) return Collections.emptyList(); - return lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope(), false, true); + return lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope(), false); } @NotNull private Collection getInnerClassesAndObjectsByName(@NotNull ClassDescriptor classDescriptor, @NotNull JetSimpleNameExpression memberReference) { - if (classDescriptor.getKind() != ClassKind.OBJECT) return Collections.emptyList(); + assert classDescriptor.getKind() == ClassKind.OBJECT; Collection descriptors; ClassDescriptor innerClass = classDescriptor.getInnerClassOrObject(memberReference.getReferencedName()); if (innerClass == null) return Collections.emptyList(); descriptors = Collections.singletonList(innerClass); - return filterResolutionResult(descriptors, memberReference, JetScope.EMPTY, false, true); + return filterResolutionResult(descriptors, memberReference, JetScope.EMPTY, false); } - private Collection lookupVariableMembers(@NotNull JetSimpleNameExpression memberReference, @NotNull VariableDescriptor variableDescriptor) { - assert !firstPhase; + private Collection lookupVariableMembers(@NotNull VariableDescriptor variableDescriptor, @NotNull JetSimpleNameExpression memberReference) { + if (firstPhase) return Collections.emptyList(); JetType variableType = variableDescriptor.getReturnType(); if (variableType == null) return Collections.emptyList(); - return lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope(), false, true); + return lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope(), false); } @NotNull private Collection lookupDescriptorsForSimpleNameReference( @NotNull JetSimpleNameExpression referenceExpression, @NotNull JetScope outerScope, - boolean namespaceLevel, - boolean isLastPart) { + boolean namespaceLevel) { + + String referencedName = referenceExpression.getReferencedName(); + if (referencedName == null) return Collections.emptyList(); List descriptors = Lists.newArrayList(); - String referencedName = referenceExpression.getReferencedName(); - if (referencedName != null) { - NamespaceDescriptor namespaceDescriptor = outerScope.getNamespace(referencedName); - if (namespaceDescriptor != null) descriptors.add(namespaceDescriptor); + NamespaceDescriptor namespaceDescriptor = outerScope.getNamespace(referencedName); + if (namespaceDescriptor != null) descriptors.add(namespaceDescriptor); - ClassifierDescriptor classifierDescriptor = outerScope.getClassifier(referencedName); - if (classifierDescriptor != null) descriptors.add(classifierDescriptor); + ClassifierDescriptor classifierDescriptor = outerScope.getClassifier(referencedName); + if (classifierDescriptor != null) descriptors.add(classifierDescriptor); - if (firstPhase) { - descriptors.add(outerScope.getObjectDescriptor(referencedName)); - } - else { - descriptors.addAll(outerScope.getFunctions(referencedName)); - - descriptors.addAll(outerScope.getProperties(referencedName)); - } + if (firstPhase) { + descriptors.add(outerScope.getObjectDescriptor(referencedName)); } + else { + descriptors.addAll(outerScope.getFunctions(referencedName)); - return filterResolutionResult(descriptors, referenceExpression, outerScope, namespaceLevel, isLastPart); + descriptors.addAll(outerScope.getProperties(referencedName)); + + VariableDescriptor localVariable = outerScope.getLocalVariable(referencedName); + if (localVariable != null) descriptors.add(localVariable); + } + return filterResolutionResult(descriptors, referenceExpression, outerScope, namespaceLevel); } private Collection filterResolutionResult( @NotNull Collection descriptors, @NotNull JetSimpleNameExpression referenceExpression, @NotNull JetScope resolutionScope, - boolean namespaceLevel, //functions and properties can be imported - boolean isLastPart) { + //functions and properties can be imported if namespaceLevel == true + boolean namespaceLevel) { if (firstPhase) { return Collections2.filter(descriptors, new Predicate() { @Override @@ -344,6 +379,16 @@ public class ImportsResolver { } }); } + storeResolutionResult(descriptors, filteredDescriptors, referenceExpression, resolutionScope); + return filteredDescriptors; + } + + private void storeResolutionResult( + @NotNull Collection descriptors, + @NotNull Collection filteredDescriptors, + @NotNull JetSimpleNameExpression referenceExpression, + @NotNull JetScope resolutionScope) { + if (descriptors.size() == 1 && filteredDescriptors.size() <= 1) { trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptors.iterator().next()); } @@ -363,7 +408,6 @@ public class ImportsResolver { if (descriptors.size() <= 1) { trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, resolutionScope); } - return filteredDescriptors; } } } diff --git a/compiler/testData/diagnostics/tests/scopes/Imports-hidden.jet b/compiler/testData/diagnostics/tests/scopes/Imports-hidden.jet new file mode 100644 index 00000000000..57b7483b3ff --- /dev/null +++ b/compiler/testData/diagnostics/tests/scopes/Imports-hidden.jet @@ -0,0 +1,45 @@ +//FILE:a.kt +package a + +import b.a +import c.a +import b + +import b.bar +import c.foo +import b.foo + +import A as ER +import B + +class A() {} +object B {} + +//FILE:b.kt +package b + +object a {} + +class B() { + class object { + object O {} + } +} + +fun foo() {} +fun bar() {} + +//FILE:c.kt +package c + +fun a() {} + +object a {} + +class C() { + class object { + object O {} + } +} + +fun foo() {} \ No newline at end of file