From b532fa2bbf85b977757d1fae2e99d9b71cb6ae1e Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Tue, 10 Nov 2015 14:37:51 +0300 Subject: [PATCH] Properly resolve values in 1st qualifier part (see implicitReceiverProperty test). Look into QUALIFIER for left-most "unrolled" qualified expression in CallExpressionResolver#getQualifiedExpressionTypeInfo. Drop some unused functions. --- .../resolve/QualifiedExpressionResolver.kt | 122 +++++++----------- .../resolve/calls/CallExpressionResolver.java | 52 ++++++-- .../resolve/calls/CallExpressionUnroller.kt | 20 ++- .../resolve/scopes/receivers/Qualifier.kt | 7 +- .../kotlin/resolve/scopes/utils/ScopeUtils.kt | 11 -- .../types/expressions/KotlinTypeInfo.kt | 2 +- .../deprecated/classWithCompanionObject.kt | 8 ++ .../deprecated/classWithCompanionObject.txt | 24 ++++ .../tests/resolve/implicitReceiverProperty.kt | 33 +++++ .../resolve/implicitReceiverProperty.txt | 34 +++++ .../checkers/DiagnosticsTestGenerated.java | 12 ++ .../lookupTracker/classifierMembers/foo.kt | 8 +- .../lookupTracker/classifierMembers/usages.kt | 8 +- 13 files changed, 228 insertions(+), 113 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/deprecated/classWithCompanionObject.kt create mode 100644 compiler/testData/diagnostics/tests/deprecated/classWithCompanionObject.txt create mode 100644 compiler/testData/diagnostics/tests/resolve/implicitReceiverProperty.kt create mode 100644 compiler/testData/diagnostics/tests/resolve/implicitReceiverProperty.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt index af8d174c527..29483eab7a7 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/QualifiedExpressionResolver.kt @@ -20,26 +20,24 @@ import com.intellij.util.SmartList import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.incremental.KotlinLookupLocation -import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.calls.CallExpressionElement +import org.jetbrains.kotlin.resolve.calls.unrollToLeftMostQualifiedExpression import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.scopes.ImportingScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope -import org.jetbrains.kotlin.resolve.scopes.receivers.ClassQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.PackageQualifier import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue import org.jetbrains.kotlin.resolve.scopes.receivers.createClassifierQualifier -import org.jetbrains.kotlin.resolve.scopes.utils.containsFunctionOrVariable import org.jetbrains.kotlin.resolve.scopes.utils.findClassifier import org.jetbrains.kotlin.resolve.source.KotlinSourceElement import org.jetbrains.kotlin.resolve.validation.SymbolUsageValidator import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext +import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.check -import java.util.* public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageValidator) { @@ -52,7 +50,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa val packageNames = packageDirective.packageNames for ((index, nameExpression) in packageNames.withIndex()) { storeResult(trace, nameExpression, module.getPackage(packageDirective.getFqName(nameExpression)), - shouldBeVisibleFrom = null, inImport = false, isQualifier = index != packageNames.lastIndex) + shouldBeVisibleFrom = null, position = QualifierPosition.PACKAGE_HEADER, isQualifier = index != packageNames.lastIndex) } } @@ -72,7 +70,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa if (userType.qualifier == null && !userType.startWithPackage) { // optimization for non-qualified types val descriptor = userType.referenceExpression?.let { val classifier = scope.findClassifier(it.getReferencedNameAsName(), KotlinLookupLocation(it)) - storeResult(trace, it, classifier, scope.ownerDescriptor, inImport = false, isQualifier = false) + storeResult(trace, it, classifier, scope.ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false) classifier } @@ -102,8 +100,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa is ClassDescriptor -> qualifier.unsubstitutedInnerClassesScope.getContributedClassifier(lastPart.name, lastPart.location) else -> null } - storeResult(trace, lastPart.expression, classifier, scope.ownerDescriptor, inImport = false, isQualifier = false) - + storeResult(trace, lastPart.expression, classifier, scope.ownerDescriptor, position = QualifierPosition.TYPE, isQualifier = false) return TypeQualifierResolutionResult(qualifierPartList, classifier) } @@ -181,14 +178,14 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa val candidates = collectCandidateDescriptors(lastPart, packageOrClassDescriptor) if (candidates.isNotEmpty()) { - storeResult(trace, lastPart.expression, candidates, packageFragmentForVisibilityCheck, inImport = true, isQualifier = false) + storeResult(trace, lastPart.expression, candidates, packageFragmentForVisibilityCheck, position = QualifierPosition.IMPORT, isQualifier = false) } else { tryResolveDescriptorsWhichCannotBeImported(trace, moduleDescriptor, packageOrClassDescriptor, lastPart) return null } - val importedDescriptors = candidates.filter { isVisible(it, packageFragmentForVisibilityCheck, inImport = true) }. + val importedDescriptors = candidates.filter { isVisible(it, packageFragmentForVisibilityCheck, position = QualifierPosition.IMPORT) }. check { it.isNotEmpty() } ?: candidates return SingleImportScope(aliasName, importedDescriptors) @@ -258,7 +255,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa else -> throw IllegalStateException("Should be class or package: $packageOrClassDescriptor") } - storeResult(trace, lastPart.expression, descriptors, shouldBeVisibleFrom = null, inImport = true, isQualifier = false) + storeResult(trace, lastPart.expression, descriptors, shouldBeVisibleFrom = null, position = QualifierPosition.IMPORT, isQualifier = false) } private fun KtExpression.asQualifierPartList(trace: BindingTrace): List { @@ -296,7 +293,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa } private enum class QualifierPosition { - IMPORT, TYPE, EXPRESSION + PACKAGE_HEADER, IMPORT, TYPE, EXPRESSION } private fun resolveToPackageOrClass( @@ -323,21 +320,20 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa trace: BindingTrace, shouldBeVisibleFrom: DeclarationDescriptor?, scopeForFirstPart: LexicalScope?, - position: QualifierPosition + position: QualifierPosition, + isValue: ((KtSimpleNameExpression) -> Boolean)? = null ): Pair { if (path.isEmpty()) { return Pair(moduleDescriptor.getPackage(FqName.ROOT), 0) } - val inImport = position == QualifierPosition.IMPORT - val firstPart = path.first() if (position == QualifierPosition.EXPRESSION) { // In expression position, value wins against classifier (and package). // If we see a function or variable (possibly ambiguous), // tell resolver we have no qualifier and let it perform the context-dependent resolution. - if (scopeForFirstPart != null && scopeForFirstPart.containsFunctionOrVariable(firstPart.name, firstPart.location)) { + if (scopeForFirstPart != null && isValue != null && isValue(firstPart.expression)) { return Pair(null, 0) } } @@ -347,14 +343,14 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa } if (classifierDescriptor != null) { - storeResult(trace, firstPart.expression, classifierDescriptor, shouldBeVisibleFrom, inImport) + storeResult(trace, firstPart.expression, classifierDescriptor, shouldBeVisibleFrom, position) } val (prefixDescriptor, nextIndexAfterPrefix) = if (classifierDescriptor != null) Pair(classifierDescriptor, 1) else - moduleDescriptor.quickResolveToPackage(path, trace, inImport) + moduleDescriptor.quickResolveToPackage(path, trace, position) var currentDescriptor: DeclarationDescriptor? = prefixDescriptor for (qualifierPartIndex in nextIndexAfterPrefix .. path.size - 1) { @@ -383,7 +379,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa // If we are in expression, this name can denote a value (not a package or class). if (!(position == QualifierPosition.EXPRESSION && nextPackageOrClassDescriptor == null)) { - storeResult(trace, qualifierPart.expression, nextPackageOrClassDescriptor, shouldBeVisibleFrom, inImport) + storeResult(trace, qualifierPart.expression, nextPackageOrClassDescriptor, shouldBeVisibleFrom, position) } if (nextPackageOrClassDescriptor == null) { @@ -399,69 +395,51 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa public fun resolveQualifierInExpressionAndUnroll( expression: KtQualifiedExpression, - context: ExpressionTypingContext + context: ExpressionTypingContext, + isValue: (KtSimpleNameExpression) -> Boolean ): List { val qualifiedExpressions = unrollToLeftMostQualifiedExpression(expression) val maxPossibleQualifierPrefix = getMaxPossibleQualifierPrefix(qualifiedExpressions) - val (packageOrClassDescriptor, nextIndexAfterPrefix) = resolveToPackageOrClassPrefix( + val nextIndexAfterPrefix = resolveToPackageOrClassPrefix( path = maxPossibleQualifierPrefix, moduleDescriptor = context.scope.ownerDescriptor.module, trace = context.trace, shouldBeVisibleFrom = context.scope.ownerDescriptor, scopeForFirstPart = context.scope, - position = QualifierPosition.EXPRESSION - ) + position = QualifierPosition.EXPRESSION, + isValue = isValue + ).second - if (nextIndexAfterPrefix > 0) { - val qualifierReferenceExpression = maxPossibleQualifierPrefix[nextIndexAfterPrefix - 1].expression - val qualifier = - when (packageOrClassDescriptor) { - is PackageViewDescriptor -> - PackageQualifier(qualifierReferenceExpression, packageOrClassDescriptor) - is ClassDescriptor -> - ClassQualifier(qualifierReferenceExpression, packageOrClassDescriptor) - else -> - null - } - if (qualifier != null) { - context.trace.record(BindingContext.QUALIFIER, qualifier.expression, qualifier) - } - } + val firstExpressionAfterQualifierIndex = + if (nextIndexAfterPrefix == 0) 0 else nextIndexAfterPrefix - 1 - return qualifiedExpressions.map { CallExpressionElement(it) } - } - - private fun unrollToLeftMostQualifiedExpression(expression: KtQualifiedExpression): List { - val unrolled = arrayListOf() - - var finger = expression - while (true) { - unrolled.add(finger) - val receiver = finger.receiverExpression - if (receiver !is KtQualifiedExpression) { - break - } - finger = receiver - } - - Collections.reverse(unrolled) - return unrolled + return qualifiedExpressions + .subList(firstExpressionAfterQualifierIndex, qualifiedExpressions.size) + .map { CallExpressionElement(it) } } private fun getMaxPossibleQualifierPrefix(qualifiedExpressions: List) : List { if (qualifiedExpressions.isEmpty()) return emptyList() val first = qualifiedExpressions.first() - if (first.operationSign != KtTokens.DOT) return emptyList() + if (first !is KtDotQualifiedExpression) return emptyList() val firstReceiver = first.receiverExpression if (firstReceiver !is KtSimpleNameExpression) return emptyList() + // Qualifier parts are receiver name for the leftmost expression + // and selector names for all but the rightmost qualified expressions + // (since rightmost selector should denote a value in expression position, + // and thus can't be a qualifier part). + // E.g.: + // qualified expression 'a.b': qualifier parts == ['a'] + // qualified expression 'a.b.c.d': qualifier parts == ['a', 'b', 'c'] + val qualifierParts = arrayListOf() qualifierParts.add(QualifierPart(firstReceiver)) for (qualifiedExpression in qualifiedExpressions.dropLast(1)) { - if (qualifiedExpression.operationSign != KtTokens.DOT) break + if (qualifiedExpression !is KtDotQualifiedExpression) break val selector = qualifiedExpression.selectorExpression if (selector !is KtSimpleNameExpression) break qualifierParts.add(QualifierPart(selector)) @@ -473,7 +451,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa private fun ModuleDescriptor.quickResolveToPackage( path: List, trace: BindingTrace, - inImport: Boolean + position: QualifierPosition ): Pair { val possiblePackagePrefixSize = path.indexOfFirst { it.typeArguments != null }.let { if (it == -1) path.size() else it + 1 } var fqName = path.subList(0, possiblePackagePrefixSize).fold(FqName.ROOT) { fqName, qualifierPart -> @@ -483,7 +461,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa while (!fqName.isRoot) { val packageDescriptor = getPackage(fqName) if (!packageDescriptor.isEmpty()) { - recordPackageViews(path.subList(0, prefixSize), packageDescriptor, trace, inImport) + recordPackageViews(path.subList(0, prefixSize), packageDescriptor, trace, position) return Pair(packageDescriptor, prefixSize) } fqName = fqName.parent() @@ -496,10 +474,10 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa path: List, packageView: PackageViewDescriptor, trace: BindingTrace, - inImport: Boolean + position: QualifierPosition ) { path.foldRight(packageView) { qualifierPart, currentView -> - storeResult(trace, qualifierPart.expression, currentView, shouldBeVisibleFrom = null, inImport = inImport) + storeResult(trace, qualifierPart.expression, currentView, shouldBeVisibleFrom = null, position = position) val parentView = currentView.containingDeclaration assert(parentView != null) { "Containing Declaration must be not null for package with fqName: ${currentView.fqName}, " + @@ -514,11 +492,11 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa referenceExpression: KtSimpleNameExpression, descriptors: Collection, shouldBeVisibleFrom: DeclarationDescriptor?, - inImport: Boolean, + position: QualifierPosition, isQualifier: Boolean = true ) { if (descriptors.size() > 1) { - val visibleDescriptors = descriptors.filter { isVisible(it, shouldBeVisibleFrom, inImport) } + val visibleDescriptors = descriptors.filter { isVisible(it, shouldBeVisibleFrom, position) } if (visibleDescriptors.isEmpty()) { val descriptor = descriptors.first() as DeclarationDescriptorWithVisibility trace.report(Errors.INVISIBLE_REFERENCE.on(referenceExpression, descriptor, descriptor.visibility, descriptor)) @@ -527,11 +505,11 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa trace.record(BindingContext.AMBIGUOUS_REFERENCE_TARGET, referenceExpression, visibleDescriptors) } else { - storeResult(trace, referenceExpression, visibleDescriptors.single(), null, inImport, isQualifier) + storeResult(trace, referenceExpression, visibleDescriptors.single(), null, position, isQualifier) } } else { - storeResult(trace, referenceExpression, descriptors.singleOrNull(), shouldBeVisibleFrom, inImport, isQualifier) + storeResult(trace, referenceExpression, descriptors.singleOrNull(), shouldBeVisibleFrom, position, isQualifier) } } @@ -540,7 +518,7 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa referenceExpression: KtSimpleNameExpression, descriptor: DeclarationDescriptor?, shouldBeVisibleFrom: DeclarationDescriptor?, - inImport: Boolean, + position: QualifierPosition, isQualifier: Boolean = true ) { if (descriptor == null) { @@ -562,17 +540,17 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa else { shouldBeVisibleFrom } - if (!isVisible(descriptor, fromToCheck, inImport)) { + if (!isVisible(descriptor, fromToCheck, position)) { trace.report(Errors.INVISIBLE_REFERENCE.on(referenceExpression, descriptor, descriptor.visibility, descriptor)) } } if (isQualifier) { - storageQualifier(trace, referenceExpression, descriptor) + storeQualifier(trace, referenceExpression, descriptor) } } - private fun storageQualifier(trace: BindingTrace, referenceExpression: KtSimpleNameExpression, descriptor: DeclarationDescriptor) { + private fun storeQualifier(trace: BindingTrace, referenceExpression: KtSimpleNameExpression, descriptor: DeclarationDescriptor) { val qualifier = when (descriptor) { is PackageViewDescriptor -> PackageQualifier(referenceExpression, descriptor) @@ -586,12 +564,12 @@ public class QualifiedExpressionResolver(val symbolUsageValidator: SymbolUsageVa private fun isVisible( descriptor: DeclarationDescriptor, shouldBeVisibleFrom: DeclarationDescriptor?, - inImport: Boolean + position: QualifierPosition ): Boolean { if (descriptor !is DeclarationDescriptorWithVisibility || shouldBeVisibleFrom == null) return true val visibility = descriptor.visibility - if (inImport) { + if (position == QualifierPosition.IMPORT) { if (Visibilities.isPrivate(visibility)) return false if (!visibility.mustCheckInImports()) return true } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java index 8bbe95da69c..13a7f425305 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionResolver.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve.calls; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; +import kotlin.jvm.functions.Function1; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.builtins.KotlinBuiltIns; @@ -329,17 +330,51 @@ public class CallExpressionResolver { */ @NotNull public KotlinTypeInfo getQualifiedExpressionTypeInfo( - @NotNull KtQualifiedExpression expression, @NotNull ExpressionTypingContext context + @NotNull KtQualifiedExpression expression, @NotNull final ExpressionTypingContext context ) { ExpressionTypingContext currentContext = context.replaceExpectedType(NO_EXPECTED_TYPE).replaceContextDependency(INDEPENDENT); + Function1 isValueFunction = new Function1() { + @Override + public Boolean invoke(KtSimpleNameExpression nameExpression) { + TemporaryTraceAndCache temporaryForVariable = TemporaryTraceAndCache.create( + context, "trace to resolve as local variable or property", nameExpression); + Call call = CallMaker.makePropertyCall(ReceiverValue.NO_RECEIVER, null, nameExpression); + BasicCallResolutionContext contextForVariable = BasicCallResolutionContext.create( + context.replaceTraceAndCache(temporaryForVariable), + call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS); + OverloadResolutionResults resolutionResult = callResolver.resolveSimpleProperty(contextForVariable); + + if (resolutionResult.isSingleResult() && + resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject) { + return false; + } + + return !resolutionResult.isNothing(); + } + }; List elementChain = - qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(expression, context); + qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(expression, context, isValueFunction); + + KotlinTypeInfo receiverTypeInfo; + KotlinType receiverType; + DataFlowInfo receiverDataFlowInfo; CallExpressionElement firstElement = elementChain.iterator().next(); - KotlinTypeInfo receiverTypeInfo = expressionTypingServices.getTypeInfo(firstElement.getReceiver(), currentContext); - KotlinType receiverType = receiverTypeInfo.getType(); - DataFlowInfo receiverDataFlowInfo = receiverTypeInfo.getDataFlowInfo(); + KtExpression firstReceiver = firstElement.getReceiver(); + Qualifier firstQualifier = context.trace.get(BindingContext.QUALIFIER, firstReceiver); + if (firstQualifier == null) { + receiverTypeInfo = expressionTypingServices.getTypeInfo(firstReceiver, currentContext); + receiverType = receiverTypeInfo.getType(); + receiverDataFlowInfo = receiverTypeInfo.getDataFlowInfo(); + } + else { + receiverType = null; + receiverDataFlowInfo = currentContext.dataFlowInfo; + //noinspection ConstantConditions + receiverTypeInfo = new KotlinTypeInfo(receiverType, receiverDataFlowInfo); + } + KotlinTypeInfo resultTypeInfo = receiverTypeInfo; boolean unconditional = true; @@ -366,7 +401,9 @@ public class CallExpressionResolver { getSelectorReturnTypeInfo(receiver, element.getNode(), selectorExpression, currentContext); KotlinType selectorReturnType = selectorReturnTypeInfo.getType(); - resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, element.getQualified(), currentContext); + if (qualifierReceiver != null) { + resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, element.getQualified(), currentContext); + } checkNestedClassAccess(element.getQualified(), currentContext); boolean safeCall = element.getSafe(); @@ -415,11 +452,10 @@ public class CallExpressionResolver { } private void resolveDeferredReceiverInQualifiedExpression( - @Nullable QualifierReceiver qualifierReceiver, + @NotNull QualifierReceiver qualifierReceiver, @NotNull KtQualifiedExpression qualifiedExpression, @NotNull ExpressionTypingContext context ) { - if (qualifierReceiver == null) return; KtExpression calleeExpression = KtPsiUtil.deparenthesize(CallUtilKt.getCalleeExpressionIfAny(qualifiedExpression.getSelectorExpression())); DeclarationDescriptor selectorDescriptor = diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionUnroller.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionUnroller.kt index 9d2059677a7..962b8a580fb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionUnroller.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallExpressionUnroller.kt @@ -22,14 +22,20 @@ import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtQualifiedExpression import java.util.* -internal fun unroll(root: KtQualifiedExpression): Deque { - var current: KtExpression = root - val result = linkedListOf() - while (current is KtQualifiedExpression) { - result.addFirst(CallExpressionElement(current)) - current = result.first.receiver +public fun unrollToLeftMostQualifiedExpression(expression: KtQualifiedExpression): List { + val unrolled = arrayListOf() + + var finger = expression + while (true) { + unrolled.add(finger) + val receiver = finger.receiverExpression + if (receiver !is KtQualifiedExpression) { + break + } + finger = receiver } - return result + + return unrolled.asReversed() } public data class CallExpressionElement internal constructor (val qualified: KtQualifiedExpression) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt index 4f3c5f7d531..b89acfd75c3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/receivers/Qualifier.kt @@ -38,7 +38,6 @@ import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext import org.jetbrains.kotlin.utils.addIfNotNull import java.util.* -import kotlin.properties.Delegates public interface Qualifier: Receiver { @@ -150,11 +149,7 @@ class ClassQualifier( override fun toString() = "Class{$classifier}" } -fun createQualifier( - expression: KtSimpleNameExpression, - receiver: Receiver, - context: ExpressionTypingContext -): QualifierReceiver? { +fun createQualifier(expression: KtSimpleNameExpression, receiver: Receiver, context: ExpressionTypingContext): QualifierReceiver? { val receiverScope = when { !receiver.exists() -> context.scope receiver is QualifierReceiver -> receiver.scope.memberScopeAsImportingScope() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt index 96a1f6ac9dc..565f2c71cfb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/scopes/utils/ScopeUtils.kt @@ -98,17 +98,6 @@ public fun HierarchicalScope.findFunction(name: Name, location: LookupLocation, return null } -public fun HierarchicalScope.containsFunctionOrVariable(name: Name, location: LookupLocation): Boolean { - processForMeAndParent { - if (it.getContributedFunctions(name, location).isNotEmpty() || - it.getContributedVariables(name, location).isNotEmpty() - ) { - return true - } - } - return false -} - public fun HierarchicalScope.collectSyntheticExtensionProperties(receiverTypes: Collection, name: Name, location: LookupLocation) = collectAllFromImportingScopes { it.getContributedSyntheticExtensionProperties(receiverTypes, name, location) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/KotlinTypeInfo.kt b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/KotlinTypeInfo.kt index b0a47d0931e..00a8cd9e5c8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/KotlinTypeInfo.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/KotlinTypeInfo.kt @@ -30,7 +30,7 @@ import org.jetbrains.kotlin.types.KotlinType * At the end current data flow info is x != null && y != null, but jump data flow info is x != null only. * Both break and continue are counted as possible jump outside of a loop, but return is not. */ -class KotlinTypeInfo( +class KotlinTypeInfo @JvmOverloads constructor( val type: KotlinType?, val dataFlowInfo: DataFlowInfo, val jumpOutPossible: Boolean = false, diff --git a/compiler/testData/diagnostics/tests/deprecated/classWithCompanionObject.kt b/compiler/testData/diagnostics/tests/deprecated/classWithCompanionObject.kt new file mode 100644 index 00000000000..4d851d7127a --- /dev/null +++ b/compiler/testData/diagnostics/tests/deprecated/classWithCompanionObject.kt @@ -0,0 +1,8 @@ +class A { + @Deprecated("deprecated") companion object + + class B +} + +val x1 = A.B() + diff --git a/compiler/testData/diagnostics/tests/deprecated/classWithCompanionObject.txt b/compiler/testData/diagnostics/tests/deprecated/classWithCompanionObject.txt new file mode 100644 index 00000000000..589ccd73a6e --- /dev/null +++ b/compiler/testData/diagnostics/tests/deprecated/classWithCompanionObject.txt @@ -0,0 +1,24 @@ +package + +public val x1: A.B + +public final class A { + public constructor A() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final class B { + public constructor B() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + + @kotlin.Deprecated(message = "deprecated") public companion object Companion { + private constructor Companion() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} diff --git a/compiler/testData/diagnostics/tests/resolve/implicitReceiverProperty.kt b/compiler/testData/diagnostics/tests/resolve/implicitReceiverProperty.kt new file mode 100644 index 00000000000..902ce7e49e1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/implicitReceiverProperty.kt @@ -0,0 +1,33 @@ +// FILE: a.kt +package a + +class A(val b: String) { + companion object { + val c: String = "" + } + + fun mtd() = c.length +} + +// FILE: b.kt +package b + +// FILE: c.kt +package c + +// FILE: test.kt +package test + +import a.A + +fun T.with(f: T.() -> R) = f() + +fun A.extFun1() = b.length + +// fun A.extFun2() = c.length // TODO fix KT-9953 + +val x1 = A("").with { b.length } + +// val x2 = A("").with { c.length } // TODO fix KT-9953 + +val x3 = A.with { c.length } \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/resolve/implicitReceiverProperty.txt b/compiler/testData/diagnostics/tests/resolve/implicitReceiverProperty.txt new file mode 100644 index 00000000000..860f855bf19 --- /dev/null +++ b/compiler/testData/diagnostics/tests/resolve/implicitReceiverProperty.txt @@ -0,0 +1,34 @@ +package + +package a { + + public final class A { + public constructor A(/*0*/ b: kotlin.String) + public final val b: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun mtd(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public companion object Companion { + private constructor Companion() + public final val c: kotlin.String = "" + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } +} + +package b { +} + +package c { +} + +package test { + public val x1: kotlin.Int + public val x3: kotlin.Int + public fun a.A.extFun1(): kotlin.Int + public fun T.with(/*0*/ f: T.() -> R): R +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index e23244db858..5c9c050efe9 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -4767,6 +4767,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("classWithCompanionObject.kt") + public void testClassWithCompanionObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/classWithCompanionObject.kt"); + doTest(fileName); + } + @TestMetadata("componentUsage.kt") public void testComponentUsage() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/deprecated/componentUsage.kt"); @@ -13074,6 +13080,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("implicitReceiverProperty.kt") + public void testImplicitReceiverProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/implicitReceiverProperty.kt"); + doTest(fileName); + } + @TestMetadata("incompleteConstructorInvocation.kt") public void testIncompleteConstructorInvocation() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/resolve/incompleteConstructorInvocation.kt"); diff --git a/jps-plugin/testData/incremental/lookupTracker/classifierMembers/foo.kt b/jps-plugin/testData/incremental/lookupTracker/classifierMembers/foo.kt index 0d9e9e31416..34f67fad97a 100644 --- a/jps-plugin/testData/incremental/lookupTracker/classifierMembers/foo.kt +++ b/jps-plugin/testData/incremental/lookupTracker/classifierMembers/foo.kt @@ -19,8 +19,8 @@ import bar.* this./*c:foo.A*/a this./*c:foo.A*/foo() /*c:foo.A c:foo.A.Companion p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io c:foo.A(getBaz) c:foo.A(getBAZ)*/baz() - /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io c:foo.A c:foo.A.Companion*/Companion./*c:foo.A.Companion*/a - /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io c:foo.A c:foo.A.Companion*/O./*c:foo.A.O*/v = "OK" + /*c:foo.A c:foo.A.Companion p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/Companion./*c:foo.A.Companion*/a + /*c:foo.A c:foo.A.Companion p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/O./*c:foo.A.O*/v = "OK" } class B { @@ -64,8 +64,8 @@ import bar.* val a = 1 fun foo() { /*c:foo.E*/a - /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io c:foo.E*/Y./*c:foo.E*/a + /*c:foo.E p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/Y./*c:foo.E*/a /*c:foo.E*/foo() - /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io c:foo.E*/X./*c:foo.E*/foo() + /*c:foo.E p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/X./*c:foo.E*/foo() } } diff --git a/jps-plugin/testData/incremental/lookupTracker/classifierMembers/usages.kt b/jps-plugin/testData/incremental/lookupTracker/classifierMembers/usages.kt index 91c0eb2f084..6297ffd3418 100644 --- a/jps-plugin/testData/incremental/lookupTracker/classifierMembers/usages.kt +++ b/jps-plugin/testData/incremental/lookupTracker/classifierMembers/usages.kt @@ -9,15 +9,15 @@ import bar.* /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A()./*c:foo.A*/d = "new value" /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A()./*c:foo.A*/foo() /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A*/B()./*c:foo.A.B*/a - /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A c:foo.A.Companion*/B./*c:foo.A.B c:foo.A.B.CO*/bar(1) - /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A c:foo.A.Companion*/B./*c:foo.A.B c:foo.A.B.CO*/CO./*c:foo.A.B.CO*/bar(1) + /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A*/B./*c:foo.A.B c:foo.A.B.CO*/bar(1) + /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A*/B./*c:foo.A.B*/CO./*c:foo.A.B.CO*/bar(1) /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A c:foo.A.Companion*/a /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A c:foo.A.Companion*/baz() /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A*/Companion - /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A c:foo.A.Companion*/Companion./*c:foo.A.Companion*/baz() + /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A*/Companion./*c:foo.A.Companion*/baz() /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A*/O - /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A c:foo.A.Companion*/O./*c:foo.A.O*/v = "OK" + /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A*/O./*c:foo.A.O*/v = "OK" /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A c:foo.A.Companion p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io c:foo.A.Companion(getVala) c:foo.A.Companion(getVALA)*/vala /*p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io*/A./*c:foo.A c:foo.A.Companion p:foo p:bar p:java.lang p:kotlin p:kotlin.annotation p:kotlin.jvm p:kotlin.io c:foo.A.Companion(getVara) c:foo.A.Companion(getVARA)*/vara()