diff --git a/java/openapi/src/com/intellij/psi/util/PsiUtil.java b/java/openapi/src/com/intellij/psi/util/PsiUtil.java index f3b41b26e7a7..1ac2d4100b5c 100644 --- a/java/openapi/src/com/intellij/psi/util/PsiUtil.java +++ b/java/openapi/src/com/intellij/psi/util/PsiUtil.java @@ -53,9 +53,9 @@ public final class PsiUtil extends PsiUtilBase { private PsiUtil() {} public static boolean isOnAssignmentLeftHand(PsiExpression expr) { - PsiElement parent = expr.getParent(); - return parent instanceof PsiAssignmentExpression - && expr.equals(((PsiAssignmentExpression) parent).getLExpression()); + PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, PsiParenthesizedExpression.class); + return parent instanceof PsiAssignmentExpression && + PsiTreeUtil.isAncestor(((PsiAssignmentExpression)parent).getLExpression(), expr, false); } public static boolean isAccessibleFromPackage(@NotNull PsiModifierListOwner element, @NotNull PsiPackage aPackage) { @@ -66,7 +66,7 @@ public final class PsiUtil extends PsiUtilBase { public static boolean isAccessedForWriting(PsiExpression expr) { if (isOnAssignmentLeftHand(expr)) return true; - PsiElement parent = expr.getParent(); + PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, PsiParenthesizedExpression.class); if (parent instanceof PsiPrefixExpression) { IElementType tokenType = ((PsiPrefixExpression) parent).getOperationTokenType(); return tokenType == JavaTokenType.PLUSPLUS || tokenType == JavaTokenType.MINUSMINUS; @@ -81,9 +81,9 @@ public final class PsiUtil extends PsiUtilBase { } public static boolean isAccessedForReading(PsiExpression expr) { - PsiElement parent = expr.getParent(); + PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, PsiParenthesizedExpression.class); return !(parent instanceof PsiAssignmentExpression) || - !expr.equals(((PsiAssignmentExpression)parent).getLExpression()) || + !PsiTreeUtil.isAncestor(((PsiAssignmentExpression)parent).getLExpression(), expr, false) || ((PsiAssignmentExpression)parent).getOperationSign().getTokenType() != JavaTokenType.EQ; } diff --git a/platform/lang-api/src/com/intellij/psi/util/PsiTreeUtil.java b/platform/lang-api/src/com/intellij/psi/util/PsiTreeUtil.java index b47dc9f8958f..217679658281 100644 --- a/platform/lang-api/src/com/intellij/psi/util/PsiTreeUtil.java +++ b/platform/lang-api/src/com/intellij/psi/util/PsiTreeUtil.java @@ -322,6 +322,19 @@ public class PsiTreeUtil { return null; } + @Nullable + public static PsiElement skipParentsOfType(@Nullable PsiElement element, @NotNull Class... parentClasses) { + if (element == null) return null; + NextSibling: + for (PsiElement e = element.getParent(); e != null; e = e.getParent()) { + for (Class aClass : parentClasses) { + if (instanceOf(aClass, e)) continue NextSibling; + } + return e; + } + return null; + } + @Nullable public static T getParentOfType(PsiElement element, @NotNull Class... classes) { if (element == null) return null; diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 8fd0671cfb07..32f213571706 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -116,6 +116,8 @@ + + elements = new ArrayList(); + if (getter != null) { + elements.addAll(Arrays.asList(SuperMethodWarningUtil.checkSuperMethods(getter, ACTION_STRING))); + } + if (setter != null) { + elements.addAll(Arrays.asList(SuperMethodWarningUtil.checkSuperMethods(setter, ACTION_STRING))); + } + return elements.toArray(new PsiElement[elements.size()]); + } else { + return PsiElement.EMPTY_ARRAY; + } + } + } + return super.getSecondaryElements(); + } + }; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyReadWriteAccessDetector.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyReadWriteAccessDetector.java new file mode 100644 index 000000000000..3e85535545bd --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/findUsages/GroovyReadWriteAccessDetector.java @@ -0,0 +1,67 @@ +/* + * Copyright 2000-2010 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.plugins.groovy.findUsages; + +import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; +import com.intellij.psi.PsiReference; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils; +import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil; + +/** + * @author Maxim.Medvedev + */ +public class GroovyReadWriteAccessDetector extends ReadWriteAccessDetector{ + @Override + public boolean isReadWriteAccessible(PsiElement element) { + return element instanceof GrVariable; + } + + @Override + public boolean isDeclarationWriteAccess(PsiElement element) { + if (element instanceof GrVariable && ((GrVariable)element).getInitializerGroovy() != null) { + return true; + } + return false; + } + + @Override + public Access getReferenceAccess(PsiElement referencedElement, PsiReference reference) { + return getExpressionAccess(reference.getElement()); + } + + @Override + public Access getExpressionAccess(PsiElement expression) { + if (!(expression instanceof GrExpression)) return Access.Read; + GrExpression expr = (GrExpression) expression; + boolean readAccess = PsiUtil.isAccessedForReading(expr); + boolean writeAccess = PsiUtil.isAccessedForWriting(expr); + if (!writeAccess && expr instanceof GrReferenceExpression) { + //when searching usages of fields, should show all found setters as a "only write usage" + PsiElement actualReferee = ((GrReferenceExpression) expr).resolve(); + if (actualReferee instanceof PsiMethod && GroovyPropertyUtils.isSimplePropertySetter((PsiMethod)actualReferee)) { + writeAccess = true; + readAccess = false; + } + } + if (writeAccess && readAccess) return Access.ReadWrite; + return writeAccess ? Access.Write : Access.Read; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java index c5a2157a9f7c..362ed5658041 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/impl/statements/expressions/GrReferenceExpressionImpl.java @@ -18,7 +18,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions; import com.intellij.lang.ASTNode; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.TextRange; @@ -55,7 +54,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpres import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression; import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition; -import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod; import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement; import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeArgumentList; import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType; @@ -684,30 +682,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements } public boolean isReferenceTo(PsiElement element) { - if (element instanceof PsiMethod && GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod) element)) { - final PsiElement target = resolve(); - if (element instanceof GrAccessorMethod && getManager().areElementsEquivalent(((GrAccessorMethod)element).getProperty(), target)) { - return false; - } - - return getManager().areElementsEquivalent(element, target); - } - - if (element instanceof GrField && ((GrField) element).isProperty()) { - final PsiElement target = resolve(); - if (getManager().areElementsEquivalent(element, target)) { - return true; - } - - for (final GrAccessorMethod getter : ((GrField)element).getGetters()) { - if (getManager().areElementsEquivalent(getter, target)) { - return true; - } - } - return getManager().areElementsEquivalent(((GrField)element).getSetter(), target); - } - - if (element instanceof PsiNamedElement && Comparing.equal(((PsiNamedElement) element).getName(), getReferenceName())) { + if (element instanceof PsiNamedElement) { return getManager().areElementsEquivalent(element, resolve()); } return false; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java index 25ba5ef6beb7..16c9961f9f2b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/lang/psi/util/PsiUtil.java @@ -27,6 +27,7 @@ import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleManager; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.search.SearchScope; +import com.intellij.psi.tree.IElementType; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; @@ -109,11 +110,11 @@ public class PsiUtil { public static boolean isLValue(GroovyPsiElement element) { if (element instanceof GrExpression) { - PsiElement parent = element.getParent(); + PsiElement parent = PsiTreeUtil.skipParentsOfType(element, GrParenthesizedExpression.class); if (parent instanceof GrListOrMap && !((GrListOrMap)parent).isMap()) { return isLValue((GroovyPsiElement)parent); } - return parent instanceof GrAssignmentExpression && element.equals(((GrAssignmentExpression)parent).getLValue()); + return parent instanceof GrAssignmentExpression && PsiTreeUtil.isAncestor(((GrAssignmentExpression)parent).getLValue(), element, false); } return false; } @@ -777,4 +778,20 @@ public class PsiUtil { return constructorResults.toArray(new GroovyResolveResult[constructorResults.size()]); } + + public static boolean isAccessedForReading(GrExpression expr) { + return !isLValue(expr); + } + + public static boolean isAccessedForWriting(GrExpression expr) { + if (isLValue(expr)) return true; + + PsiElement parent = PsiTreeUtil.skipParentsOfType(expr, GrParenthesizedExpression.class); + + if (parent instanceof GrUnaryExpression) { + IElementType tokenType = ((GrUnaryExpression)parent).getOperationTokenType(); + return tokenType == GroovyTokenTypes.mINC || tokenType == GroovyTokenTypes.mDEC; + } + return false; + } } diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index e8f1cd62632d..a7234bfd4341 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1038,7 +1038,7 @@ - +