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.
This commit is contained in:
@@ -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<QualifierPart> {
|
||||
@@ -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<DeclarationDescriptor?, Int> {
|
||||
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<CallExpressionElement> {
|
||||
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<KtQualifiedExpression> {
|
||||
val unrolled = arrayListOf<KtQualifiedExpression>()
|
||||
|
||||
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<KtQualifiedExpression>) : List<QualifierPart> {
|
||||
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<QualifierPart>()
|
||||
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<QualifierPart>,
|
||||
trace: BindingTrace,
|
||||
inImport: Boolean
|
||||
position: QualifierPosition
|
||||
): Pair<PackageViewDescriptor, Int> {
|
||||
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<QualifierPart>,
|
||||
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<DeclarationDescriptor>,
|
||||
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
|
||||
}
|
||||
|
||||
+44
-8
@@ -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<KtSimpleNameExpression, Boolean> isValueFunction = new Function1<KtSimpleNameExpression, Boolean>() {
|
||||
@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<VariableDescriptor> resolutionResult = callResolver.resolveSimpleProperty(contextForVariable);
|
||||
|
||||
if (resolutionResult.isSingleResult() &&
|
||||
resolutionResult.getResultingDescriptor() instanceof FakeCallableDescriptorForObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !resolutionResult.isNothing();
|
||||
}
|
||||
};
|
||||
List<CallExpressionElement> 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 =
|
||||
|
||||
@@ -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<CallExpressionElement> {
|
||||
var current: KtExpression = root
|
||||
val result = linkedListOf<CallExpressionElement>()
|
||||
while (current is KtQualifiedExpression) {
|
||||
result.addFirst(CallExpressionElement(current))
|
||||
current = result.first.receiver
|
||||
public fun unrollToLeftMostQualifiedExpression(expression: KtQualifiedExpression): List<KtQualifiedExpression> {
|
||||
val unrolled = arrayListOf<KtQualifiedExpression>()
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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<KotlinType>, name: Name, location: LookupLocation)
|
||||
= collectAllFromImportingScopes { it.getContributedSyntheticExtensionProperties(receiverTypes, name, location) }
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
class A {
|
||||
@Deprecated("deprecated") companion object
|
||||
|
||||
class B
|
||||
}
|
||||
|
||||
val x1 = A.B()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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, R> 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 }
|
||||
@@ -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 </*0*/ T, /*1*/ R> T.with(/*0*/ f: T.() -> R): R
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user