diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java
index 214564712db7..841070ed0cad 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/annotator/GroovyAnnotator.java
@@ -40,6 +40,10 @@ import com.intellij.pom.PomTarget;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightElement;
import com.intellij.psi.infos.CandidateInfo;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.LocalSearchScope;
+import com.intellij.psi.search.SearchScope;
+import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.search.searches.SuperMethodsSearch;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.MethodSignature;
@@ -189,6 +193,10 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
if (resolved instanceof PsiMember) {
highlightMemberResolved(myHolder, referenceExpression, ((PsiMember)resolved));
}
+ else if (resolved instanceof GrVariable) {
+ highlightVariable((GrVariable)resolved, getElementToHighlight(referenceExpression));
+ }
+
/*if (!resolveResult.isAccessible()) {
String message = GroovyBundle.message("cannot.access", referenceExpression.getReferenceName());
final Annotation annotation = myHolder.createWarningAnnotation(getElementToHighlight(referenceExpression), message);
@@ -262,6 +270,35 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
}
}
+ private void highlightVariable(GrVariable variable, PsiElement toHighlight) {
+ Annotation annotation = myHolder.createInfoAnnotation(toHighlight, null);
+ boolean reassigned = isReassigned(variable);
+ if (variable instanceof GrParameter) {
+ annotation
+ .setTextAttributes(reassigned ? DefaultHighlighter.REASSIGNED_PARAMETER : DefaultHighlighter.PARAMETER);
+ } else {
+ annotation
+ .setTextAttributes(reassigned ? DefaultHighlighter.REASSIGNED_LOCAL_VARIABLE : DefaultHighlighter.LOCAL_VARIABLE);
+ }
+ }
+
+ private static boolean isReassigned(GrVariable var) {
+ PsiMethod method = PsiTreeUtil.getParentOfType(var, PsiMethod.class);
+ boolean hasAssignment = var.getInitializerGroovy() != null || var instanceof GrParameter;
+ SearchScope scope = method == null ? GlobalSearchScope.projectScope(var.getProject()) : new LocalSearchScope(method);
+ for (PsiReference reference : ReferencesSearch.search(var, scope).findAll()) {
+ if (reference instanceof GrReferenceExpression &&
+ (PsiUtil.isLValue((GrReferenceExpression)reference) ||
+ ((GrReferenceExpression)reference).getParent() instanceof GrPostfixExpression)) {
+ if (hasAssignment) {
+ return true;
+ }
+ hasAssignment = true;
+ }
+ }
+ return false;
+ }
+
public static boolean shouldHighlightAsUnresolved(@NotNull GrReferenceExpression referenceExpression) {
PsiElement refNameElement = referenceExpression.getReferenceNameElement();
if (refNameElement != null && referenceExpression.getQualifier() == null) {
@@ -485,6 +522,10 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
@Override
public void visitMethod(GrMethod method) {
+ if (!method.isConstructor()) {
+ myHolder.createInfoAnnotation(method.getNameIdentifierGroovy(), null).setTextAttributes(DefaultHighlighter.METHOD_DECLARATION);
+ }
+
checkMethodDefinitionModifiers(myHolder, method);
checkMethodWithTypeParamsShouldHaveReturnType(myHolder, method);
checkInnerMethod(myHolder, method);
@@ -576,6 +617,8 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
checkName(variable);
if (variable instanceof GrMember) {
highlightMember(myHolder, ((GrMember)variable));
+ } else {
+ highlightVariable(variable, variable.getNameIdentifierGroovy());
}
PsiNamedElement duplicate = ResolveUtil
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/DefaultHighlighter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/DefaultHighlighter.java
index 4fe8253617cd..01b3c3dde025 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/DefaultHighlighter.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/DefaultHighlighter.java
@@ -94,6 +94,18 @@ public class DefaultHighlighter {
public static TextAttributesKey ANNOTATION = TextAttributesKey.createTextAttributesKey(ANNOTATION_ID,
HighlightInfoType.ANNOTATION_NAME.getAttributesKey().getDefaultAttributes());
+ public static TextAttributesKey LOCAL_VARIABLE = TextAttributesKey.createTextAttributesKey("Groovy var",
+ HighlightInfoType.LOCAL_VARIABLE.getAttributesKey().getDefaultAttributes());
+ public static TextAttributesKey REASSIGNED_LOCAL_VARIABLE = TextAttributesKey.createTextAttributesKey("Groovy reassigned var",
+ HighlightInfoType.REASSIGNED_LOCAL_VARIABLE.getAttributesKey().getDefaultAttributes());
+ public static TextAttributesKey PARAMETER = TextAttributesKey.createTextAttributesKey("Groovy parameter",
+ HighlightInfoType.PARAMETER.getAttributesKey().getDefaultAttributes());
+ public static TextAttributesKey REASSIGNED_PARAMETER = TextAttributesKey.createTextAttributesKey("Groovy reassigned parameter",
+ HighlightInfoType.REASSIGNED_PARAMETER.getAttributesKey().getDefaultAttributes());
+
+ public static TextAttributesKey METHOD_DECLARATION = TextAttributesKey.createTextAttributesKey("Groovy method declaration",
+ HighlightInfoType.METHOD_DECLARATION.getAttributesKey().getDefaultAttributes());
+
public static TextAttributesKey INSTANCE_FIELD = TextAttributesKey.createTextAttributesKey(INSTANCE_FIELD_ID,
HighlightInfoType.INSTANCE_FIELD.getAttributesKey().getDefaultAttributes());
diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyColorsAndFontsPage.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyColorsAndFontsPage.java
index bd6bbb63d9ab..19a5b080e094 100644
--- a/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyColorsAndFontsPage.java
+++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/highlighter/GroovyColorsAndFontsPage.java
@@ -67,10 +67,15 @@ public class GroovyColorsAndFontsPage implements ColorSettingsPage {
new AttributesDescriptor("Unresolved reference access", DefaultHighlighter.UNRESOLVED_ACCESS),
new AttributesDescriptor("List/map to object conversion", DefaultHighlighter.LITERAL_CONVERSION),
new AttributesDescriptor("Annotation", DefaultHighlighter.ANNOTATION),
+ new AttributesDescriptor("Local variable", DefaultHighlighter.LOCAL_VARIABLE),
+ new AttributesDescriptor("Reassigned local variable", DefaultHighlighter.REASSIGNED_LOCAL_VARIABLE),
+ new AttributesDescriptor("Parameter", DefaultHighlighter.PARAMETER),
+ new AttributesDescriptor("Reassigned parameter", DefaultHighlighter.REASSIGNED_PARAMETER),
new AttributesDescriptor("Static field", DefaultHighlighter.STATIC_FIELD),
new AttributesDescriptor("Instance field", DefaultHighlighter.INSTANCE_FIELD),
new AttributesDescriptor("Instance method call", DefaultHighlighter.METHOD_CALL),
new AttributesDescriptor("Static method call", DefaultHighlighter.STATIC_METHOD_ACCESS),
+ new AttributesDescriptor("Method declaration", DefaultHighlighter.METHOD_DECLARATION),
new AttributesDescriptor("Class reference", DefaultHighlighter.CLASS_REFERENCE),
new AttributesDescriptor("Map key accessed as a property", DefaultHighlighter.MAP_KEY),
new AttributesDescriptor("Instance property reference", DefaultHighlighter.INSTANCE_PROPERTY_REFERENCE),
@@ -103,10 +108,11 @@ public class GroovyColorsAndFontsPage implements ColorSettingsPage {
" def property\n" +
"//This is a line comment\n" +
"/* This is a block comment */\n" +
- " static def foo(int i) {\n" +
- " Map map = [key:1, b:2]\n" +
+ " static def foo(int i, int j) {\n" +
+ " Map map = [key:1, b:2]\n" +
+ " j++\n" +
" print map.key\n" +
- " return [i, i, property]\n" +
+ " return [i, property]\n" +
" }\n" +
" static def panel = new JPanel()\n" +
"}\n" +
@@ -114,8 +120,9 @@ public class GroovyColorsAndFontsPage implements ColorSettingsPage {
"Demo.panel.size = " +
"Demo.foo(\"123${456}789\".toInteger()) \n" +
"'JetBrains'.matches(/Jw+Bw+/) \n" +
- "def x=1 + unresolved\n" +
- "def f1 = []\n" +
+ "def x=1 + unresolved\n" +
+ "def f1 = []\n" +
+ "f1 = [2]\n" +
"File f=['path']\n" +
"print new Demo().property\n" +
"print '\\n \\x'"
@@ -140,6 +147,11 @@ public class GroovyColorsAndFontsPage implements ColorSettingsPage {
map.put("staticprop", DefaultHighlighter.STATIC_PROPERTY_REFERENCE);
map.put("validescape", DefaultHighlighter.VALID_STRING_ESCAPE);
map.put("invalidescape", DefaultHighlighter.INVALID_STRING_ESCAPE);
+ map.put("local", DefaultHighlighter.LOCAL_VARIABLE);
+ map.put("reLocal", DefaultHighlighter.REASSIGNED_LOCAL_VARIABLE);
+ map.put("param", DefaultHighlighter.PARAMETER);
+ map.put("reParam", DefaultHighlighter.REASSIGNED_PARAMETER);
+ map.put("method", DefaultHighlighter.METHOD_DECLARATION);
return map;
}
}
diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy
index 1f884636fffc..49566e1a1486 100644
--- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy
+++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/GroovyHighlightingTest.groovy
@@ -691,4 +691,8 @@ public class CorrectImplementor implements ActionListener {
''')
myFixture.testHighlighting(true, false, false)
}
+
+ public void testReassignedHighlighting() {
+ myFixture.testHighlighting(true, true, true, getTestName(false) + ".groovy");
+ }
}
\ No newline at end of file
diff --git a/plugins/groovy/testdata/highlighting/ReassignedHighlighting.groovy b/plugins/groovy/testdata/highlighting/ReassignedHighlighting.groovy
new file mode 100644
index 000000000000..22ba7339ab32
--- /dev/null
+++ b/plugins/groovy/testdata/highlighting/ReassignedHighlighting.groovy
@@ -0,0 +1,15 @@
+def method(int param1, int param2) {
+ int var1 = 0
+ int var2 = 1
+ int var3 = 1
+ if (param1 == 1) {
+ param2 = var2 = 2
+ var3++
+ }
+ println var1 +
+ var2 +
+ param1 +
+ param2
+}
+
+method(239, 42)
\ No newline at end of file