diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index dd77c5069a5..e5d49d0c837 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -44,9 +44,12 @@ public interface BindingContext { WritableSlice PROCESSED = Slices.createSimpleSetSlice("PROCESSED"); WritableSlice STATEMENT = Slices.createRemovableSetSlice("STATEMENT"); WritableSlice DELEGATED = Slices.createRemovableSetSlice("DELEGATED"); + + WritableSlice MUST_BE_WRAPPED_IN_A_REF = Slices.createSimpleSetSlice("MUST_BE_WRAPPED_IN_A_REF"); enum DeferredTypeKey {DEFERRED_TYPE_KEY} WritableSlice> DEFERRED_TYPES = Slices.createSimpleSlice("DEFERRED_TYPES"); + WritableSlice DEFERRED_TYPE = new CollectionSliceWrapper(DEFERRED_TYPES, CommonSuppliers.getArrayListSupplier()); WritableSlice BACKING_FIELD_REQUIRED = new Slices.SetSlice("BACKING_FIELD_REQUIRED", RewritePolicy.DO_NOTHING) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index e8b0a6f6bee..5e3eaa10af6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -2815,13 +2815,20 @@ public class JetTypeInferrer { // } } if (left instanceof JetSimpleNameExpression) { - JetSimpleNameExpression variable = (JetSimpleNameExpression) left; - String referencedName = variable.getReferencedName(); - if (variable.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER + JetSimpleNameExpression simpleName = (JetSimpleNameExpression) left; + String referencedName = simpleName.getReferencedName(); + if (simpleName.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && referencedName != null) { PropertyDescriptor property = context.scope.getPropertyByFieldReference(referencedName); if (property != null) { - context.trace.record(BindingContext.VARIABLE_ASSIGNMENT, variable, property); + context.trace.record(BindingContext.VARIABLE_ASSIGNMENT, simpleName, property); + } + } + VariableDescriptor variable = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), simpleName); + if (variable != null) { + DeclarationDescriptor containingDeclaration = variable.getContainingDeclaration(); + if (context.scope.getContainingDeclaration() != containingDeclaration && containingDeclaration instanceof CallableDescriptor) { + context.trace.record(MUST_BE_WRAPPED_IN_A_REF, variable); } } } diff --git a/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java b/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java index 79903d2774b..215a4a63f8a 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java +++ b/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java @@ -97,6 +97,15 @@ public class JetHighlighter extends SyntaxHighlighterBase { JET_AUTO_CAST_EXPRESSION = TextAttributesKey.createTextAttributesKey("JET.AUTO.CAST.EXPRESSION", clone); } + public static final TextAttributesKey JET_WRAPPED_INTO_REF; + + static { + TextAttributes attributes = new TextAttributes(); + attributes.setEffectType(EffectType.LINE_UNDERSCORE); + attributes.setEffectColor(Color.BLACK); + JET_WRAPPED_INTO_REF = TextAttributesKey.createTextAttributesKey("JET.WRAPPED.INTO.REF", attributes); + } + public static final TextAttributesKey JET_AUTOCREATED_IT; static { diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java index a845fd21838..85c004ef2de 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.plugin.annotations; import com.google.common.collect.Sets; import com.intellij.codeInsight.intention.IntentionAction; import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.lang.ASTNode; import com.intellij.lang.annotation.Annotation; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; @@ -117,9 +118,28 @@ public class JetPsiChecker implements Annotator { holder.createInfoAnnotation(expression, "Automatically declared based on the expected type").setTextAttributes(JetHighlighter.JET_AUTOCREATED_IT); } } + + markVariableAsWrappedIfNeeded(expression.getNode(), target); super.visitSimpleNameExpression(expression); } + private void markVariableAsWrappedIfNeeded(ASTNode node, DeclarationDescriptor target) { + if (target instanceof VariableDescriptor) { + VariableDescriptor variableDescriptor = (VariableDescriptor) target; + if (bindingContext.get(MUST_BE_WRAPPED_IN_A_REF, variableDescriptor)) { + holder.createInfoAnnotation(node, "Wrapped into a ref-object to be modifier when captured in a closure").setTextAttributes(JetHighlighter.JET_WRAPPED_INTO_REF); + } + + } + } + + @Override + public void visitProperty(JetProperty property) { + DeclarationDescriptor declarationDescriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, property); + markVariableAsWrappedIfNeeded(property.getNameIdentifier().getNode(), declarationDescriptor); + super.visitProperty(property); + } + @Override public void visitExpression(JetExpression expression) { JetType autoCast = bindingContext.get(AUTOCAST, expression); diff --git a/idea/testData/checker/infos/WrapIntoRef.jet b/idea/testData/checker/infos/WrapIntoRef.jet new file mode 100644 index 00000000000..47613236fa0 --- /dev/null +++ b/idea/testData/checker/infos/WrapIntoRef.jet @@ -0,0 +1,18 @@ +fun notContainsBreak() { + var a = 1 + val v = { + a = 2 + } + + var x = 1 + val b = object { + fun foo() { + x = 2 + } + } + + var y = 1 + fun foo() { + y = 1 + } +}