Improved error reporting, when we trying import invisible descriptor.

This commit is contained in:
Stanislav Erokhin
2015-09-21 17:35:42 +03:00
parent d7a14075f1
commit 85895bec62
4 changed files with 129 additions and 35 deletions
@@ -43,7 +43,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
) { ) {
val packageNames = packageDirective.packageNames val packageNames = packageDirective.packageNames
for ((index, nameExpression) in packageNames.withIndex()) { for ((index, nameExpression) in packageNames.withIndex()) {
storageResult(trace, nameExpression, listOf(module.getPackage(packageDirective.getFqName(nameExpression))), storageResult(trace, nameExpression, module.getPackage(packageDirective.getFqName(nameExpression)),
shouldBeVisibleFrom = null, inImport = false, isQualifier = index != packageNames.lastIndex) shouldBeVisibleFrom = null, inImport = false, isQualifier = index != packageNames.lastIndex)
} }
} }
@@ -56,7 +56,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
if (userType.qualifier == null && !userType.startWithPackage) { // optimization for non-qualified types if (userType.qualifier == null && !userType.startWithPackage) { // optimization for non-qualified types
return userType.referenceExpression?.let { return userType.referenceExpression?.let {
val classifier = scope.getClassifier(it.getReferencedNameAsName(), KotlinLookupLocation(it)) val classifier = scope.getClassifier(it.getReferencedNameAsName(), KotlinLookupLocation(it))
storageResult(trace, it, listOfNotNull(classifier), scope.ownerDescriptor, inImport = false, isQualifier = false) storageResult(trace, it, classifier, scope.ownerDescriptor, inImport = false, isQualifier = false)
classifier classifier
} }
} }
@@ -82,7 +82,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
is ClassDescriptor -> qualifier.unsubstitutedInnerClassesScope.getClassifier(lastPart.name, lastPart.location) is ClassDescriptor -> qualifier.unsubstitutedInnerClassesScope.getClassifier(lastPart.name, lastPart.location)
else -> null else -> null
} }
storageResult(trace, lastPart.expression, listOfNotNull(classifier), scope.ownerDescriptor, inImport = false, isQualifier = false) storageResult(trace, lastPart.expression, classifier, scope.ownerDescriptor, inImport = false, isQualifier = false)
return classifier return classifier
} }
@@ -173,7 +173,10 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
tryResolveDescriptorsWhichCannotBeImported(trace, moduleDescriptor, packageOrClassDescriptor, lastPart) tryResolveDescriptorsWhichCannotBeImported(trace, moduleDescriptor, packageOrClassDescriptor, lastPart)
} }
return SingleImportScope(aliasName, descriptors) val importedDescriptors = descriptors.filter { isVisible(it, packageFragmentForVisibilityCheck, inImport = true) }.
check { it.isNotEmpty() } ?: descriptors
return SingleImportScope(aliasName, importedDescriptors)
} }
} }
@@ -260,7 +263,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
val firstDescriptor = scopeForFirstPart?.let { val firstDescriptor = scopeForFirstPart?.let {
val firstPart = path.first() val firstPart = path.first()
it.getClassifier(firstPart.name, firstPart.location)?.apply { it.getClassifier(firstPart.name, firstPart.location)?.apply {
storageResult(trace, firstPart.expression, listOf(this), shouldBeVisibleFrom, inImport) storageResult(trace, firstPart.expression, this, shouldBeVisibleFrom, inImport)
} }
} }
@@ -290,7 +293,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
} }
else -> null else -> null
} }
storageResult(trace, qualifierPart.expression, listOfNotNull(nextDescriptor), shouldBeVisibleFrom, inImport) storageResult(trace, qualifierPart.expression, nextDescriptor, shouldBeVisibleFrom, inImport)
nextDescriptor nextDescriptor
} }
} }
@@ -324,7 +327,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
inImport: Boolean inImport: Boolean
) { ) {
path.foldRight(packageView) { qualifierPart, currentView -> path.foldRight(packageView) { qualifierPart, currentView ->
storageResult(trace, qualifierPart.expression, listOfNotNull(currentView), shouldBeVisibleFrom = null, inImport = inImport) storageResult(trace, qualifierPart.expression, currentView, shouldBeVisibleFrom = null, inImport = inImport)
val parentView = currentView.containingDeclaration val parentView = currentView.containingDeclaration
assert(parentView != null) { assert(parentView != null) {
"Containing Declaration must be not null for package with fqName: ${currentView.fqName}, " + "Containing Declaration must be not null for package with fqName: ${currentView.fqName}, " +
@@ -342,25 +345,49 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
inImport: Boolean, inImport: Boolean,
isQualifier: Boolean = true isQualifier: Boolean = true
) { ) {
if (descriptors.isEmpty()) { if (descriptors.size() > 1) {
trace.report(Errors.UNRESOLVED_REFERENCE.on(referenceExpression, referenceExpression)) val visibleDescriptors = descriptors.filter { isVisible(it, shouldBeVisibleFrom, inImport) }
} if (visibleDescriptors.isEmpty()) {
else if(descriptors.size() > 1) { val descriptor = descriptors.first() as DeclarationDescriptorWithVisibility
// todo all descriptors invisible - report specific error trace.report(Errors.INVISIBLE_REFERENCE.on(referenceExpression, descriptor, descriptor.visibility, descriptor.containingDeclaration!!))
trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, descriptors) }
else if (visibleDescriptors.size() > 1) {
trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, visibleDescriptors)
}
else {
storageResult(trace, referenceExpression, visibleDescriptors.single(), null, inImport, isQualifier)
}
} }
else { else {
val descriptor = descriptors.single() storageResult(trace, referenceExpression, descriptors.singleOrNull(), shouldBeVisibleFrom, inImport, isQualifier)
trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptor) }
if (descriptor is ClassifierDescriptor) { }
symbolUsageValidator.validateTypeUsage(descriptor, trace, referenceExpression)
} private fun storageResult(
if (descriptor is DeclarationDescriptorWithVisibility && shouldBeVisibleFrom != null) { trace: BindingTrace,
checkVisibility(descriptor, trace, referenceExpression, shouldBeVisibleFrom, inImport) referenceExpression: JetSimpleNameExpression,
} descriptor: DeclarationDescriptor?,
if (isQualifier) { shouldBeVisibleFrom: DeclarationDescriptor?,
storageQualifier(trace, referenceExpression, descriptor) inImport: Boolean,
} isQualifier: Boolean = true
) {
if (descriptor == null) {
trace.report(Errors.UNRESOLVED_REFERENCE.on(referenceExpression, referenceExpression))
return
}
trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, descriptor)
if (descriptor is ClassifierDescriptor) {
symbolUsageValidator.validateTypeUsage(descriptor, trace, referenceExpression)
}
if (descriptor is DeclarationDescriptorWithVisibility && !isVisible(descriptor, shouldBeVisibleFrom, inImport)) {
trace.report(Errors.INVISIBLE_REFERENCE.on(referenceExpression, descriptor, descriptor.visibility, descriptor.containingDeclaration!!))
}
if (isQualifier) {
storageQualifier(trace, referenceExpression, descriptor)
} }
} }
@@ -371,19 +398,18 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa
} }
} }
private fun checkVisibility( private fun isVisible(
descriptor: DeclarationDescriptorWithVisibility, descriptor: DeclarationDescriptor,
trace: BindingTrace, shouldBeVisibleFrom: DeclarationDescriptor?,
referenceExpression: JetSimpleNameExpression,
shouldBeVisibleFrom: DeclarationDescriptor,
inImport: Boolean inImport: Boolean
) { ): Boolean {
if (descriptor !is DeclarationDescriptorWithVisibility || shouldBeVisibleFrom == null) return true
val visibility = descriptor.visibility val visibility = descriptor.visibility
if (inImport && !visibility.mustCheckInImports()) { if (inImport) {
return if (Visibilities.isPrivate(visibility)) return false
} if (!visibility.mustCheckInImports()) return true
if (!Visibilities.isVisible(ReceiverValue.IRRELEVANT_RECEIVER, descriptor, shouldBeVisibleFrom)) {
trace.report(Errors.INVISIBLE_REFERENCE.on(referenceExpression, descriptor, visibility, descriptor.containingDeclaration!!))
} }
return Visibilities.isVisible(ReceiverValue.IRRELEVANT_RECEIVER, descriptor, shouldBeVisibleFrom)
} }
} }
@@ -0,0 +1,44 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
// FILE: 1.kt
package k
private fun zero() {}
private fun zero(a: Int) {}
private fun zero(a: String) {}
fun one() {}
private fun one(a: Int) {}
private fun one(a: String) {}
fun two() {}
fun two(a: Int) {}
private fun two(a: String) {}
fun all() {}
fun all(a: Int) {}
fun all(a: String) {}
// FILE: 2.kt
import k.<!INVISIBLE_REFERENCE, DEBUG_INFO_MISSING_UNRESOLVED!>zero<!>
import k.one
import k.two
import k.all
fun test() {
<!INVISIBLE_MEMBER!>zero<!>()
<!NONE_APPLICABLE!>zero<!>(1)
<!NONE_APPLICABLE!>zero<!>("")
one()
one(<!TOO_MANY_ARGUMENTS!>1<!>)
one(<!TOO_MANY_ARGUMENTS!>""<!>)
two()
two(1)
two(<!TYPE_MISMATCH!>""<!>)
all()
all(1)
all("")
}
@@ -0,0 +1,18 @@
package
public fun test(): kotlin.Unit
package k {
public fun all(): kotlin.Unit
public fun all(/*0*/ a: kotlin.Int): kotlin.Unit
public fun all(/*0*/ a: kotlin.String): kotlin.Unit
public fun one(): kotlin.Unit
private fun one(/*0*/ a: kotlin.Int): kotlin.Unit
private fun one(/*0*/ a: kotlin.String): kotlin.Unit
public fun two(): kotlin.Unit
public fun two(/*0*/ a: kotlin.Int): kotlin.Unit
private fun two(/*0*/ a: kotlin.String): kotlin.Unit
private fun zero(): kotlin.Unit
private fun zero(/*0*/ a: kotlin.Int): kotlin.Unit
private fun zero(/*0*/ a: kotlin.String): kotlin.Unit
}
@@ -6651,6 +6651,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName); doTest(fileName);
} }
@TestMetadata("ImportOverloadFunctions.kt")
public void testImportOverloadFunctions() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/ImportOverloadFunctions.kt");
doTest(fileName);
}
@TestMetadata("ImportProtectedClass.kt") @TestMetadata("ImportProtectedClass.kt")
public void testImportProtectedClass() throws Exception { public void testImportProtectedClass() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/ImportProtectedClass.kt"); String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/imports/ImportProtectedClass.kt");