public void resolvePropertyAccessors( @NotNull BodiesResolveContext c, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) { ObservableBindingTrace fieldAccessTrackingTrace = createFieldTrackingTrace(propertyDescriptor); JetPropertyAccessor 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); } JetPropertyAccessor 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 void checkAccessors( @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) { for (JetPropertyAccessor accessor : property.getAccessors()) { PropertyAccessorDescriptor propertyAccessorDescriptor = accessor.isGetter() ? propertyDescriptor.getGetter() : propertyDescriptor.getSetter(); assert propertyAccessorDescriptor != null : "No property accessor descriptor for " + property.getText(); modifiersChecker.checkModifiersForDeclaration(accessor, propertyAccessorDescriptor); modifiersChecker.reportIllegalModalityModifiers(accessor); } JetPropertyAccessor getter = property.getGetter(); PropertyGetterDescriptor getterDescriptor = propertyDescriptor.getGetter(); JetModifierList getterModifierList = getter != null ? getter.getModifierList() : null; if (getterModifierList != null && getterDescriptor != null) { Map<JetModifierKeywordToken, ASTNode> nodes = ModifiersChecker.getNodesCorrespondingToModifiers( getterModifierList, Sets.newHashSet( JetTokens.PUBLIC_KEYWORD, JetTokens.PROTECTED_KEYWORD, JetTokens.PRIVATE_KEYWORD, JetTokens.INTERNAL_KEYWORD)); if (getterDescriptor.getVisibility() != propertyDescriptor.getVisibility()) { for (ASTNode node : nodes.values()) { trace.report(Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY.on(node.getPsi())); } } else { for (ASTNode node : nodes.values()) { trace.report(Errors.REDUNDANT_MODIFIER_IN_GETTER.on(node.getPsi())); } } } }
private void resolveProperty( @NotNull BodiesResolveContext c, @Nullable LexicalScope parentScope, @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) { computeDeferredType(propertyDescriptor.getReturnType()); JetExpression initializer = property.getInitializer(); LexicalScope propertyScope = getScopeForProperty(c, property); if (parentScope == null) { parentScope = propertyScope; } if (initializer != null) { resolvePropertyInitializer( c.getOuterDataFlowInfo(), property, propertyDescriptor, initializer, propertyScope); } JetExpression 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 static void forceResolvePackageDeclarations( @NotNull Collection<JetFile> files, @NotNull KotlinCodeAnalyzer session) { for (JetFile file : files) { // SCRIPT: not supported if (file.isScript()) continue; FqName packageFqName = file.getPackageFqName(); // make sure we create a package descriptor PackageViewDescriptor packageDescriptor = session.getModuleDescriptor().getPackage(packageFqName); if (packageDescriptor.isEmpty()) { LOG.warn( "No descriptor found for package " + packageFqName + " in file " + file.getName() + "\n" + file.getText()); session.forceResolveAll(); continue; } for (JetDeclaration declaration : file.getDeclarations()) { if (declaration instanceof JetFunction) { JetFunction jetFunction = (JetFunction) declaration; Name name = jetFunction.getNameAsSafeName(); Collection<FunctionDescriptor> functions = packageDescriptor.getMemberScope().getFunctions(name, LookupLocation.NO_LOCATION); for (FunctionDescriptor descriptor : functions) { ForceResolveUtil.forceResolveAllContents(descriptor); } } else if (declaration instanceof JetProperty) { JetProperty jetProperty = (JetProperty) declaration; Name name = jetProperty.getNameAsSafeName(); Collection<VariableDescriptor> properties = packageDescriptor.getMemberScope().getProperties(name, LookupLocation.NO_LOCATION); for (VariableDescriptor descriptor : properties) { ForceResolveUtil.forceResolveAllContents(descriptor); } } else if (declaration instanceof JetClassOrObject) { // Do nothing: we are not interested in classes } else { LOG.error( "Unsupported declaration kind: " + declaration + " in file " + file.getName() + "\n" + file.getText()); } } } }
// Source code is taken from org.jetbrains.kotlin.idea.projectView.JetDeclarationTreeNode, // updateImple() private String getPresentableElement(JetElement declaration) { String text = ""; if (declaration != null) { text = declaration.getName(); if (text == null) return ""; if (declaration instanceof JetClassInitializer) { text = CLASS_INITIALIZER; } else if (declaration instanceof JetProperty) { JetProperty property = (JetProperty) declaration; JetTypeReference ref = property.getTypeReference(); if (ref != null) { text += " "; text += ":"; text += " "; text += ref.getText(); } } else if (declaration instanceof JetFunction) { JetFunction function = (JetFunction) declaration; JetTypeReference receiverTypeRef = function.getReceiverTypeReference(); if (receiverTypeRef != null) { text = receiverTypeRef.getText() + "." + text; } text += "("; List<JetParameter> parameters = function.getValueParameters(); for (JetParameter parameter : parameters) { if (parameter.getName() != null) { text += parameter.getName(); text += " "; text += ":"; text += " "; } JetTypeReference typeReference = parameter.getTypeReference(); if (typeReference != null) { text += typeReference.getText(); } text += ", "; } if (parameters.size() > 0) text = text.substring(0, text.length() - 2); text += ")"; JetTypeReference typeReference = function.getTypeReference(); if (typeReference != null) { text += " "; text += ":"; text += " "; text += typeReference.getText(); } } } return text; }
@NotNull private static LexicalScope getScopeForProperty( @NotNull BodiesResolveContext c, @NotNull JetProperty property) { LexicalScope scope = c.getDeclaringScope(property); assert scope != null : "Scope for property " + property.getText() + " should exists"; return scope; }
public void resolvePropertyDelegate( @NotNull DataFlowInfo outerDataFlowInfo, @NotNull JetProperty jetProperty, @NotNull PropertyDescriptor propertyDescriptor, @NotNull JetExpression delegateExpression, @NotNull LexicalScope parentScopeForAccessor, @NotNull LexicalScope propertyScope) { JetPropertyAccessor getter = jetProperty.getGetter(); if (getter != null && getter.hasBody()) { trace.report(ACCESSOR_FOR_DELEGATED_PROPERTY.on(getter)); } JetPropertyAccessor 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); JetType 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 JetProperty property, @NotNull PropertyDescriptor propertyDescriptor, @NotNull JetExpression initializer, @NotNull LexicalScope scope) { LexicalScope propertyDeclarationInnerScope = JetScopeUtils.getPropertyDeclarationInnerScopeForInitializer( propertyDescriptor, scope, propertyDescriptor.getTypeParameters(), null, trace); JetType expectedTypeForInitializer = property.getTypeReference() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE; if (propertyDescriptor.getCompileTimeInitializer() == null) { expressionTypingServices.getType( propertyDeclarationInnerScope, initializer, expectedTypeForInitializer, outerDataFlowInfo, trace); } }
private void checkPropertyAbstractness( @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor, @NotNull ClassDescriptor classDescriptor) { JetPropertyAccessor getter = property.getGetter(); JetPropertyAccessor setter = property.getSetter(); JetModifierList modifierList = property.getModifierList(); ASTNode abstractNode = modifierList != null ? modifierList.getModifierNode(JetTokens.ABSTRACT_KEYWORD) : null; if (abstractNode != null) { // has abstract modifier if (!classCanHaveAbstractMembers(classDescriptor)) { String name = property.getName(); trace.report( ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on( property, name != null ? name : "", classDescriptor)); return; } if (classDescriptor.getKind() == ClassKind.INTERFACE) { trace.report(ABSTRACT_MODIFIER_IN_TRAIT.on(property)); } } if (propertyDescriptor.getModality() == Modality.ABSTRACT) { JetExpression initializer = property.getInitializer(); if (initializer != null) { trace.report(ABSTRACT_PROPERTY_WITH_INITIALIZER.on(initializer)); } JetPropertyDelegate delegate = property.getDelegate(); if (delegate != null) { trace.report(ABSTRACT_DELEGATED_PROPERTY.on(delegate)); } if (getter != null && getter.hasBody()) { trace.report(ABSTRACT_PROPERTY_WITH_GETTER.on(getter)); } if (setter != null && setter.hasBody()) { trace.report(ABSTRACT_PROPERTY_WITH_SETTER.on(setter)); } } }
private void checkPropertyInitializer( @NotNull JetProperty property, @NotNull PropertyDescriptor propertyDescriptor) { JetPropertyAccessor getter = property.getGetter(); JetPropertyAccessor setter = property.getSetter(); boolean hasAccessorImplementation = (getter != null && getter.hasBody()) || (setter != null && setter.hasBody()); if (propertyDescriptor.getModality() == Modality.ABSTRACT) { if (!property.hasDelegateExpressionOrInitializer() && property.getTypeReference() == null) { trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property)); } return; } DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration(); boolean inTrait = containingDeclaration instanceof ClassDescriptor && ((ClassDescriptor) containingDeclaration).getKind() == ClassKind.INTERFACE; JetExpression initializer = property.getInitializer(); JetPropertyDelegate delegate = property.getDelegate(); boolean backingFieldRequired = Boolean.TRUE.equals( trace .getBindingContext() .get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor)); if (inTrait && backingFieldRequired && hasAccessorImplementation) { trace.report(BACKING_FIELD_IN_TRAIT.on(property)); } if (initializer == null && delegate == null) { boolean error = false; if (backingFieldRequired && !inTrait && Boolean.TRUE.equals( trace.getBindingContext().get(BindingContext.IS_UNINITIALIZED, propertyDescriptor))) { if (!(containingDeclaration instanceof ClassDescriptor) || hasAccessorImplementation) { error = true; trace.report(MUST_BE_INITIALIZED.on(property)); } else { error = true; trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property)); } } if (!error && property.getTypeReference() == null) { trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property)); } if (inTrait && property.hasModifier(JetTokens.FINAL_KEYWORD) && backingFieldRequired) { trace.report(FINAL_PROPERTY_IN_TRAIT.on(property)); } return; } if (inTrait) { if (delegate != null) { trace.report(DELEGATED_PROPERTY_IN_TRAIT.on(delegate)); } else { trace.report(PROPERTY_INITIALIZER_IN_TRAIT.on(initializer)); } } else if (delegate == null) { if (!backingFieldRequired) { trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer)); } else if (property.getReceiverTypeReference() != null) { trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer)); } } }
@NotNull @Override protected List<IntentionAction> doCreateActions(@NotNull Diagnostic diagnostic) { List<IntentionAction> actions = new LinkedList<IntentionAction>(); BindingContext context = ResolutionUtils.analyzeFully((JetFile) diagnostic.getPsiFile()); PsiElement diagnosticElement = diagnostic.getPsiElement(); if (!(diagnosticElement instanceof JetExpression)) { LOG.error("Unexpected element: " + diagnosticElement.getText()); return Collections.emptyList(); } JetExpression expression = (JetExpression) diagnosticElement; JetType expectedType; JetType expressionType; if (diagnostic.getFactory() == Errors.TYPE_MISMATCH) { DiagnosticWithParameters2<JetExpression, JetType, JetType> diagnosticWithParameters = Errors.TYPE_MISMATCH.cast(diagnostic); expectedType = diagnosticWithParameters.getA(); expressionType = diagnosticWithParameters.getB(); } else if (diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE) { DiagnosticWithParameters1<JetConstantExpression, JetType> diagnosticWithParameters = Errors.NULL_FOR_NONNULL_TYPE.cast(diagnostic); expectedType = diagnosticWithParameters.getA(); expressionType = TypeUtilsKt.makeNullable(expectedType); } else if (diagnostic.getFactory() == Errors.CONSTANT_EXPECTED_TYPE_MISMATCH) { DiagnosticWithParameters2<JetConstantExpression, String, JetType> diagnosticWithParameters = Errors.CONSTANT_EXPECTED_TYPE_MISMATCH.cast(diagnostic); expectedType = diagnosticWithParameters.getB(); expressionType = context.getType(expression); if (expressionType == null) { LOG.error("No type inferred: " + expression.getText()); return Collections.emptyList(); } } else { LOG.error("Unexpected diagnostic: " + DefaultErrorMessages.render(diagnostic)); return Collections.emptyList(); } // We don't want to cast a cast or type-asserted expression: if (!(expression instanceof JetBinaryExpressionWithTypeRHS) && !(expression.getParent() instanceof JetBinaryExpressionWithTypeRHS)) { actions.add(new CastExpressionFix(expression, expectedType)); } // Property initializer type mismatch property type: JetProperty property = PsiTreeUtil.getParentOfType(expression, JetProperty.class); if (property != null) { JetPropertyAccessor getter = property.getGetter(); JetExpression initializer = property.getInitializer(); if (QuickFixUtil.canEvaluateTo(initializer, expression) || (getter != null && QuickFixUtil.canFunctionOrGetterReturnExpression( property.getGetter(), expression))) { LexicalScope scope = CorePackage.getResolutionScope( property, context, ResolutionUtils.getResolutionFacade(property)); JetType typeToInsert = TypeUtils.approximateWithResolvableType(expressionType, scope, false); actions.add(new ChangeVariableTypeFix(property, typeToInsert)); } } PsiElement expressionParent = expression.getParent(); // Mismatch in returned expression: JetCallableDeclaration function = expressionParent instanceof JetReturnExpression ? BindingContextUtilPackage.getTargetFunction( (JetReturnExpression) expressionParent, context) : PsiTreeUtil.getParentOfType(expression, JetFunction.class, true); if (function instanceof JetFunction && QuickFixUtil.canFunctionOrGetterReturnExpression(function, expression)) { LexicalScope scope = CorePackage.getResolutionScope( function, context, ResolutionUtils.getResolutionFacade(function)); JetType typeToInsert = TypeUtils.approximateWithResolvableType(expressionType, scope, false); actions.add(new ChangeFunctionReturnTypeFix((JetFunction) function, typeToInsert)); } // Fixing overloaded operators: if (expression instanceof JetOperationExpression) { ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context); if (resolvedCall != null) { JetFunction declaration = getFunctionDeclaration(resolvedCall); if (declaration != null) { actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType)); } } } // Change function return type when TYPE_MISMATCH is reported on call expression: if (expression instanceof JetCallExpression) { ResolvedCall<?> resolvedCall = CallUtilPackage.getResolvedCall(expression, context); if (resolvedCall != null) { JetFunction declaration = getFunctionDeclaration(resolvedCall); if (declaration != null) { actions.add(new ChangeFunctionReturnTypeFix(declaration, expectedType)); } } } ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilPackage.getParentResolvedCall(expression, context, true); if (resolvedCall != null) { // to fix 'type mismatch' on 'if' branches // todo: the same with 'when' JetExpression parentIf = QuickFixUtil.getParentIfForBranch(expression); JetExpression argumentExpression = (parentIf != null) ? parentIf : expression; ValueArgument valueArgument = CallUtilPackage.getValueArgumentForExpression(resolvedCall.getCall(), argumentExpression); if (valueArgument != null) { JetParameter correspondingParameter = QuickFixUtil.getParameterDeclarationForValueArgument(resolvedCall, valueArgument); JetType valueArgumentType = diagnostic.getFactory() == Errors.NULL_FOR_NONNULL_TYPE ? expressionType : context.getType(valueArgument.getArgumentExpression()); if (correspondingParameter != null && valueArgumentType != null) { JetCallableDeclaration callable = PsiTreeUtil.getParentOfType( correspondingParameter, JetCallableDeclaration.class, true); LexicalScope scope = callable != null ? CorePackage.getResolutionScope( callable, context, ResolutionUtils.getResolutionFacade(callable)) : null; JetType typeToInsert = TypeUtils.approximateWithResolvableType(valueArgumentType, scope, true); actions.add(new ChangeParameterTypeFix(correspondingParameter, typeToInsert)); } } } return actions; }