forbid import of functions and properties from objects

This commit is contained in:
svtk
2012-01-12 18:39:25 +04:00
parent 5cb15c6e48
commit 390eb0cde3
5 changed files with 76 additions and 64 deletions
@@ -84,6 +84,8 @@ public interface Errors {
SimpleDiagnosticFactory EXPRESSION_EXPECTED_NAMESPACE_FOUND = SimpleDiagnosticFactory.create(ERROR, "Expression expected, but a namespace name found"); SimpleDiagnosticFactory EXPRESSION_EXPECTED_NAMESPACE_FOUND = SimpleDiagnosticFactory.create(ERROR, "Expression expected, but a namespace name found");
ParameterizedDiagnosticFactory1<DeclarationDescriptor> CANNOT_IMPORT_FROM_ELEMENT = ParameterizedDiagnosticFactory1.create(ERROR, "Cannot import from ''{0}''", NAME); ParameterizedDiagnosticFactory1<DeclarationDescriptor> CANNOT_IMPORT_FROM_ELEMENT = ParameterizedDiagnosticFactory1.create(ERROR, "Cannot import from ''{0}''", NAME);
ParameterizedDiagnosticFactory1<DeclarationDescriptor> 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 CANNOT_INFER_PARAMETER_TYPE = SimpleDiagnosticFactory.create(ERROR, "Cannot infer a type for this parameter. To specify it explicitly use the {(p : Type) => ...} notation"); SimpleDiagnosticFactory CANNOT_INFER_PARAMETER_TYPE = SimpleDiagnosticFactory.create(ERROR, "Cannot infer a type for this parameter. To specify it explicitly use the {(p : Type) => ...} notation");
@@ -1,5 +1,7 @@
package org.jetbrains.jet.lang.resolve; 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.Lists;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -75,13 +77,8 @@ public class ImportsResolver {
} }
else { else {
assert importedReference instanceof JetSimpleNameExpression; assert importedReference instanceof JetSimpleNameExpression;
// for "import java.*" there's should be a correct resolving
// but for "import SomeClass" we want to get unresolved error, even if SomeClass descriptor exist in outer scope
JetScope resolveScope = importDirective.isAllUnder() ? namespaceScope : JetScope.EMPTY;
descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference, descriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) importedReference,
resolveScope, namespaceScope, !importDirective.isAllUnder()); namespaceScope, true, !importDirective.isAllUnder());
} }
JetSimpleNameExpression referenceExpression = getLastReference(importedReference); JetSimpleNameExpression referenceExpression = getLastReference(importedReference);
@@ -174,7 +171,7 @@ public class ImportsResolver {
} }
else { else {
assert receiverExpression instanceof JetSimpleNameExpression; assert receiverExpression instanceof JetSimpleNameExpression;
declarationDescriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) receiverExpression, outerScope, false); declarationDescriptors = lookupDescriptorsForSimpleNameReference((JetSimpleNameExpression) receiverExpression, outerScope, true, false);
} }
JetExpression selectorExpression = importedReference.getSelectorExpression(); JetExpression selectorExpression = importedReference.getSelectorExpression();
@@ -187,7 +184,7 @@ public class ImportsResolver {
Collection<? extends DeclarationDescriptor> result; Collection<? extends DeclarationDescriptor> result;
for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) { for (DeclarationDescriptor declarationDescriptor : declarationDescriptors) {
if (declarationDescriptor instanceof NamespaceDescriptor) { if (declarationDescriptor instanceof NamespaceDescriptor) {
result = lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope(), isForLastPart); result = lookupDescriptorsForSimpleNameReference(selector, ((NamespaceDescriptor) declarationDescriptor).getMemberScope(), true, isForLastPart);
if (!result.isEmpty()) return result; if (!result.isEmpty()) return result;
} }
if (declarationDescriptor instanceof ClassDescriptor) { if (declarationDescriptor instanceof ClassDescriptor) {
@@ -268,7 +265,7 @@ public class ImportsResolver {
//on second phase class descriptor is only a descriptor for class object //on second phase class descriptor is only a descriptor for class object
JetType classObjectType = classDescriptor.getClassObjectType(); JetType classObjectType = classDescriptor.getClassObjectType();
if (classObjectType == null) return Collections.emptyList(); if (classObjectType == null) return Collections.emptyList();
return lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope(), true); return lookupDescriptorsForSimpleNameReference(memberReference, classObjectType.getMemberScope(), false, true);
} }
@NotNull @NotNull
@@ -278,43 +275,22 @@ public class ImportsResolver {
ClassDescriptor innerClass = classDescriptor.getInnerClassOrObject(memberReference.getReferencedName()); ClassDescriptor innerClass = classDescriptor.getInnerClassOrObject(memberReference.getReferencedName());
if (innerClass == null) return Collections.emptyList(); if (innerClass == null) return Collections.emptyList();
descriptors = Collections.<DeclarationDescriptor>singletonList(innerClass); descriptors = Collections.<DeclarationDescriptor>singletonList(innerClass);
storeResolutionResult(descriptors, memberReference, JetScope.EMPTY, true); return filterResolutionResult(descriptors, memberReference, JetScope.EMPTY, false, true);
return descriptors;
} }
private Collection<DeclarationDescriptor> lookupVariableMembers(@NotNull JetSimpleNameExpression memberReference, @NotNull VariableDescriptor variableDescriptor) { private Collection<? extends DeclarationDescriptor> lookupVariableMembers(@NotNull JetSimpleNameExpression memberReference, @NotNull VariableDescriptor variableDescriptor) {
assert !firstPhase; assert !firstPhase;
JetType variableType = variableDescriptor.getReturnType(); JetType variableType = variableDescriptor.getReturnType();
if (variableType == null) return Collections.emptyList(); if (variableType == null) return Collections.emptyList();
return lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope(), true); return lookupDescriptorsForSimpleNameReference(memberReference, variableType.getMemberScope(), false, true);
} }
@NotNull @NotNull
private Collection<DeclarationDescriptor> lookupDescriptorsForSimpleNameReference( private Collection<? extends DeclarationDescriptor> lookupDescriptorsForSimpleNameReference(
@NotNull JetSimpleNameExpression referenceExpression, @NotNull JetSimpleNameExpression referenceExpression,
@NotNull JetScope outerScope, @NotNull JetScope outerScope,
boolean isLastPart) { boolean namespaceLevel,
return lookupDescriptorsForSimpleNameReference(referenceExpression, outerScope, outerScope, isLastPart);
}
/**
*
* @param referenceExpression
* @param outerScope
* @param bindingScope scope for searching completion descriptors. In most cases it's equal to outer scope
* but for case "import SomeIdentifier" we want an unresolved reference error, so give empty
* outer scope.
* @param isLastPart is the part given by referenceExpression last in import directive. Parameter should be false
* if there's .* after it or some other parts in full qualified name.
* @return
*/
@NotNull
private Collection<DeclarationDescriptor> lookupDescriptorsForSimpleNameReference(
@NotNull JetSimpleNameExpression referenceExpression,
@NotNull JetScope outerScope,
@NotNull JetScope bindingScope,
boolean isLastPart) { boolean isLastPart) {
List<DeclarationDescriptor> descriptors = Lists.newArrayList(); List<DeclarationDescriptor> descriptors = Lists.newArrayList();
@@ -336,32 +312,58 @@ public class ImportsResolver {
} }
} }
storeResolutionResult(descriptors, referenceExpression, bindingScope, isLastPart); return filterResolutionResult(descriptors, referenceExpression, outerScope, namespaceLevel, isLastPart);
return descriptors;
} }
private void storeResolutionResult( private Collection<? extends DeclarationDescriptor> filterResolutionResult(
@NotNull Collection<? extends DeclarationDescriptor> descriptors, @NotNull Collection<? extends DeclarationDescriptor> descriptors,
@NotNull JetSimpleNameExpression referenceExpression, @NotNull JetSimpleNameExpression referenceExpression,
@NotNull JetScope resolutionScope, @NotNull JetScope resolutionScope,
boolean namespaceLevel, //functions and properties can be imported
boolean isLastPart) { boolean isLastPart) {
if (firstPhase) return; if (firstPhase) {
return Collections2.filter(descriptors, new Predicate<DeclarationDescriptor>() {
if (descriptors.size() == 1 && !(isLastPart && descriptors.iterator().next() instanceof NamespaceDescriptor)) { @Override
trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptors.iterator().next()); public boolean apply(@Nullable DeclarationDescriptor descriptor) {
return (descriptor instanceof ClassDescriptor) ||
(descriptor instanceof NamespaceDescriptor);
}
});
} }
else if (descriptors.size() > 1) { Collection<? extends DeclarationDescriptor> filteredDescriptors;
trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, descriptors); if (namespaceLevel) {
filteredDescriptors = descriptors;
} }
else { else {
trace.report(UNRESOLVED_REFERENCE.on(referenceExpression)); filteredDescriptors = Collections2.filter(descriptors, new Predicate<DeclarationDescriptor>() {
@Override
public boolean apply(@Nullable DeclarationDescriptor descriptor) {
return (descriptor instanceof NamespaceDescriptor) ||
(descriptor instanceof ClassDescriptor) ||
(descriptor instanceof VariableDescriptor && ((VariableDescriptor) descriptor).isObjectDeclaration());
}
});
}
if (descriptors.size() == 1 && filteredDescriptors.size() <= 1) {
trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptors.iterator().next());
}
if (filteredDescriptors.isEmpty()) {
if (!descriptors.isEmpty()) {
trace.report(CANNOT_BE_IMPORTED.on(referenceExpression, descriptors.iterator().next()));
}
else {
trace.report(UNRESOLVED_REFERENCE.on(referenceExpression));
}
}
else if (filteredDescriptors.size() > 1) {
trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, descriptors);
} }
// If it's not an ambiguous case - store resolution scope // If it's not an ambiguous case - store resolution scope
if (descriptors.size() <= 1) { if (descriptors.size() <= 1) {
trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, resolutionScope); trace.record(BindingContext.RESOLUTION_SCOPE, referenceExpression, resolutionScope);
} }
return filteredDescriptors;
} }
} }
} }
@@ -5,29 +5,29 @@ import b.B //class
import b.foo //function import b.foo //function
import b.ext //extension function import b.ext //extension function
import b.value //property import b.value //property
import b.C.bar //function from class object import b.C.<!CANNOT_BE_IMPORTED!>bar<!> //function from class object
import b.C.cValue //property from class object import b.C.<!CANNOT_BE_IMPORTED!>cValue<!> //property from class object
import b.<!CANNOT_IMPORT_FROM_ELEMENT!>constant<!>.fff //function from val import b.<!CANNOT_IMPORT_FROM_ELEMENT!>constant<!>.fff //function from val
import b.<!CANNOT_IMPORT_FROM_ELEMENT!>constant<!>.dValue //property from val import b.<!CANNOT_IMPORT_FROM_ELEMENT!>constant<!>.dValue //property from val
import b.constant import b.constant
import b.E.f //val from class object import b.E.<!CANNOT_BE_IMPORTED!>f<!> //val from class object
import <!UNRESOLVED_REFERENCE!>smth<!>.illegal import <!UNRESOLVED_REFERENCE!>smth<!>.illegal
import b.C.<!UNRESOLVED_REFERENCE!>smth<!>.illegal import b.C.<!UNRESOLVED_REFERENCE!>smth<!>.illegal
import <!CANNOT_IMPORT_FROM_ELEMENT!>bar<!>.smth import b.<!CANNOT_IMPORT_FROM_ELEMENT!>bar<!>.smth
import <!CANNOT_IMPORT_FROM_ELEMENT!>bar<!>.* import b.<!CANNOT_IMPORT_FROM_ELEMENT!>bar<!>.*
fun test(arg: B) { fun test(arg: B) {
foo(value) foo(value)
arg.ext() arg.ext()
bar() <!UNRESOLVED_REFERENCE!>bar<!>()
foo(cValue) foo(<!UNRESOLVED_REFERENCE!>cValue<!>)
<!UNRESOLVED_REFERENCE!>fff<!>(<!UNRESOLVED_REFERENCE!>dValue<!>) <!UNRESOLVED_REFERENCE!>fff<!>(<!UNRESOLVED_REFERENCE!>dValue<!>)
constant.fff(constant.dValue) constant.fff(constant.dValue)
f.f() <!UNRESOLVED_REFERENCE!>f<!>.f()
} }
// FILE:b.kt // FILE:b.kt
@@ -80,4 +80,20 @@ object C {
fun foo() { fun foo() {
if (i == 3) f() if (i == 3) f()
}
//FILE:d.kt
package d
import A.B
import A.C
val b : B = B()
val c : B = C
class A() {
class object {
open class B() {}
object C : B() {}
}
} }
@@ -101,7 +101,7 @@ package d
import A.* import A.*
import M.R import M.R
import M.R.bar import M.R.<!CANNOT_BE_IMPORTED!>bar<!>
import M.T import M.T
import M.Y import M.Y
@@ -109,7 +109,7 @@ var r: T = T()
val y: T = Y val y: T = Y
fun f() { fun f() {
bar() <!UNRESOLVED_REFERENCE!>bar<!>()
R.bar() R.bar()
B.foo() B.foo()
} }
@@ -1,8 +0,0 @@
// KT-960 import namespace should give unresolved reference
package some
import java.<error>util</error>
class Test {
}