psi leaks

This commit is contained in:
Alexey Kudravtsev
2011-04-18 17:06:17 +04:00
parent 65ca67c7d7
commit 8270a8614b
13 changed files with 255 additions and 191 deletions
@@ -20,8 +20,7 @@ import com.intellij.codeInsight.daemon.QuickFixBundle;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightMessageUtil;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
import com.intellij.codeInsight.highlighting.HighlightManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.ide.DataManager;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
@@ -38,32 +37,36 @@ import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class AccessStaticViaInstanceFix implements LocalQuickFix {
public class AccessStaticViaInstanceFix extends LocalQuickFixAndIntentionActionOnPsiElement {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.quickfix.AccessStaticViaInstanceFix");
private final PsiReferenceExpression myExpression;
private final boolean myOnTheFly;
private final PsiMember myMember;
private final JavaResolveResult myResult;
private final String myText;
public AccessStaticViaInstanceFix(PsiReferenceExpression expression, JavaResolveResult result, boolean onTheFly) {
myExpression = expression;
super(expression);
myOnTheFly = onTheFly;
myMember = (PsiMember)result.getElement();
myResult = result;
PsiMember member = (PsiMember)result.getElement();
myText = calcText(member, result.getSubstitutor());
}
@NotNull
public String getName() {
PsiClass aClass = myMember.getContainingClass();
@Override
public String getText() {
return myText;
}
private static String calcText(PsiMember member, PsiSubstitutor substitutor) {
PsiClass aClass = member.getContainingClass();
if (aClass == null) return "";
return QuickFixBundle.message("access.static.via.class.reference.text",
HighlightMessageUtil.getSymbolName(myMember, myResult.getSubstitutor()),
HighlightMessageUtil.getSymbolName(member, substitutor),
HighlightUtil.formatClass(aClass),
HighlightUtil.formatClass(aClass,false));
HighlightUtil.formatClass(aClass, false));
}
@NotNull
@@ -71,16 +74,28 @@ public class AccessStaticViaInstanceFix implements LocalQuickFix {
return QuickFixBundle.message("access.static.via.class.reference.family");
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
if (!myExpression.isValid() || !myMember.isValid()) return;
@Override
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable("is null when called from inspection") Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
final PsiReferenceExpression myExpression = (PsiReferenceExpression)startElement;
if (!myExpression.isValid()) return;
if (!CodeInsightUtilBase.prepareFileForWrite(myExpression.getContainingFile())) return;
PsiElement element = myExpression.resolve();
if (!(element instanceof PsiMember)) return;
PsiMember myMember = (PsiMember)element;
if (!myMember.isValid()) return;
PsiClass containingClass = myMember.getContainingClass();
if (containingClass == null) return;
try {
final PsiExpression qualifierExpression = myExpression.getQualifierExpression();
PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
if (qualifierExpression != null) {
if (!checkSideEffects(project, containingClass, qualifierExpression, factory)) return;
if (!checkSideEffects(project, containingClass, qualifierExpression, factory, myExpression)) return;
PsiElement newQualifier = qualifierExpression.replace(factory.createReferenceExpression(containingClass));
PsiElement qualifiedWithClassName = myExpression.copy();
newQualifier.delete();
@@ -95,7 +110,7 @@ public class AccessStaticViaInstanceFix implements LocalQuickFix {
}
private boolean checkSideEffects(final Project project, PsiClass containingClass, final PsiExpression qualifierExpression,
PsiElementFactory factory) {
PsiElementFactory factory, final PsiElement myExpression) {
final List<PsiElement> sideEffects = new ArrayList<PsiElement>();
boolean hasSideEffects = RemoveUnusedVariableFix.checkSideEffects(qualifierExpression, null, sideEffects);
if (hasSideEffects && !myOnTheFly) return false;
@@ -35,7 +35,6 @@ import org.jetbrains.annotations.NotNull;
*/
public class SurroundWithIfFix implements LocalQuickFix {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.SurroundWithIfFix");
private final PsiExpression myExpression;
private final String myText;
@NotNull
@@ -44,8 +43,7 @@ public class SurroundWithIfFix implements LocalQuickFix {
}
public SurroundWithIfFix(@NotNull PsiExpression expressionToAssert) {
myExpression = expressionToAssert;
myText = myExpression.getText();
myText = expressionToAssert.getText();
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
@@ -83,11 +81,11 @@ public class SurroundWithIfFix implements LocalQuickFix {
return InspectionsBundle.message("inspection.surround.if.family");
}
public boolean isAvailable() {
if (!myExpression.isValid() || myText == null) {
public boolean isAvailable(PsiExpression qualifier) {
if (!qualifier.isValid() || myText == null) {
return false;
}
PsiStatement statement = PsiTreeUtil.getParentOfType(myExpression, PsiStatement.class);
PsiStatement statement = PsiTreeUtil.getParentOfType(qualifier, PsiStatement.class);
if (statement == null) return false;
PsiElement parent = statement.getParent();
return !(parent instanceof PsiForStatement);
@@ -126,7 +126,7 @@ public class DataFlowInspection extends BaseLocalInspectionTool {
fixes.add(new AddAssertStatementFix(binary));
}
SurroundWithIfFix ifFix = new SurroundWithIfFix(qualifier);
if (ifFix.isAvailable()) {
if (ifFix.isAvailable(qualifier)) {
fixes.add(ifFix);
}
return fixes.toArray(new LocalQuickFix[fixes.size()]);
@@ -29,8 +29,10 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -54,9 +56,9 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
private static final String RETURN_VALUE_UNDEFINED = "#";
private ArrayList<RefMethod> mySuperMethods;
private ArrayList<RefMethod> myDerivedMethods;
private ArrayList<PsiClass> myUnThrownExceptions;
private List<RefMethod> mySuperMethods;
private List<RefMethod> myDerivedMethods;
private List<String> myUnThrownExceptions;
private RefParameter[] myParameters;
private String myReturnValueTemplate;
@@ -288,7 +290,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
getRefManager().fireBuildReferences(this);
}
private void collectUncaughtExceptions(PsiMethod method) {
private void collectUncaughtExceptions(@NotNull PsiMethod method) {
if (isExternalOverride()) return;
@NonNls final String name = method.getName();
if (getOwnerClass().isTestCase() && name.startsWith("test")) return;
@@ -296,9 +298,13 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
if (getSuperMethods().isEmpty()) {
PsiClassType[] throwsList = method.getThrowsList().getReferencedTypes();
if (throwsList.length > 0) {
myUnThrownExceptions = new ArrayList<PsiClass>(throwsList.length);
myUnThrownExceptions = throwsList.length == 1 ? new SmartList<String>() : new ArrayList<String>(throwsList.length);
for (final PsiClassType type : throwsList) {
myUnThrownExceptions.add(type.resolve());
PsiClass aClass = type.resolve();
String fqn = aClass == null ? null : aClass.getQualifiedName();
if (fqn != null) {
myUnThrownExceptions.add(fqn);
}
}
}
}
@@ -314,7 +320,7 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
public void removeUnThrownExceptions(PsiClass unThrownException) {
if (myUnThrownExceptions != null) {
myUnThrownExceptions.remove(unThrownException);
myUnThrownExceptions.remove(unThrownException.getQualifiedName());
}
}
@@ -413,8 +419,8 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
else {
result[0] = PsiFormatUtil.formatMethod(psiMethod,
PsiSubstitutor.EMPTY,
PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_PARAMETERS,
PsiFormatUtil.SHOW_TYPE
PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS,
PsiFormatUtilBase.SHOW_TYPE
);
}
}
@@ -525,7 +531,9 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
if (psiField.hasModifierProperty(PsiModifier.STATIC) &&
psiField.hasModifierProperty(PsiModifier.FINAL) &&
refUtil.compareAccess(refUtil.getAccessModifier(psiField), getAccessModifier()) >= 0) {
newTemplate = PsiFormatUtil.formatVariable(psiField, PsiFormatUtil.SHOW_NAME | PsiFormatUtil.SHOW_CONTAINING_CLASS | PsiFormatUtil.SHOW_FQ_NAME, PsiSubstitutor.EMPTY);
newTemplate = PsiFormatUtil.formatVariable(psiField, PsiFormatUtilBase.SHOW_NAME |
PsiFormatUtilBase.SHOW_CONTAINING_CLASS |
PsiFormatUtilBase.SHOW_FQ_NAME, PsiSubstitutor.EMPTY);
}
}
} else if (refUtil.isCallToSuperMethod(expression, (PsiMethod) getElement())) return;
@@ -573,17 +581,19 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
for (RefMethod refSuper : getSuperMethods()) {
((RefMethodImpl)refSuper).updateThrowsList(exceptionType);
}
} else if (myUnThrownExceptions != null) {
}
else if (myUnThrownExceptions != null) {
if (exceptionType == null) {
myUnThrownExceptions = null;
return;
}
PsiClass[] arrayed = myUnThrownExceptions.toArray(new PsiClass[myUnThrownExceptions.size()]);
for (int i = arrayed.length - 1; i >= 0; i--) {
PsiClass classType = arrayed[i];
if (InheritanceUtil.isInheritorOrSelf(exceptionType.resolve(), classType, true) ||
InheritanceUtil.isInheritorOrSelf(classType, exceptionType.resolve(), true)) {
PsiClass exceptionClass = exceptionType.resolve();
JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject());
for (int i = myUnThrownExceptions.size() - 1; i >= 0; i--) {
String exceptionFqn = myUnThrownExceptions.get(i);
PsiClass classType = facade.findClass(exceptionFqn, GlobalSearchScope.allScope(getRefManager().getProject()));
if (InheritanceUtil.isInheritorOrSelf(exceptionClass, classType, true) ||
InheritanceUtil.isInheritorOrSelf(classType, exceptionClass, true)) {
myUnThrownExceptions.remove(i);
}
}
@@ -595,7 +605,13 @@ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod {
@Nullable
public PsiClass[] getUnThrownExceptions() {
if (myUnThrownExceptions == null) return null;
return myUnThrownExceptions.toArray(new PsiClass[myUnThrownExceptions.size()]);
JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject());
List<PsiClass> result = new ArrayList<PsiClass>(myUnThrownExceptions.size());
for (String exception : myUnThrownExceptions) {
PsiClass element = facade.findClass(exception, GlobalSearchScope.allScope(myManager.getProject()));
if (element != null) result.add(element);
}
return result.toArray(new PsiClass[result.size()]);
}
@@ -105,10 +105,6 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool {
@Override
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new JavaElementVisitor() {
public void visitReferenceExpression(PsiReferenceExpression expression) {
}
@Override
public void visitJavaFile(PsiJavaFile file) {
for (PsiClass aClass : file.getClasses()) {
@@ -143,7 +139,7 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool {
for (PsiField field : candidates) {
if (usedFields.contains(field) && !hasImplicitReadOrWriteUsage(field, implicitUsageProviders)) {
final String message = InspectionsBundle.message("inspection.field.can.be.local.problem.descriptor");
holder.registerProblem(field.getNameIdentifier(), message, new MyQuickFix(field));
holder.registerProblem(field.getNameIdentifier(), message, new MyQuickFix());
}
}
}
@@ -210,13 +206,9 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool {
}
private static boolean isImmutableState(PsiType type) {
if (type instanceof PsiPrimitiveType) {
return true;
}
if (PsiPrimitiveType.getUnboxedType(type) != null) {
return true;
}
return Comparing.strEqual(CommonClassNames.JAVA_LANG_STRING, type.getCanonicalText());
return type instanceof PsiPrimitiveType ||
PsiPrimitiveType.getUnboxedType(type) != null ||
Comparing.strEqual(CommonClassNames.JAVA_LANG_STRING, type.getCanonicalText());
}
private static Collection<PsiVariable> getWrittenVariables(ControlFlow controlFlow, Ref<Collection<PsiVariable>> writtenVariables) {
@@ -263,19 +255,15 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool {
}
private static class MyQuickFix implements LocalQuickFix {
private final PsiField myField;
public MyQuickFix(final PsiField field) {
myField = field;
}
@NotNull
public String getName() {
return InspectionsBundle.message("inspection.field.can.be.local.quickfix");
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
if (!myField.isValid()) return; //weird. should not get here when field becomes invalid
PsiElement element = descriptor.getPsiElement();
PsiField myField = PsiTreeUtil.getParentOfType(element, PsiField.class);
if (myField == null || !myField.isValid()) return; //weird. should not get here when field becomes invalid
final Collection<PsiReference> refs = ReferencesSearch.search(myField).findAll();
if (refs.isEmpty()) return;
@@ -302,18 +290,20 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool {
final PsiExpression initializer = expression.getRExpression();
final PsiDeclarationStatement decl = elementFactory.createVariableDeclarationStatement(localName, myField.getType(), initializer);
if (!mayBeFinal) {
PsiUtil.setModifierProperty(((PsiModifierListOwner)decl.getDeclaredElements()[0]), PsiModifier.FINAL, false);
PsiUtil.setModifierProperty((PsiModifierListOwner)decl.getDeclaredElements()[0], PsiModifier.FINAL, false);
}
newDeclaration = anchor.replace(decl);
refsSet.remove(expression.getLExpression());
retargetReferences(elementFactory, localName, refsSet);
}
else {
newDeclaration = addDeclarationWithFieldInitializerAndRetargetReferences(elementFactory, localName, anchorBlock, anchor, refsSet);
newDeclaration = addDeclarationWithFieldInitializerAndRetargetReferences(elementFactory, localName, anchorBlock, anchor, refsSet,
myField);
}
}
else {
newDeclaration = addDeclarationWithFieldInitializerAndRetargetReferences(elementFactory, localName, anchorBlock, anchor, refsSet);
newDeclaration = addDeclarationWithFieldInitializerAndRetargetReferences(elementFactory, localName, anchorBlock, anchor, refsSet,
myField);
}
}
catch (IncorrectOperationException e) {
@@ -361,10 +351,12 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool {
}
}
private PsiElement addDeclarationWithFieldInitializerAndRetargetReferences(final PsiElementFactory elementFactory, final String localName,
final PsiCodeBlock anchorBlock,
final PsiElement anchor,
final Set<PsiReference> refs)
private static PsiElement addDeclarationWithFieldInitializerAndRetargetReferences(final PsiElementFactory elementFactory,
final String localName,
final PsiCodeBlock anchorBlock,
final PsiElement anchor,
final Set<PsiReference> refs,
PsiField myField)
throws IncorrectOperationException {
final PsiDeclarationStatement decl = elementFactory.createVariableDeclarationStatement(localName, myField.getType(), myField.getInitializer());
final PsiElement newDeclaration = anchorBlock.addBefore(decl, anchor);