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