diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java index 499c060a011..15c11ffea42 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetFlowInformationProvider.java @@ -57,6 +57,7 @@ import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilPackage; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; +import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.ResolvedCallUtilPackage; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils; @@ -830,7 +831,7 @@ public class JetFlowInformationProvider { // } // } boolean sameDispatchReceiver = - PseudocodeUtil.isThisOrNoDispatchReceiver(resolvedCall, trace.getBindingContext()); + ResolvedCallUtilPackage.hasThisOrNoDispatchReceiver(resolvedCall, trace.getBindingContext()); TailRecursionKind kind = isTail && sameDispatchReceiver ? TAIL_CALL : NON_TAIL; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java index ae6c497fae9..5fca2e4000b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/pseudocode/PseudocodeUtil.java @@ -22,8 +22,6 @@ import org.jetbrains.kotlin.cfg.JetControlFlowProcessor; import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction; import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*; import org.jetbrains.kotlin.cfg.pseudocode.instructions.special.VariableDeclarationInstruction; -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor; -import org.jetbrains.kotlin.descriptors.ReceiverParameterDescriptor; import org.jetbrains.kotlin.descriptors.VariableDescriptor; import org.jetbrains.kotlin.diagnostics.Diagnostic; import org.jetbrains.kotlin.psi.*; @@ -31,9 +29,7 @@ import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingContextUtils; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; -import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver; -import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; -import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver; +import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.ResolvedCallUtilPackage; import org.jetbrains.kotlin.util.slicedMap.ReadOnlySlice; import org.jetbrains.kotlin.util.slicedMap.WritableSlice; @@ -105,37 +101,6 @@ public class PseudocodeUtil { "AccessTarget.Declaration has no receivers and it's not BlackBox, so it should be Call"; ResolvedCall accessResolvedCall = ((AccessTarget.Call) accessTarget).getResolvedCall(); - return isThisOrNoDispatchReceiver(accessResolvedCall, bindingContext); + return ResolvedCallUtilPackage.hasThisOrNoDispatchReceiver(accessResolvedCall, bindingContext); } - - public static boolean isThisOrNoDispatchReceiver( - @NotNull ResolvedCall resolvedCall, - @NotNull BindingContext bindingContext - ) { - // it returns true if call has no dispatch receiver (e.g. resulting descriptor is top-level function or local variable) - // or call receiver is effectively `this` instance (explicitly or implicitly) of resulting descriptor - // class A(other: A) { - // val x - // val y = other.x // return false for `other.x` as it's receiver is not `this` - // } - ReceiverParameterDescriptor dispatchReceiverParameter = resolvedCall.getResultingDescriptor().getDispatchReceiverParameter(); - ReceiverValue dispatchReceiverValue = resolvedCall.getDispatchReceiver(); - if (dispatchReceiverParameter == null || !dispatchReceiverValue.exists()) return true; - - DeclarationDescriptor classDescriptor = null; - if (dispatchReceiverValue instanceof ThisReceiver) { - // foo() -- implicit receiver - classDescriptor = ((ThisReceiver) dispatchReceiverValue).getDeclarationDescriptor(); - } - else if (dispatchReceiverValue instanceof ExpressionReceiver) { - JetExpression expression = JetPsiUtil.deparenthesize(((ExpressionReceiver) dispatchReceiverValue).getExpression()); - if (expression instanceof JetThisExpression) { - // this.foo() -- explicit receiver - JetThisExpression thisExpression = (JetThisExpression) expression; - classDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, thisExpression.getInstanceReference()); - } - } - return dispatchReceiverParameter.getContainingDeclaration() == classDescriptor; - } - } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/ClassDescriptorWithResolutionScopes.java b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/ClassDescriptorWithResolutionScopes.java index dfda79e9e52..07d1e710ccb 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/ClassDescriptorWithResolutionScopes.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/ClassDescriptorWithResolutionScopes.java @@ -33,9 +33,6 @@ public interface ClassDescriptorWithResolutionScopes extends ClassDescriptor { @NotNull JetScope getScopeForInitializerResolution(); - @NotNull - JetScope getScopeForSecondaryConstructorHeaderResolution(); - @NotNull JetScope getScopeForMemberLookup(); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/MutableClassDescriptor.java b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/MutableClassDescriptor.java index b10718e1c54..0b981c2a8d8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/MutableClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/descriptors/impl/MutableClassDescriptor.java @@ -57,7 +57,6 @@ public class MutableClassDescriptor extends ClassDescriptorBase implements Class private final WritableScope scopeForMemberResolution; // This scope contains type parameters but does not contain inner classes private final WritableScope scopeForSupertypeResolution; - private final WritableScope scopeForSecondaryConstructorHeaderResolution; private WritableScope scopeForInitializers; //contains members + primary constructor value parameters + map for backing fields private JetScope scopeForMemberLookup; private final JetScope staticScope = new StaticScopeForKotlinClass(this); @@ -84,8 +83,6 @@ public class MutableClassDescriptor extends ClassDescriptorBase implements Class .changeLockLevel(WritableScope.LockLevel.BOTH); this.scopeForMemberResolution = new WritableScopeImpl(scopeForSupertypeResolution, this, redeclarationHandler, "MemberResolution") .changeLockLevel(WritableScope.LockLevel.BOTH); - this.scopeForSecondaryConstructorHeaderResolution = - new WritableScopeImpl(scopeForSupertypeResolution, this, redeclarationHandler, "SecondaryConstructorHeaderResolution "); if (kind == ClassKind.TRAIT) { setUpScopeForInitializers(this); @@ -93,7 +90,6 @@ public class MutableClassDescriptor extends ClassDescriptorBase implements Class scopeForMemberResolution.importScope(staticScope); scopeForMemberResolution.addLabeledDeclaration(this); - scopeForSecondaryConstructorHeaderResolution.importScope(staticScope); } @Nullable @@ -293,12 +289,6 @@ public class MutableClassDescriptor extends ClassDescriptorBase implements Class return getWritableScopeForInitializers(); } - @NotNull - @Override - public JetScope getScopeForSecondaryConstructorHeaderResolution() { - return scopeForSecondaryConstructorHeaderResolution; - } - private void setUpScopeForInitializers(@NotNull DeclarationDescriptor containingDeclaration) { this.scopeForInitializers = new WritableScopeImpl( scopeForMemberResolution, containingDeclaration, RedeclarationHandler.DO_NOTHING, "Initializers") diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 350a7bb9725..604f782dfa8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -171,6 +171,8 @@ public interface Errors { DiagnosticFactory0 EXPLICIT_DELEGATION_CALL_REQUIRED = DiagnosticFactory0.create(ERROR, PositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL); + DiagnosticFactory1 INSTANCE_ACCESS_BEFORE_SUPER_CALL = DiagnosticFactory1.create(ERROR); + // Trait-specific DiagnosticFactory0 ABSTRACT_MODIFIER_IN_TRAIT = DiagnosticFactory0 diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 34548a6c7b8..f23638a46b8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -400,6 +400,8 @@ public class DefaultErrorMessages { MAP.put(EXPLICIT_DELEGATION_CALL_REQUIRED, "Explicit 'this' or 'super' call is required. There is no constructor in superclass that can be called without arguments"); + MAP.put(INSTANCE_ACCESS_BEFORE_SUPER_CALL, "Cannot access ''{0}'' before superclass constructor has been called", NAME); + MAP.put(INIT_KEYWORD_BEFORE_CLASS_INITIALIZER_EXPECTED, "Expecting 'init' keyword before class initializer"); MAP.put(ILLEGAL_SELECTOR, "Expression ''{0}'' cannot be a selector (occur after a dot)", STRING); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java index 320b01f85f6..f08c6737a71 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/BodyResolver.java @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.*; import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.calls.CallResolver; +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.calls.results.OverloadResolutionResults; import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo; @@ -35,6 +36,7 @@ import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.scopes.*; import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.kotlin.types.*; +import org.jetbrains.kotlin.types.expressions.ExpressionTypingContext; import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices; import org.jetbrains.kotlin.util.Box; import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException; @@ -142,22 +144,20 @@ public class BodyResolver { @NotNull final BindingTrace trace, @NotNull final JetSecondaryConstructor constructor, @NotNull final ConstructorDescriptor descriptor, - @NotNull JetScope bodyDeclaringScope + @NotNull JetScope declaringScope ) { AnnotationResolver.resolveAnnotationsArguments(constructor.getModifierList(), trace); - assert descriptor.getContainingDeclaration() instanceof ClassDescriptorWithResolutionScopes - : "When resolving body it should be class descriptor with resolution scopes"; - ClassDescriptorWithResolutionScopes classDescriptor = (ClassDescriptorWithResolutionScopes) descriptor.getContainingDeclaration(); - - resolveFunctionBody(c, trace, constructor, descriptor, bodyDeclaringScope, - classDescriptor.getScopeForSecondaryConstructorHeaderResolution(), + final CallChecker callChecker = new ConstructorHeaderCallChecker(descriptor, expressionTypingServices.getCallChecker()); + resolveFunctionBody(c, trace, constructor, descriptor, declaringScope, new Function1() { @Override public DataFlowInfo invoke(@NotNull JetScope headerInnerScope) { - return resolveSecondaryConstructorDelegationCall(c, trace, headerInnerScope, constructor, descriptor); + return resolveSecondaryConstructorDelegationCall(c, trace, headerInnerScope, constructor, descriptor, + callChecker); } - }); + }, + callChecker); } @Nullable @@ -166,11 +166,13 @@ public class BodyResolver { @NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetSecondaryConstructor constructor, - @NotNull ConstructorDescriptor descriptor + @NotNull ConstructorDescriptor descriptor, + @NotNull CallChecker callChecker ) { OverloadResolutionResults results = callResolver.resolveConstructorDelegationCall( trace, scope, c.getOuterDataFlowInfo(), - descriptor, constructor.getDelegationCall()); + descriptor, constructor.getDelegationCall(), + callChecker); if (results != null && results.isSingleResult()) { ResolvedCall resolvedCall = results.getResultingCall(); @@ -715,30 +717,29 @@ public class BodyResolver { @NotNull BindingTrace trace, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor, - @NotNull JetScope bodyDeclaringScope, - @Nullable JetScope headerDeclaringScope, - @Nullable Function1 beforeBlockBody + @NotNull JetScope scope, + @Nullable Function1 beforeBlockBody, + @Nullable CallChecker callChecker ) { - JetScope headerInnerScope = FunctionDescriptorUtil.getFunctionInnerScope( - headerDeclaringScope == null ? bodyDeclaringScope : headerDeclaringScope, functionDescriptor, trace); + JetScope innerScope = FunctionDescriptorUtil.getFunctionInnerScope(scope, functionDescriptor, trace); List valueParameters = function.getValueParameters(); List valueParameterDescriptors = functionDescriptor.getValueParameters(); - expressionTypingServices.resolveValueParameters(valueParameters, valueParameterDescriptors, headerInnerScope, - c.getOuterDataFlowInfo(), trace); + expressionTypingServices.resolveValueParameters( + valueParameters, valueParameterDescriptors, + ExpressionTypingContext.newContext( + expressionTypingServices, trace, innerScope, c.getOuterDataFlowInfo(), NO_EXPECTED_TYPE, callChecker) + ); DataFlowInfo dataFlowInfo = null; if (beforeBlockBody != null) { - dataFlowInfo = beforeBlockBody.invoke(headerInnerScope); + dataFlowInfo = beforeBlockBody.invoke(innerScope); } - JetScope bodyInnerScope = headerDeclaringScope == null ? headerInnerScope : - FunctionDescriptorUtil.getFunctionInnerScope(bodyDeclaringScope, functionDescriptor, trace); - if (function.hasBody()) { expressionTypingServices.checkFunctionReturnType( - bodyInnerScope, function, functionDescriptor, dataFlowInfo != null ? dataFlowInfo : c.getOuterDataFlowInfo(), null, trace); + innerScope, function, functionDescriptor, dataFlowInfo != null ? dataFlowInfo : c.getOuterDataFlowInfo(), null, trace); } assert functionDescriptor.getReturnType() != null; diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ConstructorHeaderCallChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ConstructorHeaderCallChecker.kt new file mode 100644 index 00000000000..d3aa09c8926 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ConstructorHeaderCallChecker.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve + +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.psi.JetConstructorDelegationCall +import org.jetbrains.kotlin.psi.JetInstanceExpressionWithLabel +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker +import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.calls.resolvedCallUtil.hasImplicitThisOrSuperDispatchReceiver +import org.jetbrains.kotlin.resolve.descriptorUtil.getOwnerForEffectiveDispatchReceiverParameter + + +public class ConstructorHeaderCallChecker(constructor: ConstructorDescriptor, private val wrapped: CallChecker) : CallChecker { + private val containingClass = constructor.getContainingDeclaration() + + override fun check(resolvedCall: ResolvedCall, context: BasicCallResolutionContext) { + if (resolvedCall.getStatus().isSuccess() && + resolvedCall.hasImplicitThisOrSuperDispatchReceiver(context.trace.getBindingContext()) && + containingClass == resolvedCall.getResultingDescriptor().getOwnerForEffectiveDispatchReceiverParameter() + ) { + reportError(context, resolvedCall) + } + else { + val callElement = resolvedCall.getCall().getCallElement() + if (callElement is JetInstanceExpressionWithLabel) { + val descriptor = context.trace.get(BindingContext.REFERENCE_TARGET, callElement.getInstanceReference()) + if (containingClass == descriptor) { + reportError(context, resolvedCall) + } + } + } + + wrapped.check(resolvedCall, context) + } + + private fun reportError(context: BasicCallResolutionContext, resolvedCall: ResolvedCall<*>) { + context.trace.report( + Errors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.on(context.call.getCalleeExpression(), resolvedCall.getResultingDescriptor())) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java index 29ef0cef905..1052b76ea9b 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/CallResolver.java @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; import org.jetbrains.kotlin.resolve.*; import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage; +import org.jetbrains.kotlin.resolve.calls.checkers.CallChecker; import org.jetbrains.kotlin.resolve.calls.context.*; import org.jetbrains.kotlin.resolve.calls.model.MutableDataFlowInfoForArguments; import org.jetbrains.kotlin.resolve.calls.model.MutableResolvedCall; @@ -301,7 +302,7 @@ public class CallResolver { public OverloadResolutionResults resolveConstructorDelegationCall( @NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull DataFlowInfo dataFlowInfo, @NotNull ConstructorDescriptor constructorDescriptor, - @NotNull JetConstructorDelegationCall call + @NotNull JetConstructorDelegationCall call, @NotNull CallChecker callChecker ) { // Method returns `null` when there is nothing to resolve in trivial cases like `null` call expression or // when super call should be conventional enum constructor and super call should be empty @@ -311,7 +312,7 @@ public class CallResolver { CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, call), NO_EXPECTED_TYPE, dataFlowInfo, ContextDependency.INDEPENDENT, CheckValueArgumentsMode.ENABLED, - expressionTypingServices.getCallChecker(), expressionTypingServices.getAdditionalTypeChecker(), false); + callChecker, expressionTypingServices.getAdditionalTypeChecker(), false); if (call.getCalleeExpression() == null) return checkArgumentTypesAndFail(context); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt new file mode 100644 index 00000000000..da03a928a6b --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/resolvedCallUtil.kt @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.calls.resolvedCallUtil + +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.psi.JetPsiUtil +import org.jetbrains.kotlin.psi.JetSuperExpression +import org.jetbrains.kotlin.psi.JetThisExpression +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall +import org.jetbrains.kotlin.resolve.descriptorUtil.getOwnerForEffectiveDispatchReceiverParameter +import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver +import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver + +// it returns true if call has no dispatch receiver (e.g. resulting descriptor is top-level function or local variable) +// or call receiver is effectively `this` instance (explicitly or implicitly) of resulting descriptor +// class A(other: A) { +// val x +// val y = other.x // return false for `other.x` as it's receiver is not `this` +// } +public fun ResolvedCall<*>.hasThisOrNoDispatchReceiver(context: BindingContext): Boolean = + hasThisOrNoDispatchReceiver(context, true, true) + +public fun ResolvedCall<*>.hasImplicitThisOrSuperDispatchReceiver(context: BindingContext): Boolean = + hasThisOrNoDispatchReceiver(context, false, false) + +private fun ResolvedCall<*>.hasThisOrNoDispatchReceiver( + context: BindingContext, + returnForNoReceiver: Boolean, + considerExplicitReceivers: Boolean +): Boolean { + val dispatchReceiverValue = getDispatchReceiver() + if (getResultingDescriptor().getDispatchReceiverParameter() == null || !dispatchReceiverValue.exists()) return returnForNoReceiver + + var dispatchReceiverDescriptor: DeclarationDescriptor? = null + if (dispatchReceiverValue is ThisReceiver) { + // foo() -- implicit receiver + dispatchReceiverDescriptor = dispatchReceiverValue.getDeclarationDescriptor() + } + else if (dispatchReceiverValue is ExpressionReceiver && considerExplicitReceivers) { + val expression = JetPsiUtil.deparenthesize(dispatchReceiverValue.getExpression()) + if (expression is JetThisExpression) { + // this.foo() -- explicit receiver + dispatchReceiverDescriptor = context.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference()) + } + } + + return dispatchReceiverDescriptor == getResultingDescriptor().getOwnerForEffectiveDispatchReceiverParameter() +} + diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java index e8a947b69a0..62ccf86a364 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassDescriptor.java @@ -92,7 +92,6 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes private final NotNullLazyValue scopeForClassHeaderResolution; private final NotNullLazyValue scopeForMemberDeclarationResolution; private final NotNullLazyValue scopeForPropertyInitializerResolution; - private final NotNullLazyValue scopeForSecondaryConstructorHeaderResolution; private final NullableLazyValue forceResolveAllContents; private final boolean isCompanionObject; @@ -212,12 +211,6 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes return computeScopeForPropertyInitializerResolution(); } }); - this.scopeForSecondaryConstructorHeaderResolution = storageManager.createLazyValue(new Function0() { - @Override - public JetScope invoke() { - return computeScopeForSecondaryConstructorHeaderResolution(); - } - }); this.forceResolveAllContents = storageManager.createRecursionTolerantNullableLazyValue(new Function0() { @Override public Void invoke() { @@ -335,24 +328,6 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes scope, getScopeForMemberDeclarationResolution()); } - @NotNull - @Override - public JetScope getScopeForSecondaryConstructorHeaderResolution() { - return scopeForSecondaryConstructorHeaderResolution.invoke(); - } - - - @NotNull - private JetScope computeScopeForSecondaryConstructorHeaderResolution() { - return new ChainedScope( - this, - "ScopeForSecondaryConstructorHeaderResolution: " + getName(), - getScopeForClassHeaderResolution(), - getCompanionObjectScope(), - DescriptorUtils.getStaticNestedClassesScope(this), - getStaticScope() - ); - } @NotNull @Override diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt index 2ff51bcfe68..1bd622a6ee5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/lazy/descriptors/LazyClassMemberScope.kt @@ -305,7 +305,7 @@ public open class LazyClassMemberScope( return classOrObject.getSecondaryConstructors().map { constructor -> val descriptor = c.functionDescriptorResolver.resolveSecondaryConstructorDescriptor( - thisDescriptor.getScopeForSecondaryConstructorHeaderResolution(), thisDescriptor, constructor, trace + thisDescriptor.getScopeForClassHeaderResolution(), thisDescriptor, constructor, trace ) setDeferredReturnType(descriptor) descriptor diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingContext.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingContext.java index ac1c29c1c55..43fc716113e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingContext.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/ExpressionTypingContext.java @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.types.expressions; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.StatementFilter; import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker; @@ -39,10 +40,23 @@ public class ExpressionTypingContext extends ResolutionContext valueParameters, + @NotNull List valueParameterDescriptors, + @NotNull ExpressionTypingContext context ) { for (int i = 0; i < valueParameters.size(); i++) { ValueParameterDescriptor valueParameterDescriptor = valueParameterDescriptors.get(i); JetParameter jetParameter = valueParameters.get(i); - AnnotationResolver.resolveAnnotationsArguments(jetParameter.getModifierList(), trace); + AnnotationResolver.resolveAnnotationsArguments(jetParameter.getModifierList(), context.trace); - resolveDefaultValue(declaringScope, valueParameterDescriptor, jetParameter, dataFlowInfo, trace); + resolveDefaultValue(valueParameterDescriptor, jetParameter, context); } } private void resolveDefaultValue( - @NotNull JetScope declaringScope, @NotNull ValueParameterDescriptor valueParameterDescriptor, @NotNull JetParameter jetParameter, - @NotNull DataFlowInfo dataFlowInfo, - @NotNull BindingTrace trace + @NotNull ExpressionTypingContext context ) { if (valueParameterDescriptor.hasDefaultValue()) { JetExpression defaultValue = jetParameter.getDefaultValue(); if (defaultValue != null) { - getType(declaringScope, defaultValue, valueParameterDescriptor.getType(), dataFlowInfo, trace); - if (DescriptorUtils.isAnnotationClass(DescriptorResolver.getContainingClass(declaringScope))) { - ConstantExpressionEvaluator.evaluate(defaultValue, trace, valueParameterDescriptor.getType()); + getTypeInfo(defaultValue, context.replaceExpectedType(valueParameterDescriptor.getType())); + if (DescriptorUtils.isAnnotationClass(DescriptorResolver.getContainingClass(context.scope))) { + ConstantExpressionEvaluator.evaluate( + defaultValue, context.trace, valueParameterDescriptor.getType()); } } } diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase.kt new file mode 100644 index 00000000000..02f3768a13d --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +open class Base(p: Any?) { + fun foo1(t: T) {} +} + +class D: Base("") { + inner class B : Base { + constructor() : super(foo1("")) + constructor(x: Int) : super(foo1(1)) + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase.txt new file mode 100644 index 00000000000..902bb3b3e9e --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase.txt @@ -0,0 +1,26 @@ +package + +internal open class Base { + public constructor Base(/*0*/ p: kotlin.Any?) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun foo1(/*0*/ t: T): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal final class D : Base { + public constructor D() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final override /*1*/ /*fake_override*/ fun foo1(/*0*/ t: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + internal final inner class B : Base { + public constructor B() + public constructor B(/*0*/ x: kotlin.Int) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final override /*1*/ /*fake_override*/ fun foo1(/*0*/ t: kotlin.String): kotlin.Unit + 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/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.kt new file mode 100644 index 00000000000..280bd7ae1f7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.kt @@ -0,0 +1,13 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +open class Base(p: Any?) { + fun foo1(t: T) {} +} + +class D: Base(1) { + inner class B : Base { + constructor() : super(foo1(1)) + constructor(x: Int) : super(this@B.foo1(1)) + constructor(x: Int, y: Int) : super(this@D.foo1(1)) + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.txt new file mode 100644 index 00000000000..2dab275f394 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.txt @@ -0,0 +1,27 @@ +package + +internal open class Base { + public constructor Base(/*0*/ p: kotlin.Any?) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun foo1(/*0*/ t: T): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal final class D : Base { + public constructor D() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final override /*1*/ /*fake_override*/ fun foo1(/*0*/ t: kotlin.Int): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + internal final inner class B : Base { + public constructor B() + public constructor B(/*0*/ x: kotlin.Int) + public constructor B(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final override /*1*/ /*fake_override*/ fun foo1(/*0*/ t: kotlin.Int): kotlin.Unit + 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/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.kt new file mode 100644 index 00000000000..dfe314fde26 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +open class Base(p: Any?) { + fun foo1() {} +} + +fun Base.foo() { + class B : Base { + constructor() : super(foo1()) + constructor(x: Int) : super(this@foo.foo1()) + constructor(x: Int, y: Int) : super(this@B.foo1()) + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.txt new file mode 100644 index 00000000000..e56f760c6be --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.txt @@ -0,0 +1,11 @@ +package + +internal fun Base.foo(): kotlin.Unit + +internal open class Base { + public constructor Base(/*0*/ p: kotlin.Any?) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun foo1(): kotlin.Unit + 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/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.kt new file mode 100644 index 00000000000..d9b64e85b79 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.kt @@ -0,0 +1,13 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +open class Base(p: Any?) { + fun foo1(t: T) {} +} + +fun Base.foo() { + class B : Base { + constructor() : super(foo1("")) + constructor(x: Int) : super(foo1(1)) + constructor(x: Int, y: Int) : super(this@foo.foo1(12)) + constructor(x: Int, y: Int, z: Int) : super(this@B.foo1("")) + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.txt new file mode 100644 index 00000000000..baf49acdc2b --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.txt @@ -0,0 +1,11 @@ +package + +internal fun Base.foo(): kotlin.Unit + +internal open class Base { + public constructor Base(/*0*/ p: kotlin.Any?) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun foo1(/*0*/ t: T): kotlin.Unit + 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/secondaryConstructors/headerCallChecker/innerInstanceCreation.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.kt new file mode 100644 index 00000000000..086914d928e --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.kt @@ -0,0 +1,11 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +fun foo(x: Outer) = 1 +class Outer { + inner class Inner { + val prop = 1 + } + + constructor(x: Int) + constructor(x: Int, y: Int, z: Int = x + Inner().prop + this.Inner().prop) : + this(x + Inner().prop + this.Inner().prop) +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.txt new file mode 100644 index 00000000000..3097e8586a6 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.txt @@ -0,0 +1,19 @@ +package + +internal fun foo(/*0*/ x: Outer): kotlin.Int + +internal final class Outer { + public constructor Outer(/*0*/ x: kotlin.Int) + public constructor Outer(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int, /*2*/ z: kotlin.Int = ...) + 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 + + internal final inner class Inner { + public constructor Inner() + internal final val prop: kotlin.Int = 1 + 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/secondaryConstructors/headerCallChecker/memberFunAccess.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.kt new file mode 100644 index 00000000000..13f74fb3ea9 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.kt @@ -0,0 +1,7 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +class A { + fun foo() = 1 + constructor(x: Int) + constructor(x: Int, y: Int, z: Int = x + foo() + this.foo()) : + this(x + foo() + this.foo()) +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.txt new file mode 100644 index 00000000000..78e47aac1cd --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.txt @@ -0,0 +1,10 @@ +package + +internal final class A { + public constructor A(/*0*/ x: kotlin.Int) + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int, /*2*/ z: kotlin.Int = ...) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun foo(): kotlin.Int + 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/secondaryConstructors/headerCallChecker/passingInstance.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.kt new file mode 100644 index 00000000000..4233f7f90ba --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.kt @@ -0,0 +1,8 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +fun foo(x: A) = 1 + +class A { + constructor(x: Int) + constructor(x: Int, y: Int, z: Int = x + foo(this) + foo(this@A)) : + this(x + foo(this) + foo(this@A)) +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.txt new file mode 100644 index 00000000000..982458af881 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.txt @@ -0,0 +1,11 @@ +package + +internal fun foo(/*0*/ x: A): kotlin.Int + +internal final class A { + public constructor A(/*0*/ x: kotlin.Int) + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int, /*2*/ z: kotlin.Int = ...) + 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/secondaryConstructors/headerCallChecker/propertyAccess.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.kt new file mode 100644 index 00000000000..b80ceeaf18a --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.kt @@ -0,0 +1,7 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +class A { + val prop = 1 + constructor(x: Int) + constructor(x: Int, y: Int, z: Int = x + prop + this.prop) : + this(x + prop + this.prop) +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.txt new file mode 100644 index 00000000000..22d2fe6074a --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.txt @@ -0,0 +1,10 @@ +package + +internal final class A { + public constructor A(/*0*/ x: kotlin.Int) + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int, /*2*/ z: kotlin.Int = ...) + internal final val prop: kotlin.Int = 1 + 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/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.kt new file mode 100644 index 00000000000..7a4f2235813 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.kt @@ -0,0 +1,7 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +open class B(x: Int) +class A : B { + val prop = 1 + constructor(x: Int, y: Int = x + prop + this.prop) : + super(x + prop + this.prop) +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.txt new file mode 100644 index 00000000000..d3881c3c31a --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.txt @@ -0,0 +1,16 @@ +package + +internal final class A : B { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int = ...) + internal final val prop: kotlin.Int = 1 + 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 +} + +internal open class B { + public constructor B(/*0*/ x: kotlin.Int) + 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/secondaryConstructors/headerCallChecker/superFunAccess.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.kt new file mode 100644 index 00000000000..908a4b45c47 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.kt @@ -0,0 +1,8 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +open class B(x: Int) { + fun foo() = 1 +} +class A : B { + constructor(x: Int, y: Int = x + foo() + this.foo() + super.foo()) : + super(x + foo() + this.foo() + super.foo()) +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.txt new file mode 100644 index 00000000000..a479ec67819 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.txt @@ -0,0 +1,17 @@ +package + +internal final class A : B { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int = ...) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final override /*1*/ /*fake_override*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal open class B { + public constructor B(/*0*/ x: kotlin.Int) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal final fun foo(): kotlin.Int + 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/secondaryConstructors/headerCallChecker/superFunAccessOverriden.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.kt new file mode 100644 index 00000000000..1d0f1cc128f --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.kt @@ -0,0 +1,9 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +open class B(x: Int) { + open fun foo() = 1 +} +class A : B { + override fun foo() = 2 + constructor(x: Int, y: Int = x + foo() + this.foo() + super.foo()) : + super(x + foo() + this.foo() + super.foo()) +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.txt new file mode 100644 index 00000000000..d7758e33ded --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.txt @@ -0,0 +1,17 @@ +package + +internal final class A : B { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int = ...) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal open override /*1*/ fun foo(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +internal open class B { + public constructor B(/*0*/ x: kotlin.Int) + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + internal open fun foo(): kotlin.Int + 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/secondaryConstructors/headerCallChecker/superPropertyAccess.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.kt new file mode 100644 index 00000000000..fa98c702d07 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.kt @@ -0,0 +1,6 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +open class B(val prop: Int) +class A : B { + constructor(x: Int, y: Int = x + prop + this.prop + super.prop) : + super(x + prop + this.prop + super.prop) +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.txt new file mode 100644 index 00000000000..6a891b2e5a7 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.txt @@ -0,0 +1,17 @@ +package + +internal final class A : B { + public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int = ...) + internal final override /*1*/ /*fake_override*/ val prop: kotlin.Int + 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 +} + +internal open class B { + public constructor B(/*0*/ prop: kotlin.Int) + internal final val prop: kotlin.Int + 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/secondaryConstructors/headerCallChecker/usingOuterInstance.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterInstance.kt new file mode 100644 index 00000000000..2ae3abd1d32 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterInstance.kt @@ -0,0 +1,8 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +fun foo(x: Outer) = 1 +class Outer { + inner class Inner { + constructor(x: Int) + constructor(x: Int, y: Int, z: Int = x + foo(this@Outer)) : this(x + foo(this@Outer)) + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterInstance.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterInstance.txt new file mode 100644 index 00000000000..ea984fbe41b --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterInstance.txt @@ -0,0 +1,18 @@ +package + +internal fun foo(/*0*/ x: Outer): kotlin.Int + +internal final class Outer { + public constructor Outer() + 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 + + internal final inner class Inner { + public constructor Inner(/*0*/ x: kotlin.Int) + public constructor Inner(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int, /*2*/ z: kotlin.Int = ...) + 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/secondaryConstructors/headerCallChecker/usingOuterProperty.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterProperty.kt new file mode 100644 index 00000000000..f429be3cf36 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterProperty.kt @@ -0,0 +1,8 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER +class Outer { + val prop = 1 + inner class Inner { + constructor(x: Int) + constructor(x: Int, y: Int, z: Int = x + prop + this@Outer.prop) : this(x + prop + this@Outer.prop) + } +} diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterProperty.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterProperty.txt new file mode 100644 index 00000000000..be5da526451 --- /dev/null +++ b/compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterProperty.txt @@ -0,0 +1,17 @@ +package + +internal final class Outer { + public constructor Outer() + internal final val prop: kotlin.Int = 1 + 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 + + internal final inner class Inner { + public constructor Inner(/*0*/ x: kotlin.Int) + public constructor Inner(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.Int, /*2*/ z: kotlin.Int = ...) + 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/secondaryConstructors/memberAccessBeforeSuperCall.kt b/compiler/testData/diagnostics/tests/secondaryConstructors/memberAccessBeforeSuperCall.kt deleted file mode 100644 index bf32a7f53fa..00000000000 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/memberAccessBeforeSuperCall.kt +++ /dev/null @@ -1,13 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER -open class B(open val parentProperty: String) -class A : B { - val myProp: String = "" - override val parentProperty: String = "" - constructor(arg: String = myProp): super(myProp) - constructor(x1: String, arg: String = this.myProp): super(this.myProp) - constructor(x1: String, x2: String, arg: String = parentProperty): super(parentProperty) - constructor(x1: String, x2: String, x3: String, arg: String = super.parentProperty): super(super.parentProperty) - constructor(x1: String, x2: String, x3: String, x4: String, arg: String = foo(this)): super(foo(this)) - constructor(x1: String, x2: String, x3: String, x4: String, x5: String, arg: String = foo(this@A)): super(foo(this@A)) -} -fun foo(x: A) = "" diff --git a/compiler/testData/diagnostics/tests/secondaryConstructors/memberAccessBeforeSuperCall.txt b/compiler/testData/diagnostics/tests/secondaryConstructors/memberAccessBeforeSuperCall.txt deleted file mode 100644 index 1b793856747..00000000000 --- a/compiler/testData/diagnostics/tests/secondaryConstructors/memberAccessBeforeSuperCall.txt +++ /dev/null @@ -1,25 +0,0 @@ -package - -internal fun foo(/*0*/ x: A): kotlin.String - -internal final class A : B { - public constructor A(/*0*/ arg: kotlin.String = ...) - public constructor A(/*0*/ x1: kotlin.String, /*1*/ arg: kotlin.String = ...) - public constructor A(/*0*/ x1: kotlin.String, /*1*/ x2: kotlin.String, /*2*/ arg: kotlin.String = ...) - public constructor A(/*0*/ x1: kotlin.String, /*1*/ x2: kotlin.String, /*2*/ x3: kotlin.String, /*3*/ arg: kotlin.String = ...) - public constructor A(/*0*/ x1: kotlin.String, /*1*/ x2: kotlin.String, /*2*/ x3: kotlin.String, /*3*/ x4: kotlin.String, /*4*/ arg: kotlin.String = ...) - public constructor A(/*0*/ x1: kotlin.String, /*1*/ x2: kotlin.String, /*2*/ x3: kotlin.String, /*3*/ x4: kotlin.String, /*4*/ x5: kotlin.String, /*5*/ arg: kotlin.String = ...) - internal final val myProp: kotlin.String = "" - internal open override /*1*/ val parentProperty: 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 -} - -internal open class B { - public constructor B(/*0*/ parentProperty: kotlin.String) - internal open val parentProperty: 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 -} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index ea24d646e96..2759483403b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -10569,6 +10569,9 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { @TestMetadata("compiler/testData/diagnostics/tests/secondaryConstructors") @TestDataPath("$PROJECT_ROOT") + @InnerTestClasses({ + SecondaryConstructors.HeaderCallChecker.class, + }) @RunWith(JUnit3RunnerWithInners.class) public static class SecondaryConstructors extends AbstractJetDiagnosticsTest { public void testAllFilesPresentInSecondaryConstructors() throws Exception { @@ -10719,12 +10722,6 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } - @TestMetadata("memberAccessBeforeSuperCall.kt") - public void testMemberAccessBeforeSuperCall() throws Exception { - String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/memberAccessBeforeSuperCall.kt"); - doTest(fileName); - } - @TestMetadata("nestedExtendsInner.kt") public void testNestedExtendsInner() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/nestedExtendsInner.kt"); @@ -10838,6 +10835,99 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/varargsInDelegationCallToSecondary.kt"); doTest(fileName); } + + @TestMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class HeaderCallChecker extends AbstractJetDiagnosticsTest { + @TestMetadata("accessBaseGenericFromInnerExtendingSameBase.kt") + public void testAccessBaseGenericFromInnerExtendingSameBase() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase.kt"); + doTest(fileName); + } + + @TestMetadata("accessBaseGenericFromInnerExtendingSameBase2.kt") + public void testAccessBaseGenericFromInnerExtendingSameBase2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseGenericFromInnerExtendingSameBase2.kt"); + doTest(fileName); + } + + @TestMetadata("accessBaseWithSameExtension.kt") + public void testAccessBaseWithSameExtension() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessBaseWithSameExtension.kt"); + doTest(fileName); + } + + @TestMetadata("accessGenericBaseWithSameExtension.kt") + public void testAccessGenericBaseWithSameExtension() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/accessGenericBaseWithSameExtension.kt"); + doTest(fileName); + } + + public void testAllFilesPresentInHeaderCallChecker() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("innerInstanceCreation.kt") + public void testInnerInstanceCreation() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/innerInstanceCreation.kt"); + doTest(fileName); + } + + @TestMetadata("memberFunAccess.kt") + public void testMemberFunAccess() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/memberFunAccess.kt"); + doTest(fileName); + } + + @TestMetadata("passingInstance.kt") + public void testPassingInstance() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/passingInstance.kt"); + doTest(fileName); + } + + @TestMetadata("propertyAccess.kt") + public void testPropertyAccess() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccess.kt"); + doTest(fileName); + } + + @TestMetadata("propertyAccessUnitialized.kt") + public void testPropertyAccessUnitialized() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/propertyAccessUnitialized.kt"); + doTest(fileName); + } + + @TestMetadata("superFunAccess.kt") + public void testSuperFunAccess() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccess.kt"); + doTest(fileName); + } + + @TestMetadata("superFunAccessOverriden.kt") + public void testSuperFunAccessOverriden() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superFunAccessOverriden.kt"); + doTest(fileName); + } + + @TestMetadata("superPropertyAccess.kt") + public void testSuperPropertyAccess() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/superPropertyAccess.kt"); + doTest(fileName); + } + + @TestMetadata("usingOuterInstance.kt") + public void testUsingOuterInstance() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterInstance.kt"); + doTest(fileName); + } + + @TestMetadata("usingOuterProperty.kt") + public void testUsingOuterProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/secondaryConstructors/headerCallChecker/usingOuterProperty.kt"); + doTest(fileName); + } + } } @TestMetadata("compiler/testData/diagnostics/tests/senselessComparison") diff --git a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java index 761337f440c..860481ec584 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java +++ b/core/descriptors/src/org/jetbrains/kotlin/descriptors/impl/FunctionDescriptorImpl.java @@ -216,6 +216,16 @@ public abstract class FunctionDescriptorImpl extends DeclarationDescriptorNonRoo ReceiverParameterDescriptor substitutedExpectedThis = null; if (dispatchReceiverParameter != null) { + // When generating fake-overridden member it's dispatch receiver parameter has type of Base, and it's correct. + // E.g. + // class Base { fun foo() } + // class Derived : Base + // val x: Base + // if (x is Derived) { + // // `x` shouldn't be marked as smart-cast + // // but it would if fake-overridden `foo` had `Derived` as it's dispatch receiver parameter type + // x.foo() + // } substitutedExpectedThis = dispatchReceiverParameter.substitute(substitutor); if (substitutedExpectedThis == null) { return null; diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt index 8d1d11a60a8..a86ce36a414 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.kt @@ -98,4 +98,29 @@ public fun ClassDescriptor.getSuperClassNotAny(): ClassDescriptor? { public fun ClassDescriptor.getSuperClassOrAny(): ClassDescriptor = getSuperClassNotAny() ?: KotlinBuiltIns.getInstance().getAny() public val ClassDescriptor.secondaryConstructors: List - get() = getConstructors().filterNot { it.isPrimary() } \ No newline at end of file + get() = getConstructors().filterNot { it.isPrimary() } + +/** + * Returns containing declaration of dispatch receiver for callable adjusted to fake-overridden cases + * + * open class A { + * fun foo() = 1 + * } + * class B : A() + * + * for A.foo -> returns A (dispatch receiver parameter is A) + * for B.foo -> returns B (dispatch receiver parameter is still A, but it's fake-overridden in B, so it's containing declaration is B) + * + * class Outer { + * inner class Inner() + * } + * + * for constructor of Outer.Inner -> returns Outer (dispatch receiver parameter is Outer, but it's containing declaration is Inner) + * + */ +public fun CallableDescriptor.getOwnerForEffectiveDispatchReceiverParameter(): DeclarationDescriptor? { + if (this is CallableMemberDescriptor && getKind() == CallableMemberDescriptor.Kind.FAKE_OVERRIDE) { + return getContainingDeclaration() + } + return getDispatchReceiverParameter()?.getContainingDeclaration() +} diff --git a/idea/testData/completion/basic/common/InSecondaryConstructorDefaultParameter.kt b/idea/testData/completion/basic/common/InSecondaryConstructorDefaultParameter.kt index a10508db80c..21ebebed597 100644 --- a/idea/testData/completion/basic/common/InSecondaryConstructorDefaultParameter.kt +++ b/idea/testData/completion/basic/common/InSecondaryConstructorDefaultParameter.kt @@ -9,5 +9,5 @@ class A(val prop: Int, arg: Int) { fun foo() = 1 } -// EXIST: topLevel, abc -// ABSENT: arg, local, prop, another, foo +// EXIST: topLevel, abc, prop, another, foo +// ABSENT: arg, local diff --git a/idea/testData/completion/basic/common/InSecondaryConstructorDelegationCall.kt b/idea/testData/completion/basic/common/InSecondaryConstructorDelegationCall.kt index cd9e406e651..18f68232cc2 100644 --- a/idea/testData/completion/basic/common/InSecondaryConstructorDelegationCall.kt +++ b/idea/testData/completion/basic/common/InSecondaryConstructorDelegationCall.kt @@ -9,5 +9,5 @@ class A(val prop: Int, arg: Int) { fun foo() = 1 } -// EXIST: abc, topLevel -// ABSENT: arg, local, prop, another, foo +// EXIST: abc, topLevel, prop, another, foo +// ABSENT: arg, local diff --git a/idea/testData/completion/basic/common/InSecondaryConstructorFirstDefaultParameter.kt b/idea/testData/completion/basic/common/InSecondaryConstructorFirstDefaultParameter.kt index 2240ee6b534..da60fe1eebb 100644 --- a/idea/testData/completion/basic/common/InSecondaryConstructorFirstDefaultParameter.kt +++ b/idea/testData/completion/basic/common/InSecondaryConstructorFirstDefaultParameter.kt @@ -9,5 +9,5 @@ class A(val prop: Int, arg: Int) { fun foo() = 1 } -// EXIST: abc, topLevel, x -// ABSENT: arg, local, prop, another, foo +// EXIST: abc, topLevel, x, prop, another, foo +// ABSENT: arg, local