remove duplicates from find usages of groovy properties & accessors

read-write support for groovy property usages
This commit is contained in:
Maxim Medvedev
2010-06-03 15:09:14 +04:00
parent 3462517d52
commit 8fd66c2785
8 changed files with 205 additions and 35 deletions
@@ -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;
}
@@ -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 extends PsiElement> T getParentOfType(PsiElement element, @NotNull Class<? extends T>... classes) {
if (element == null) return null;
+2
View File
@@ -116,6 +116,8 @@
<lang.surroundDescriptor language="Groovy"
implementationClass="org.jetbrains.plugins.groovy.lang.surroundWith.descriptors.GroovyStmtsSurroundDescriptor"/>
<lang.findUsagesProvider language="Groovy" implementationClass="org.jetbrains.plugins.groovy.findUsages.GroovyFindUsagesProvider"/>
<readWriteAccessDetector implementation="org.jetbrains.plugins.groovy.findUsages.GroovyReadWriteAccessDetector" order="before java"/>
<findUsagesHandlerFactory implementation="org.jetbrains.plugins.groovy.findUsages.GroovyFindUsagesHandlerFactory"/>
<lang.braceMatcher language="Groovy" implementationClass="org.jetbrains.plugins.groovy.highlighter.GroovyBraceMatcher"/>
<lang.importOptimizer language="Groovy" implementationClass="org.jetbrains.plugins.groovy.lang.editor.GroovyImportOptimizer"/>
<lang.documentationProvider language="Groovy"
@@ -0,0 +1,96 @@
/*
* 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.CommonBundle;
import com.intellij.find.FindBundle;
import com.intellij.find.findUsages.FindUsagesHandler;
import com.intellij.find.findUsages.JavaFindUsagesHandler;
import com.intellij.find.findUsages.JavaFindUsagesHandlerFactory;
import com.intellij.ide.util.SuperMethodWarningUtil;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiMethod;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Maxim.Medvedev
*/
public class GroovyFindUsagesHandlerFactory extends JavaFindUsagesHandlerFactory {
public GroovyFindUsagesHandlerFactory(Project project) {
super(project);
}
@Override
public boolean canFindUsages(@NotNull PsiElement element) {
return element instanceof GrField;
}
@Override
public FindUsagesHandler createFindUsagesHandler(@NotNull PsiElement element, boolean forHighlightUsages) {
return new JavaFindUsagesHandler(element, getFindClassOptions(), getFindMethodOptions(), getFindPackageOptions(), getFindThrowOptions(),
getFindVariableOptions()) {
@NotNull
@Override
public PsiElement[] getSecondaryElements() {
PsiElement element = getPsiElement();
if (ApplicationManager.getApplication().isUnitTestMode()) return PsiElement.EMPTY_ARRAY;
final PsiField field = (PsiField)element;
PsiClass containingClass = field.getContainingClass();
if (containingClass != null) {
PsiMethod getter = GroovyPropertyUtils.findGetterForField(field);
PsiMethod setter = GroovyPropertyUtils.findSetterForField(field);
if (getter != null || setter != null) {
final boolean doSearch;
if ((getter == null || !getter.isPhysical()) && (setter == null || !setter.isPhysical())) {
doSearch = true;
}
else {
doSearch = Messages.showDialog(FindBundle.message("find.field.accessors.prompt", field.getName()),
FindBundle.message("find.field.accessors.title"),
new String[]{CommonBundle.getYesButtonText(), CommonBundle.getNoButtonText()}, 0,
Messages.getQuestionIcon()) == DialogWrapper.OK_EXIT_CODE;
}
if (doSearch) {
final List<PsiElement> elements = new ArrayList<PsiElement>();
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();
}
};
}
}
@@ -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;
}
}
@@ -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;
@@ -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;
}
}
+1 -1
View File
@@ -1038,7 +1038,7 @@
<vetoRenameCondition implementation="com.intellij.refactoring.rename.JavaVetoRenameCondition"/>
<readWriteAccessDetector implementation="com.intellij.codeInsight.highlighting.JavaReadWriteAccessDetector"/>
<readWriteAccessDetector implementation="com.intellij.codeInsight.highlighting.JavaReadWriteAccessDetector" id="java"/>
<elementDescriptionProvider implementation="com.intellij.codeInsight.highlighting.JavaHighlightUsagesDescriptionProvider"/>
<elementDescriptionProvider implementation="com.intellij.usageView.JavaUsageViewDescriptionProvider"/>