PSI leak via the LocalQuickFix

This commit is contained in:
Alexey Kudravtsev
2011-03-31 14:57:33 +04:00
parent 1d6649bfb9
commit ed07bd205d
12 changed files with 271 additions and 154 deletions
@@ -25,21 +25,22 @@ import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.refactoring.actions.TypeCookAction;
import org.jetbrains.annotations.NotNull;
public class GenerifyFileFix implements IntentionAction, LocalQuickFix {
private final PsiFile myFile;
private final String myFileName;
public GenerifyFileFix(PsiFile file) {
myFile = file;
public GenerifyFileFix(String fileName) {
myFileName = fileName;
}
@NotNull
public String getText() {
return QuickFixBundle.message("generify.text", myFile.getName());
return QuickFixBundle.message("generify.text", myFileName);
}
@NotNull
@@ -55,21 +56,23 @@ public class GenerifyFileFix implements IntentionAction, LocalQuickFix {
@Override
public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) {
if (isAvailable(project, null, null)) {
final PsiElement element = descriptor.getPsiElement();
if (element == null) return;
if (isAvailable(project, null, element.getContainingFile())) {
new WriteCommandAction(project) {
protected void run(Result result) throws Throwable {
invoke(project, FileEditorManager.getInstance(project).getSelectedTextEditor(), descriptor.getPsiElement().getContainingFile());
invoke(project, FileEditorManager.getInstance(project).getSelectedTextEditor(), element.getContainingFile());
}
}.execute();
}
}
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return myFile.isValid() && PsiManager.getInstance(project).isInProject(myFile);
return file != null && file.isValid() && PsiManager.getInstance(project).isInProject(file);
}
public void invoke(@NotNull Project project, Editor editor, PsiFile file) {
if (!CodeInsightUtilBase.prepareFileForWrite(myFile)) return;
if (!CodeInsightUtilBase.prepareFileForWrite(file)) return;
new TypeCookAction().getHandler().invoke(project, editor, file, null);
}
@@ -315,24 +315,20 @@ public class DataFlowInspection extends BaseLocalInspectionTool {
@Nullable
private static LocalQuickFix createSimplifyBooleanExpressionFix(PsiElement element, final boolean value) {
if (!(element instanceof PsiExpression)) return null;
final PsiExpression expression = (PsiExpression)element;
while (element.getParent() instanceof PsiExpression) {
element = element.getParent();
}
final SimplifyBooleanExpressionFix fix = new SimplifyBooleanExpressionFix(expression, value);
// simplify intention already active
if (!fix.isAvailable(element.getProject(), null, element.getContainingFile()) ||
SimplifyBooleanExpressionFix.canBeSimplified((PsiExpression)element)) {
return null;
}
SimplifyBooleanExpressionFix fix = createIntention(element, value);
if (fix == null) return null;
final String text = fix.getText();
return new LocalQuickFix() {
@NotNull public String getName() {
return fix.getText();
@NotNull
public String getName() {
return text;
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiElement psiElement = descriptor.getPsiElement();
if (psiElement == null) return;
final SimplifyBooleanExpressionFix fix = createIntention(psiElement, value);
if (fix==null) return;
try {
LOG.assertTrue(psiElement.isValid());
fix.invoke(project, null, psiElement.getContainingFile());
@@ -349,6 +345,21 @@ public class DataFlowInspection extends BaseLocalInspectionTool {
};
}
private static SimplifyBooleanExpressionFix createIntention(PsiElement element, boolean value) {
if (!(element instanceof PsiExpression)) return null;
final PsiExpression expression = (PsiExpression)element;
while (element.getParent() instanceof PsiExpression) {
element = element.getParent();
}
final SimplifyBooleanExpressionFix fix = new SimplifyBooleanExpressionFix(expression, value);
// simplify intention already active
if (!fix.isAvailable(element.getProject(), null, element.getContainingFile()) ||
SimplifyBooleanExpressionFix.canBeSimplified((PsiExpression)element)) {
return null;
}
return fix;
}
private static class RedundantInstanceofFix implements LocalQuickFix {
@NotNull
public String getName() {
@@ -33,6 +33,7 @@ import com.intellij.ui.FieldPanel;
import com.intellij.ui.IdeBorderFactory;
import com.intellij.util.IJSwingUtilities;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.UIUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NonNls;
@@ -326,7 +327,7 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
final PsiDocTag tag = factory.createDocTagFromText("@" + myTag + " " + myValue);
if (docComment != null) {
PsiElement addedTag;
final PsiElement anchor = getAnchor();
final PsiElement anchor = getAnchor(descriptor);
if (anchor != null) {
addedTag = docComment.addBefore(tag, anchor);
}
@@ -343,7 +344,7 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
}
@Nullable
protected PsiElement getAnchor() {
protected PsiElement getAnchor(ProblemDescriptor descriptor) {
return null;
}
@@ -742,24 +743,36 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
PsiParameter param,
final InspectionManager manager, boolean isOnTheFly) {
String message = InspectionsBundle.message("inspection.javadoc.method.problem.missing.param.tag", "<code>@param</code>", "<code>" + param.getName() + "</code>");
return createDescriptor(elementToHighlight, message, new AddMissingParamTagFix(param), manager, isOnTheFly);
return createDescriptor(elementToHighlight, message, new AddMissingParamTagFix(param.getName()), manager, isOnTheFly);
}
private static class AddMissingParamTagFix extends AddMissingTagFix {
private final PsiParameter myParam;
private final String myName;
public AddMissingParamTagFix(final PsiParameter param) {
super("param", param.getName());
myParam = param;
public AddMissingParamTagFix(String name) {
super("param", name);
myName = name;
}
@NotNull
public String getName() {
return InspectionsBundle.message("inspection.javadoc.problem.add.param.tag", myParam.getName());
return InspectionsBundle.message("inspection.javadoc.problem.add.param.tag", myName);
}
@Nullable
protected PsiElement getAnchor() {
protected PsiElement getAnchor(ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
PsiElement parent = element == null ? null : element.getParent();
if (!(parent instanceof PsiMethod)) return null;
PsiParameter[] parameters = ((PsiMethod)parent).getParameterList().getParameters();
PsiParameter myParam = ContainerUtil.find(parameters, new Condition<PsiParameter>() {
@Override
public boolean value(PsiParameter psiParameter) {
return myName.equals(psiParameter.getName());
}
});
if (myParam == null) return null;
final PsiMethod psiMethod = PsiTreeUtil.getParentOfType(myParam, PsiMethod.class);
LOG.assertTrue(psiMethod != null);
final PsiDocComment docComment = psiMethod.getDocComment();
@@ -938,12 +951,12 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
if (tagInfo == null) {
problems.add(
createDescriptor(nameElement, InspectionsBundle.message("inspection.javadoc.problem.wrong.tag", "<code>" + tagName + "</code>"),
new AddUnknownTagToCustoms(tag), inspectionManager, isOnTheFly));
new AddUnknownTagToCustoms(tag.getName()), inspectionManager, isOnTheFly));
}
else {
problems.add(createDescriptor(nameElement, InspectionsBundle.message("inspection.javadoc.problem.disallowed.tag",
"<code>" + tagName + "</code>"),
new AddUnknownTagToCustoms(tag), inspectionManager, isOnTheFly));
new AddUnknownTagToCustoms(tag.getName()), inspectionManager, isOnTheFly));
}
}
return false;
@@ -1129,15 +1142,15 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
}
private class AddUnknownTagToCustoms implements LocalQuickFix {
PsiDocTag myTag;
private final String myTag;
public AddUnknownTagToCustoms(PsiDocTag tag) {
public AddUnknownTagToCustoms(String tag) {
myTag = tag;
}
@NotNull
public String getName() {
return QuickFixBundle.message("add.doctag.to.custom.tags", myTag.getName());
return QuickFixBundle.message("add.doctag.to.custom.tags", myTag);
}
@NotNull
@@ -1146,12 +1159,12 @@ public class JavaDocLocalInspection extends BaseLocalInspectionTool {
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
if (myTag == null || !myTag.isValid()) return;
if (myTag == null) return;
if (myAdditionalJavadocTags.length() > 0) {
myAdditionalJavadocTags += "," + myTag.getName();
myAdditionalJavadocTags += "," + myTag;
}
else {
myAdditionalJavadocTags = myTag.getName();
myAdditionalJavadocTags = myTag;
}
final InspectionProfile inspectionProfile =
InspectionProjectProfileManager.getInstance(project).getInspectionProfile();
@@ -179,7 +179,7 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
}
}
}
fixes.add(new RemoveTagFix(tagName, paramName, tag));
fixes.add(new RemoveTagFix(tagName, paramName));
problems.add(inspectionManager.createProblemDescriptor(valueElement, reference.getRangeInElement(), cannotResolveSymbolMessage(params),
ProblemHighlightType.LIKE_UNKNOWN_SYMBOL, onTheFly,
@@ -300,12 +300,10 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
private static class RemoveTagFix implements LocalQuickFix {
private final String myTagName;
private final CharSequence myParamName;
private final PsiDocTag myTag;
public RemoveTagFix(String tagName, CharSequence paramName, PsiDocTag tag) {
public RemoveTagFix(String tagName, CharSequence paramName) {
myTagName = tagName;
myParamName = paramName;
myTag = tag;
}
@NotNull
@@ -319,6 +317,8 @@ public class JavaDocReferenceInspection extends BaseLocalInspectionTool {
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final PsiDocTag myTag = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PsiDocTag.class);
if (myTag == null) return;
myTag.delete();
}
}
@@ -213,7 +213,7 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool
if (GenericsHighlightUtil.isUncheckedCast(castType, exprType)) {
final String description =
JavaErrorMessages.message("generics.unchecked.cast", HighlightUtil.formatType(exprType), HighlightUtil.formatType(castType));
registerProblem(description, expression, myOnTheFly ? new GenerifyFileFix(operand.getContainingFile()) : null);
registerProblem(description, expression, myOnTheFly ? new GenerifyFileFix(operand.getContainingFile().getName()) : null);
}
}
@@ -227,7 +227,7 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool
if (IGNORE_UNCHECKED_CALL) return;
registerProblem(description, callExpression instanceof PsiMethodCallExpression
? ((PsiMethodCallExpression)callExpression).getMethodExpression()
: callExpression, myOnTheFly ? new GenerifyFileFix(callExpression.getContainingFile()) : null);
: callExpression, myOnTheFly ? new GenerifyFileFix(callExpression.getContainingFile().getName()) : null);
}
else {
if (IGNORE_UNCHECKED_ASSIGNMENT) return;
@@ -245,7 +245,7 @@ public class UncheckedWarningLocalInspection extends BaseJavaLocalInspectionTool
final PsiType parameterType = substitutor.substitute(parameter.getType());
final PsiType expressionType = substitutor.substitute(expression.getType());
if (expressionType != null) {
checkRawToGenericsAssignment(expression, parameterType, expressionType, true, myOnTheFly ? new GenerifyFileFix(expression.getContainingFile()) : null);
checkRawToGenericsAssignment(expression, parameterType, expressionType, true, myOnTheFly ? new GenerifyFileFix(expression.getContainingFile().getName()) : null);
}
}
}