Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.resolve.BodyResolver Maven / Gradle / Ivy
/*
* 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 com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.Queue;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
import org.jetbrains.kotlin.diagnostics.Errors;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
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;
import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
import org.jetbrains.kotlin.resolve.scopes.JetScopeUtils;
import org.jetbrains.kotlin.resolve.scopes.LexicalScope;
import org.jetbrains.kotlin.resolve.scopes.LexicalScopeImpl;
import org.jetbrains.kotlin.resolve.scopes.RedeclarationHandler;
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.types.expressions.PreliminaryDeclarationVisitor;
import org.jetbrains.kotlin.types.expressions.ValueParameterResolver;
import org.jetbrains.kotlin.types.expressions.typeInfoFactory.TypeInfoFactoryKt;
import org.jetbrains.kotlin.util.Box;
import org.jetbrains.kotlin.util.ReenteringLazyValueComputationException;
import org.jetbrains.kotlin.util.slicedMap.WritableSlice;
import java.util.*;
import static org.jetbrains.kotlin.diagnostics.Errors.*;
import static org.jetbrains.kotlin.resolve.BindingContext.*;
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
public class BodyResolver {
@NotNull private final ScriptBodyResolver scriptBodyResolverResolver;
@NotNull private final AnnotationChecker annotationChecker;
@NotNull private final ExpressionTypingServices expressionTypingServices;
@NotNull private final CallResolver callResolver;
@NotNull private final ObservableBindingTrace trace;
@NotNull private final ControlFlowAnalyzer controlFlowAnalyzer;
@NotNull private final DeclarationsChecker declarationsChecker;
@NotNull private final AnnotationResolver annotationResolver;
@NotNull private final DelegatedPropertyResolver delegatedPropertyResolver;
@NotNull private final FunctionAnalyzerExtension functionAnalyzerExtension;
@NotNull private final ValueParameterResolver valueParameterResolver;
@NotNull private final BodyResolveCache bodyResolveCache;
public BodyResolver(
@NotNull AnnotationResolver annotationResolver,
@NotNull BodyResolveCache bodyResolveCache,
@NotNull CallResolver callResolver,
@NotNull ControlFlowAnalyzer controlFlowAnalyzer,
@NotNull DeclarationsChecker declarationsChecker,
@NotNull DelegatedPropertyResolver delegatedPropertyResolver,
@NotNull ExpressionTypingServices expressionTypingServices,
@NotNull FunctionAnalyzerExtension functionAnalyzerExtension,
@NotNull ScriptBodyResolver scriptBodyResolverResolver,
@NotNull BindingTrace trace,
@NotNull ValueParameterResolver valueParameterResolver,
@NotNull AnnotationChecker annotationChecker
) {
this.annotationResolver = annotationResolver;
this.bodyResolveCache = bodyResolveCache;
this.callResolver = callResolver;
this.controlFlowAnalyzer = controlFlowAnalyzer;
this.declarationsChecker = declarationsChecker;
this.delegatedPropertyResolver = delegatedPropertyResolver;
this.expressionTypingServices = expressionTypingServices;
this.functionAnalyzerExtension = functionAnalyzerExtension;
this.scriptBodyResolverResolver = scriptBodyResolverResolver;
this.annotationChecker = annotationChecker;
this.trace = new ObservableBindingTrace(trace);
this.valueParameterResolver = valueParameterResolver;
}
private void resolveBehaviorDeclarationBodies(@NotNull BodiesResolveContext c) {
resolveDelegationSpecifierLists(c);
resolvePropertyDeclarationBodies(c);
resolveAnonymousInitializers(c);
resolvePrimaryConstructorParameters(c);
resolveSecondaryConstructors(c);
resolveFunctionBodies(c);
// SCRIPT: resolve script bodies
scriptBodyResolverResolver.resolveScriptBodies(c);
if (!c.getTopDownAnalysisMode().isLocalDeclarations()) {
computeDeferredTypes();
}
}
private void resolveSecondaryConstructors(@NotNull BodiesResolveContext c) {
for (Map.Entry entry : c.getSecondaryConstructors().entrySet()) {
LexicalScope declaringScope = c.getDeclaringScope(entry.getKey());
assert declaringScope != null : "Declaring scope should be registered before body resolve";
resolveSecondaryConstructorBody(c.getOuterDataFlowInfo(), trace, entry.getKey(), entry.getValue(), declaringScope);
}
if (c.getSecondaryConstructors().isEmpty()) return;
Set visitedConstructors = Sets.newHashSet();
for (Map.Entry entry : c.getSecondaryConstructors().entrySet()) {
checkCyclicConstructorDelegationCall(entry.getValue(), visitedConstructors);
}
}
public void resolveSecondaryConstructorBody(
@NotNull final DataFlowInfo outerDataFlowInfo,
@NotNull final BindingTrace trace,
@NotNull final KtSecondaryConstructor constructor,
@NotNull final ConstructorDescriptor descriptor,
@NotNull LexicalScope declaringScope
) {
ForceResolveUtil.forceResolveAllContents(descriptor.getAnnotations());
final CallChecker callChecker = new ConstructorHeaderCallChecker(descriptor);
resolveFunctionBody(outerDataFlowInfo, trace, constructor, descriptor, declaringScope,
new Function1() {
@Override
public DataFlowInfo invoke(@NotNull LexicalScope headerInnerScope) {
return resolveSecondaryConstructorDelegationCall(outerDataFlowInfo, trace, headerInnerScope, constructor, descriptor,
callChecker);
}
},
callChecker);
}
@Nullable
private DataFlowInfo resolveSecondaryConstructorDelegationCall(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace,
@NotNull LexicalScope scope,
@NotNull KtSecondaryConstructor constructor,
@NotNull ConstructorDescriptor descriptor,
@NotNull CallChecker callChecker
) {
OverloadResolutionResults> results = callResolver.resolveConstructorDelegationCall(
trace, scope, outerDataFlowInfo,
descriptor, constructor.getDelegationCall(),
callChecker);
if (results != null && results.isSingleResult()) {
ResolvedCall extends CallableDescriptor> resolvedCall = results.getResultingCall();
recordConstructorDelegationCall(trace, descriptor, resolvedCall);
return resolvedCall.getDataFlowInfoForArguments().getResultInfo();
}
return null;
}
private void checkCyclicConstructorDelegationCall(
@NotNull ConstructorDescriptor constructorDescriptor,
@NotNull Set visitedConstructors
) {
if (visitedConstructors.contains(constructorDescriptor)) return;
// if visit constructor that is already in current chain
// such constructor is on cycle
Set visitedInCurrentChain = Sets.newHashSet();
ConstructorDescriptor currentConstructorDescriptor = constructorDescriptor;
while (true) {
visitedInCurrentChain.add(currentConstructorDescriptor);
ConstructorDescriptor delegatedConstructorDescriptor = getDelegatedConstructor(currentConstructorDescriptor);
if (delegatedConstructorDescriptor == null) break;
// if next delegation call is super or primary constructor or already visited
if (!constructorDescriptor.getContainingDeclaration().equals(delegatedConstructorDescriptor.getContainingDeclaration()) ||
delegatedConstructorDescriptor.isPrimary() ||
visitedConstructors.contains(delegatedConstructorDescriptor)) {
break;
}
if (visitedInCurrentChain.contains(delegatedConstructorDescriptor)) {
reportEachConstructorOnCycle(delegatedConstructorDescriptor);
break;
}
currentConstructorDescriptor = delegatedConstructorDescriptor;
}
visitedConstructors.addAll(visitedInCurrentChain);
}
private void reportEachConstructorOnCycle(@NotNull ConstructorDescriptor startConstructor) {
ConstructorDescriptor currentConstructor = startConstructor;
do {
PsiElement constructorToReport = DescriptorToSourceUtils.descriptorToDeclaration(currentConstructor);
if (constructorToReport != null) {
KtConstructorDelegationCall call = ((KtSecondaryConstructor) constructorToReport).getDelegationCall();
assert call.getCalleeExpression() != null
: "Callee expression of delegation call should not be null on cycle as there should be explicit 'this' calls";
trace.report(CYCLIC_CONSTRUCTOR_DELEGATION_CALL.on(call.getCalleeExpression()));
}
currentConstructor = getDelegatedConstructor(currentConstructor);
assert currentConstructor != null : "Delegated constructor should not be null in cycle";
} while (startConstructor != currentConstructor);
}
@Nullable
private ConstructorDescriptor getDelegatedConstructor(@NotNull ConstructorDescriptor constructor) {
ResolvedCall call = trace.get(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructor);
return call == null || !call.getStatus().isSuccess() ? null : call.getResultingDescriptor().getOriginal();
}
public void resolveBodies(@NotNull BodiesResolveContext c) {
resolveBehaviorDeclarationBodies(c);
controlFlowAnalyzer.process(c);
declarationsChecker.process(c);
functionAnalyzerExtension.process(c);
}
private void resolveDelegationSpecifierLists(@NotNull BodiesResolveContext c) {
// TODO : Make sure the same thing is not initialized twice
for (Map.Entry entry : c.getDeclaredClasses().entrySet()) {
KtClassOrObject classOrObject = entry.getKey();
ClassDescriptorWithResolutionScopes descriptor = entry.getValue();
resolveDelegationSpecifierList(c.getOuterDataFlowInfo(), classOrObject, descriptor,
descriptor.getUnsubstitutedPrimaryConstructor(),
descriptor.getScopeForClassHeaderResolution(),
descriptor.getScopeForMemberDeclarationResolution());
}
}
public void resolveDelegationSpecifierList(
@NotNull final DataFlowInfo outerDataFlowInfo,
@NotNull KtClassOrObject jetClass,
@NotNull final ClassDescriptor descriptor,
@Nullable final ConstructorDescriptor primaryConstructor,
@NotNull LexicalScope scopeForSupertypeResolution,
@NotNull final LexicalScope scopeForMemberResolution
) {
final LexicalScope scopeForConstructor = primaryConstructor == null
? null
: FunctionDescriptorUtil.getFunctionInnerScope(scopeForSupertypeResolution, primaryConstructor, trace);
final ExpressionTypingServices typeInferrer = expressionTypingServices; // TODO : flow
final Map supertypes = Maps.newLinkedHashMap();
final ResolvedCall>[] primaryConstructorDelegationCall = new ResolvedCall[1];
KtVisitorVoid visitor = new KtVisitorVoid() {
private void recordSupertype(KtTypeReference typeReference, KotlinType supertype) {
if (supertype == null) return;
supertypes.put(typeReference, supertype);
}
@Override
public void visitDelegationByExpressionSpecifier(@NotNull KtDelegatorByExpressionSpecifier specifier) {
if (descriptor.getKind() == ClassKind.INTERFACE) {
trace.report(DELEGATION_IN_INTERFACE.on(specifier));
}
KotlinType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
recordSupertype(specifier.getTypeReference(), supertype);
if (supertype != null) {
DeclarationDescriptor declarationDescriptor = supertype.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
if (classDescriptor.getKind() != ClassKind.INTERFACE) {
trace.report(DELEGATION_NOT_TO_INTERFACE.on(specifier.getTypeReference()));
}
}
}
KtExpression delegateExpression = specifier.getDelegateExpression();
if (delegateExpression != null) {
LexicalScope scope = scopeForConstructor == null ? scopeForMemberResolution : scopeForConstructor;
KotlinType expectedType = supertype != null ? supertype : NO_EXPECTED_TYPE;
typeInferrer.getType(scope, delegateExpression, expectedType, outerDataFlowInfo, trace);
}
if (primaryConstructor == null) {
trace.report(UNSUPPORTED.on(specifier, "Delegation without primary constructor is not supported"));
}
}
@Override
public void visitDelegationToSuperCallSpecifier(@NotNull KtDelegatorToSuperCall call) {
KtValueArgumentList valueArgumentList = call.getValueArgumentList();
PsiElement elementToMark = valueArgumentList == null ? call : valueArgumentList;
if (descriptor.getKind() == ClassKind.INTERFACE) {
trace.report(SUPERTYPE_INITIALIZED_IN_INTERFACE.on(elementToMark));
}
KtTypeReference typeReference = call.getTypeReference();
if (typeReference == null) return;
if (primaryConstructor == null) {
if (descriptor.getKind() != ClassKind.INTERFACE) {
trace.report(SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR.on(call));
}
recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference));
return;
}
OverloadResolutionResults results = callResolver.resolveFunctionCall(
trace, scopeForConstructor,
CallMaker.makeCall(ReceiverValue.NO_RECEIVER, null, call), NO_EXPECTED_TYPE, outerDataFlowInfo, false);
if (results.isSuccess()) {
KotlinType supertype = results.getResultingDescriptor().getReturnType();
recordSupertype(typeReference, supertype);
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) {
// allow only one delegating constructor
if (primaryConstructorDelegationCall[0] == null) {
primaryConstructorDelegationCall[0] = results.getResultingCall();
}
else {
primaryConstructorDelegationCall[0] = null;
}
}
// Recording type info for callee to use later in JetObjectLiteralExpression
trace.record(PROCESSED, call.getCalleeExpression(), true);
trace.record(EXPRESSION_TYPE_INFO, call.getCalleeExpression(),
TypeInfoFactoryKt.noTypeInfo(results.getResultingCall().getDataFlowInfoForArguments().getResultInfo()));
}
else {
recordSupertype(typeReference, trace.getBindingContext().get(BindingContext.TYPE, typeReference));
}
}
@Override
public void visitDelegationToSuperClassSpecifier(@NotNull KtDelegatorToSuperClass specifier) {
KtTypeReference typeReference = specifier.getTypeReference();
KotlinType supertype = trace.getBindingContext().get(BindingContext.TYPE, typeReference);
recordSupertype(typeReference, supertype);
if (supertype == null) return;
ClassDescriptor superClass = TypeUtils.getClassDescriptor(supertype);
if (superClass == null) return;
if (superClass.getKind().isSingleton()) {
// A "singleton in supertype" diagnostic will be reported later
return;
}
if (descriptor.getKind() != ClassKind.INTERFACE &&
descriptor.getUnsubstitutedPrimaryConstructor() != null &&
superClass.getKind() != ClassKind.INTERFACE &&
!superClass.getConstructors().isEmpty() &&
!ErrorUtils.isError(superClass)
) {
trace.report(SUPERTYPE_NOT_INITIALIZED.on(specifier));
}
}
@Override
public void visitJetElement(@NotNull KtElement element) {
throw new UnsupportedOperationException(element.getText() + " : " + element);
}
};
for (KtDelegationSpecifier delegationSpecifier : jetClass.getDelegationSpecifiers()) {
delegationSpecifier.accept(visitor);
}
if (DescriptorUtils.isAnnotationClass(descriptor) && jetClass.getDelegationSpecifierList() != null) {
trace.report(SUPERTYPES_FOR_ANNOTATION_CLASS.on(jetClass.getDelegationSpecifierList()));
}
if (primaryConstructorDelegationCall[0] != null && primaryConstructor != null) {
recordConstructorDelegationCall(trace, primaryConstructor, primaryConstructorDelegationCall[0]);
}
checkSupertypeList(descriptor, supertypes, jetClass);
}
// Returns a set of enum or sealed types of which supertypeOwner is an entry or a member
@NotNull
private static Set getAllowedFinalSupertypes(
@NotNull ClassDescriptor descriptor,
@NotNull KtClassOrObject jetClass
) {
Set parentEnumOrSealed;
if (jetClass instanceof KtEnumEntry) {
parentEnumOrSealed = Collections.singleton(((ClassDescriptor) descriptor.getContainingDeclaration()).getTypeConstructor());
}
else {
parentEnumOrSealed = Collections.emptySet();
ClassDescriptor currentDescriptor = descriptor;
while (currentDescriptor.getContainingDeclaration() instanceof ClassDescriptor) {
currentDescriptor = (ClassDescriptor) currentDescriptor.getContainingDeclaration();
if (currentDescriptor.getModality() == Modality.SEALED) {
if (parentEnumOrSealed.isEmpty()) {
parentEnumOrSealed = new HashSet();
}
parentEnumOrSealed.add(currentDescriptor.getTypeConstructor());
}
}
}
return parentEnumOrSealed;
}
private static void recordConstructorDelegationCall(
@NotNull BindingTrace trace,
@NotNull ConstructorDescriptor constructor,
@NotNull ResolvedCall> call
) {
//noinspection unchecked
trace.record(CONSTRUCTOR_RESOLVED_DELEGATION_CALL, constructor, (ResolvedCall) call);
}
private void checkSupertypeList(
@NotNull ClassDescriptor supertypeOwner,
@NotNull Map supertypes,
@NotNull KtClassOrObject jetClass
) {
Set allowedFinalSupertypes = getAllowedFinalSupertypes(supertypeOwner, jetClass);
Set typeConstructors = Sets.newHashSet();
boolean classAppeared = false;
for (Map.Entry entry : supertypes.entrySet()) {
KtTypeReference typeReference = entry.getKey();
KotlinType supertype = entry.getValue();
KtTypeElement typeElement = typeReference.getTypeElement();
if (typeElement instanceof KtFunctionType) {
for (KtParameter parameter : ((KtFunctionType) typeElement).getParameters()) {
PsiElement nameIdentifier = parameter.getNameIdentifier();
if (nameIdentifier != null) {
trace.report(Errors.UNSUPPORTED.on(nameIdentifier, "named parameter in function type in supertype position"));
}
}
}
boolean addSupertype = true;
ClassDescriptor classDescriptor = TypeUtils.getClassDescriptor(supertype);
if (classDescriptor != null) {
if (ErrorUtils.isError(classDescriptor)) continue;
if (KotlinBuiltIns.isExactExtensionFunctionType(supertype)) {
trace.report(SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE.on(typeReference));
}
if (classDescriptor.getKind() != ClassKind.INTERFACE) {
if (supertypeOwner.getKind() == ClassKind.ENUM_CLASS) {
trace.report(CLASS_IN_SUPERTYPE_FOR_ENUM.on(typeReference));
addSupertype = false;
}
else if (supertypeOwner.getKind() == ClassKind.INTERFACE &&
!classAppeared && !DynamicTypesKt.isDynamic(supertype) /* avoid duplicate diagnostics */) {
trace.report(INTERFACE_WITH_SUPERCLASS.on(typeReference));
addSupertype = false;
}
else if (jetClass.hasModifier(KtTokens.DATA_KEYWORD)) {
trace.report(DATA_CLASS_CANNOT_HAVE_CLASS_SUPERTYPES.on(typeReference));
addSupertype = false;
}
if (classAppeared) {
trace.report(MANY_CLASSES_IN_SUPERTYPE_LIST.on(typeReference));
}
else {
classAppeared = true;
}
}
}
else {
trace.report(SUPERTYPE_NOT_A_CLASS_OR_INTERFACE.on(typeReference));
}
TypeConstructor constructor = supertype.getConstructor();
if (addSupertype && !typeConstructors.add(constructor)) {
trace.report(SUPERTYPE_APPEARS_TWICE.on(typeReference));
}
if (DescriptorUtils.isSingleton(classDescriptor)) {
trace.report(SINGLETON_IN_SUPERTYPE.on(typeReference));
}
else if (constructor.isFinal() && !allowedFinalSupertypes.contains(constructor)) {
if (classDescriptor.getModality() == Modality.SEALED) {
DeclarationDescriptor containingDescriptor = supertypeOwner.getContainingDeclaration();
while (containingDescriptor != null && containingDescriptor != classDescriptor) {
containingDescriptor = containingDescriptor.getContainingDeclaration();
}
if (containingDescriptor == null) {
trace.report(SEALED_SUPERTYPE.on(typeReference));
}
else {
trace.report(SEALED_SUPERTYPE_IN_LOCAL_CLASS.on(typeReference));
}
}
else {
trace.report(FINAL_SUPERTYPE.on(typeReference));
}
}
}
}
private void resolveAnonymousInitializers(@NotNull BodiesResolveContext c) {
for (Map.Entry entry : c.getAnonymousInitializers().entrySet()) {
KtClassInitializer initializer = entry.getKey();
ClassDescriptorWithResolutionScopes descriptor = entry.getValue();
resolveAnonymousInitializer(c.getOuterDataFlowInfo(), initializer, descriptor);
}
}
public void resolveAnonymousInitializer(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull KtClassInitializer anonymousInitializer,
@NotNull ClassDescriptorWithResolutionScopes classDescriptor
) {
LexicalScope scopeForInitializers = classDescriptor.getScopeForInitializerResolution();
if (!classDescriptor.getConstructors().isEmpty()) {
KtExpression body = anonymousInitializer.getBody();
if (body != null) {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(
(KtDeclaration) anonymousInitializer.getParent().getParent(), trace);
expressionTypingServices.getType(scopeForInitializers, body, NO_EXPECTED_TYPE, outerDataFlowInfo, trace);
}
processModifiersOnInitializer(anonymousInitializer, scopeForInitializers);
}
else {
trace.report(ANONYMOUS_INITIALIZER_IN_INTERFACE.on(anonymousInitializer));
processModifiersOnInitializer(anonymousInitializer, scopeForInitializers);
}
}
private void processModifiersOnInitializer(@NotNull KtModifierListOwner owner, @NotNull LexicalScope scope) {
annotationChecker.check(owner, trace, null);
ModifierCheckerCore.INSTANCE$.check(owner, trace, null);
KtModifierList modifierList = owner.getModifierList();
if (modifierList == null) return;
annotationResolver.resolveAnnotationsWithArguments(scope, modifierList, trace);
}
private void resolvePrimaryConstructorParameters(@NotNull BodiesResolveContext c) {
for (Map.Entry entry : c.getDeclaredClasses().entrySet()) {
KtClassOrObject klass = entry.getKey();
ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
ConstructorDescriptor unsubstitutedPrimaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
if (unsubstitutedPrimaryConstructor != null) {
ForceResolveUtil.forceResolveAllContents(unsubstitutedPrimaryConstructor.getAnnotations());
LexicalScope parameterScope = getPrimaryConstructorParametersScope(classDescriptor.getScopeForClassHeaderResolution(),
unsubstitutedPrimaryConstructor);
valueParameterResolver.resolveValueParameters(klass.getPrimaryConstructorParameters(),
unsubstitutedPrimaryConstructor.getValueParameters(),
parameterScope, c.getOuterDataFlowInfo(), trace);
}
}
}
private static LexicalScope getPrimaryConstructorParametersScope(
LexicalScope originalScope,
final ConstructorDescriptor unsubstitutedPrimaryConstructor
) {
return new LexicalScopeImpl(originalScope, unsubstitutedPrimaryConstructor, false, null,
"Scope with value parameters of a constructor", RedeclarationHandler.DO_NOTHING,
new Function1() {
@Override
public Unit invoke(LexicalScopeImpl.InitializeHandler handler) {
for (ValueParameterDescriptor valueParameterDescriptor : unsubstitutedPrimaryConstructor.getValueParameters()) {
handler.addVariableDescriptor(valueParameterDescriptor);
}
return Unit.INSTANCE$;
}
});
}
private void resolveProperty(
@NotNull BodiesResolveContext c,
@Nullable LexicalScope parentScope,
@NotNull KtProperty property,
@NotNull PropertyDescriptor propertyDescriptor
) {
computeDeferredType(propertyDescriptor.getReturnType());
PreliminaryDeclarationVisitor.Companion.createForDeclaration(property, trace);
KtExpression initializer = property.getInitializer();
LexicalScope propertyScope = getScopeForProperty(c, property);
if (parentScope == null) {
parentScope = propertyScope;
}
if (initializer != null) {
resolvePropertyInitializer(c.getOuterDataFlowInfo(), property, propertyDescriptor, initializer, propertyScope);
}
KtExpression delegateExpression = property.getDelegateExpression();
if (delegateExpression != null) {
assert initializer == null : "Initializer should be null for delegated property : " + property.getText();
resolvePropertyDelegate(c.getOuterDataFlowInfo(), property, propertyDescriptor, delegateExpression, parentScope, propertyScope);
}
resolvePropertyAccessors(c, property, propertyDescriptor);
}
private void resolvePropertyDeclarationBodies(@NotNull BodiesResolveContext c) {
// Member properties
Set processed = Sets.newHashSet();
for (Map.Entry entry : c.getDeclaredClasses().entrySet()) {
if (!(entry.getKey() instanceof KtClass)) continue;
KtClass ktClass = (KtClass) entry.getKey();
ClassDescriptorWithResolutionScopes classDescriptor = entry.getValue();
for (KtProperty property : ktClass.getProperties()) {
PropertyDescriptor propertyDescriptor = c.getProperties().get(property);
assert propertyDescriptor != null;
resolveProperty(c, classDescriptor.getScopeForMemberDeclarationResolution(), property, propertyDescriptor);
processed.add(property);
}
}
// Top-level properties & properties of objects
for (Map.Entry entry : c.getProperties().entrySet()) {
KtProperty property = entry.getKey();
if (processed.contains(property)) continue;
PropertyDescriptor propertyDescriptor = entry.getValue();
resolveProperty(c, null, property, propertyDescriptor);
}
}
private LexicalScope makeScopeForPropertyAccessor(
@NotNull BodiesResolveContext c, @NotNull KtPropertyAccessor accessor, @NotNull PropertyDescriptor descriptor
) {
LexicalScope accessorDeclaringScope = c.getDeclaringScope(accessor);
assert accessorDeclaringScope != null : "Scope for accessor " + accessor.getText() + " should exists";
return JetScopeUtils.makeScopeForPropertyAccessor(descriptor, accessorDeclaringScope, trace);
}
public void resolvePropertyAccessors(
@NotNull BodiesResolveContext c,
@NotNull KtProperty property,
@NotNull PropertyDescriptor propertyDescriptor
) {
ObservableBindingTrace fieldAccessTrackingTrace = createFieldTrackingTrace(propertyDescriptor);
KtPropertyAccessor getter = property.getGetter();
PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter();
if (getter != null && getterDescriptor != null) {
LexicalScope accessorScope = makeScopeForPropertyAccessor(c, getter, propertyDescriptor);
ForceResolveUtil.forceResolveAllContents(getterDescriptor.getAnnotations());
resolveFunctionBody(c.getOuterDataFlowInfo(), fieldAccessTrackingTrace, getter, getterDescriptor, accessorScope);
}
KtPropertyAccessor setter = property.getSetter();
PropertySetterDescriptor setterDescriptor = propertyDescriptor.getSetter();
if (setter != null && setterDescriptor != null) {
LexicalScope accessorScope = makeScopeForPropertyAccessor(c, setter, propertyDescriptor);
ForceResolveUtil.forceResolveAllContents(setterDescriptor.getAnnotations());
resolveFunctionBody(c.getOuterDataFlowInfo(), fieldAccessTrackingTrace, setter, setterDescriptor, accessorScope);
}
}
private ObservableBindingTrace createFieldTrackingTrace(final PropertyDescriptor propertyDescriptor) {
return new ObservableBindingTrace(trace).addHandler(BindingContext.REFERENCE_TARGET, new ObservableBindingTrace.RecordHandler() {
@Override
public void handleRecord(WritableSlice slice, KtReferenceExpression expression, DeclarationDescriptor descriptor) {
if (expression instanceof KtSimpleNameExpression) {
KtSimpleNameExpression simpleNameExpression = (KtSimpleNameExpression) expression;
if (simpleNameExpression.getReferencedNameElementType() == KtTokens.FIELD_IDENTIFIER) {
// This check may be considered redundant as long as $x is only accessible from accessors to $x
if (descriptor == propertyDescriptor) { // TODO : original?
trace.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor); // TODO: this trace?
trace.report(Errors.BACKING_FIELD_OLD_SYNTAX.on(simpleNameExpression));
}
}
if (descriptor instanceof SyntheticFieldDescriptor) {
trace.record(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor);
}
}
}
});
}
public void resolvePropertyDelegate(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull KtProperty jetProperty,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull KtExpression delegateExpression,
@NotNull LexicalScope parentScopeForAccessor,
@NotNull LexicalScope propertyScope
) {
KtPropertyAccessor getter = jetProperty.getGetter();
if (getter != null && getter.hasBody()) {
trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(getter));
}
KtPropertyAccessor setter = jetProperty.getSetter();
if (setter != null && setter.hasBody()) {
trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(setter));
}
LexicalScope propertyDeclarationInnerScope = JetScopeUtils.getPropertyDeclarationInnerScopeForInitializer(
propertyDescriptor, propertyScope, propertyDescriptor.getTypeParameters(), null, trace);
LexicalScope accessorScope = JetScopeUtils.makeScopeForPropertyAccessor(
propertyDescriptor, parentScopeForAccessor, trace);
KotlinType delegateType = delegatedPropertyResolver.resolveDelegateExpression(
delegateExpression, jetProperty, propertyDescriptor, propertyDeclarationInnerScope, accessorScope, trace,
outerDataFlowInfo);
delegatedPropertyResolver.resolveDelegatedPropertyGetMethod(propertyDescriptor, delegateExpression, delegateType,
trace, accessorScope);
if (jetProperty.isVar()) {
delegatedPropertyResolver.resolveDelegatedPropertySetMethod(propertyDescriptor, delegateExpression, delegateType,
trace, accessorScope);
}
delegatedPropertyResolver.resolveDelegatedPropertyPDMethod(propertyDescriptor, delegateExpression, delegateType,
trace, accessorScope);
}
public void resolvePropertyInitializer(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull KtProperty property,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull KtExpression initializer,
@NotNull LexicalScope scope
) {
LexicalScope propertyDeclarationInnerScope = JetScopeUtils.getPropertyDeclarationInnerScopeForInitializer(
propertyDescriptor, scope, propertyDescriptor.getTypeParameters(), null, trace);
KotlinType expectedTypeForInitializer = property.getTypeReference() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE;
if (propertyDescriptor.getCompileTimeInitializer() == null) {
expressionTypingServices.getType(propertyDeclarationInnerScope, initializer, expectedTypeForInitializer,
outerDataFlowInfo, trace);
}
}
@NotNull
private static LexicalScope getScopeForProperty(@NotNull BodiesResolveContext c, @NotNull KtProperty property) {
LexicalScope scope = c.getDeclaringScope(property);
assert scope != null : "Scope for property " + property.getText() + " should exists";
return scope;
}
private void resolveFunctionBodies(@NotNull BodiesResolveContext c) {
for (Map.Entry entry : c.getFunctions().entrySet()) {
KtNamedFunction declaration = entry.getKey();
LexicalScope scope = c.getDeclaringScope(declaration);
assert scope != null : "Scope is null: " + PsiUtilsKt.getElementTextWithContext(declaration);
if (!c.getTopDownAnalysisMode().isLocalDeclarations() && !(bodyResolveCache instanceof BodyResolveCache.ThrowException) &&
expressionTypingServices.getStatementFilter() != StatementFilter.NONE) {
bodyResolveCache.resolveFunctionBody(declaration).addOwnDataTo(trace, true);
}
else {
resolveFunctionBody(c.getOuterDataFlowInfo(), trace, declaration, entry.getValue(), scope);
}
}
}
public void resolveFunctionBody(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace,
@NotNull KtDeclarationWithBody function,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull LexicalScope declaringScope
) {
computeDeferredType(functionDescriptor.getReturnType());
resolveFunctionBody(outerDataFlowInfo, trace, function, functionDescriptor, declaringScope, null, CallChecker.DoNothing.INSTANCE$);
assert functionDescriptor.getReturnType() != null;
}
public void resolveFunctionBody(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace,
@NotNull KtDeclarationWithBody function,
@NotNull FunctionDescriptor functionDescriptor,
@NotNull LexicalScope scope,
@Nullable Function1 beforeBlockBody,
@NotNull CallChecker callChecker
) {
PreliminaryDeclarationVisitor.Companion.createForDeclaration(function, trace);
LexicalScope innerScope = FunctionDescriptorUtil.getFunctionInnerScope(scope, functionDescriptor, trace);
List valueParameters = function.getValueParameters();
List valueParameterDescriptors = functionDescriptor.getValueParameters();
valueParameterResolver.resolveValueParameters(
valueParameters, valueParameterDescriptors,
ExpressionTypingContext.newContext(
trace, innerScope, outerDataFlowInfo, NO_EXPECTED_TYPE, callChecker)
);
// Synthetic "field" creation
if (functionDescriptor instanceof PropertyAccessorDescriptor && functionDescriptor.getExtensionReceiverParameter() == null) {
PropertyAccessorDescriptor accessorDescriptor = (PropertyAccessorDescriptor) functionDescriptor;
KtProperty property = (KtProperty) function.getParent();
final SyntheticFieldDescriptor fieldDescriptor = new SyntheticFieldDescriptor(accessorDescriptor, property);
innerScope = new LexicalScopeImpl(innerScope, functionDescriptor, true, null,
"Accessor inner scope with synthetic field",
RedeclarationHandler.DO_NOTHING, new Function1() {
@Override
public Unit invoke(LexicalScopeImpl.InitializeHandler handler) {
handler.addVariableOrClassDescriptor(fieldDescriptor);
return Unit.INSTANCE$;
}
});
// Check parameter name shadowing
for (KtParameter parameter : function.getValueParameters()) {
if (SyntheticFieldDescriptor.NAME.equals(parameter.getNameAsName())) {
trace.report(Errors.ACCESSOR_PARAMETER_NAME_SHADOWING.on(parameter));
}
}
}
DataFlowInfo dataFlowInfo = null;
if (beforeBlockBody != null) {
dataFlowInfo = beforeBlockBody.invoke(innerScope);
}
if (function.hasBody()) {
expressionTypingServices.checkFunctionReturnType(
innerScope, function, functionDescriptor, dataFlowInfo != null ? dataFlowInfo : outerDataFlowInfo, null, trace);
}
assert functionDescriptor.getReturnType() != null;
}
public void resolveConstructorParameterDefaultValuesAndAnnotations(
@NotNull DataFlowInfo outerDataFlowInfo,
@NotNull BindingTrace trace,
@NotNull KtClass klass,
@NotNull ConstructorDescriptor constructorDescriptor,
@NotNull LexicalScope declaringScope
) {
List valueParameters = klass.getPrimaryConstructorParameters();
List valueParameterDescriptors = constructorDescriptor.getValueParameters();
LexicalScope scope = getPrimaryConstructorParametersScope(declaringScope, constructorDescriptor);
valueParameterResolver.resolveValueParameters(valueParameters, valueParameterDescriptors, scope, outerDataFlowInfo, trace);
}
private static void computeDeferredType(KotlinType type) {
// handle type inference loop: function or property body contains a reference to itself
// fun f() = { f() }
// val x = x
// type resolution must be started before body resolution
if (type instanceof DeferredType) {
DeferredType deferredType = (DeferredType) type;
if (!deferredType.isComputed()) {
deferredType.getDelegate();
}
}
}
private void computeDeferredTypes() {
Collection> deferredTypes = trace.getKeys(DEFERRED_TYPE);
if (deferredTypes.isEmpty()) {
return;
}
// +1 is a work around against new Queue(0).addLast(...) bug // stepan.koltsov@ 2011-11-21
final Queue queue = new Queue(deferredTypes.size() + 1);
trace.addHandler(DEFERRED_TYPE, new ObservableBindingTrace.RecordHandler, Boolean>() {
@Override
public void handleRecord(WritableSlice, Boolean> deferredTypeKeyDeferredTypeWritableSlice, Box key, Boolean value) {
queue.addLast(key.getData());
}
});
for (Box deferredType : deferredTypes) {
queue.addLast(deferredType.getData());
}
while (!queue.isEmpty()) {
DeferredType deferredType = queue.pullFirst();
if (!deferredType.isComputed()) {
try {
deferredType.getDelegate(); // to compute
}
catch (ReenteringLazyValueComputationException e) {
// A problem should be reported while computing the type
}
}
}
}
}