don't leak psi from CreateNSDeclarationIntentionFix

This commit is contained in:
peter
2012-01-05 20:38:48 +01:00
parent e62be9a7f2
commit 7b0cfd3eb8
5 changed files with 47 additions and 42 deletions
@@ -19,7 +19,6 @@ package com.intellij.psi;
import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.NullableComputable;
@@ -46,7 +45,6 @@ import java.util.Set;
* @author db
*/
public abstract class PsiAnchor {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.PsiAnchor");
@Nullable
public abstract PsiElement retrieve();
public abstract PsiFile getFile();
@@ -161,7 +161,7 @@ public class XsltNamespaceContext implements NamespaceContext {
// TODO: verify API
public MyCreateNSDeclarationAction(XmlElement xmlElement, String prefix, XmlFile xmlFile) {
super(xmlElement, prefix, xmlFile);
super(xmlElement, prefix);
myXmlFile = xmlFile;
}
@@ -26,7 +26,6 @@ import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.SchemaReferencesProvider;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlFile;
import com.intellij.util.ProcessingContext;
import org.intellij.lang.xpath.psi.XPath2TypeElement;
import org.intellij.lang.xpath.xslt.XsltSupport;
@@ -97,7 +96,7 @@ public class XsltReferenceContributor {
public void registerQuickfix(HighlightInfo info, PsiReference reference) {
final XmlAttributeValue valueElement = myAttribute.getValueElement();
if (valueElement != null) {
QuickFixAction.registerQuickFixAction(info, new CreateNSDeclarationIntentionFix(valueElement, getCanonicalText(), (XmlFile)myAttribute.getContainingFile()) {
QuickFixAction.registerQuickFixAction(info, new CreateNSDeclarationIntentionFix(valueElement, getCanonicalText()) {
@Override
public boolean showHint(Editor editor) {
return false;
@@ -38,6 +38,7 @@ import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiAnchor;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -50,6 +51,7 @@ import com.intellij.psi.xml.XmlToken;
import com.intellij.ui.components.JBList;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.XmlExtension;
import com.intellij.xml.impl.schema.AnyXmlElementDescriptor;
@@ -73,38 +75,43 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.daemon.impl.analysis.CreateNSDeclarationIntentionFix");
private final String myNamespacePrefix;
private final PsiElement myElement;
private final XmlFile myFile;
private final XmlToken myToken;
private final PsiAnchor myElement;
private final PsiAnchor myToken;
@NotNull
private XmlFile getFile() {
return (XmlFile)myElement.getFile();
}
@Nullable
public static CreateNSDeclarationIntentionFix createFix(@NotNull final PsiElement element, @NotNull final String namespacePrefix) {
PsiFile file = element.getContainingFile();
return file instanceof XmlFile ? new CreateNSDeclarationIntentionFix(element, namespacePrefix, (XmlFile)file) : null;
return file instanceof XmlFile ? new CreateNSDeclarationIntentionFix(element, namespacePrefix) : null;
}
protected CreateNSDeclarationIntentionFix(@NotNull final PsiElement element,
@NotNull final String namespacePrefix,
@NotNull XmlFile containingFile) {
this(element, namespacePrefix, null, containingFile);
@NotNull final String namespacePrefix) {
this(element, namespacePrefix, null);
}
public CreateNSDeclarationIntentionFix(final PsiElement element,
public CreateNSDeclarationIntentionFix(@NotNull final PsiElement element,
final String namespacePrefix,
@Nullable final XmlToken token,
@NotNull XmlFile containingFile) {
@Nullable final XmlToken token) {
myNamespacePrefix = namespacePrefix;
myElement = element;
myFile = containingFile;
myToken = token;
myElement = PsiAnchor.create(element);
myToken = token == null ? null : PsiAnchor.create(token);
}
@NotNull
public String getText() {
final String alias = StringUtil.capitalize(XmlExtension.getExtension(myFile).getNamespaceAlias(myFile));
final String alias = StringUtil.capitalize(getXmlExtension().getNamespaceAlias(getFile()));
return XmlErrorMessages.message("create.namespace.declaration.quickfix", alias);
}
private XmlExtension getXmlExtension() {
return XmlExtension.getExtension(getFile());
}
@NotNull
public String getName() {
return getFamilyName();
@@ -127,13 +134,15 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi
}
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return myElement.isValid();
PsiElement element = myElement.retrieve();
return element != null && element.isValid();
}
public void invoke(@NotNull final Project project, final Editor editor, final PsiFile file) throws IncorrectOperationException {
if (!myElement.isValid() || !CodeInsightUtilBase.prepareFileForWrite(file)) return;
if (!CodeInsightUtilBase.prepareFileForWrite(file)) return;
final Set<String> set = XmlExtension.getExtension(myFile).guessUnboundNamespaces(myElement, myFile);
final PsiElement element = ObjectUtils.assertNotNull(myElement.retrieve());
final Set<String> set = getXmlExtension().guessUnboundNamespaces(element, getFile());
final String[] namespaces = ArrayUtil.toStringArray(set);
Arrays.sort(namespaces);
@@ -144,18 +153,18 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi
public void doSomethingWithGivenStringToProduceXmlAttributeNowPlease(@NotNull final String namespace) throws IncorrectOperationException {
String prefix = myNamespacePrefix;
if (StringUtil.isEmpty(prefix)) {
final XmlExtension extension = XmlExtension.getExtension(myFile);
final XmlFile xmlFile = extension.getContainingFile(myElement);
final XmlExtension extension = getXmlExtension();
final XmlFile xmlFile = extension.getContainingFile(element);
prefix = ExtendedTagInsertHandler.getPrefixByNamespace(xmlFile, namespace);
if (StringUtil.isNotEmpty(prefix)) {
// namespace already declared
ExtendedTagInsertHandler.qualifyWithPrefix(prefix, myElement);
ExtendedTagInsertHandler.qualifyWithPrefix(prefix, element);
return;
}
else {
prefix = ExtendedTagInsertHandler.suggestPrefix(xmlFile, namespace);
if (!StringUtil.isEmpty(prefix)) {
ExtendedTagInsertHandler.qualifyWithPrefix(prefix, myElement);
ExtendedTagInsertHandler.qualifyWithPrefix(prefix, element);
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument());
}
}
@@ -177,7 +186,7 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi
}
private String getTitle() {
return XmlErrorMessages.message("select.namespace.title", StringUtil.capitalize(XmlExtension.getExtension(myFile).getNamespaceAlias(myFile)));
return XmlErrorMessages.message("select.namespace.title", StringUtil.capitalize(getXmlExtension().getNamespaceAlias(getFile())));
}
public boolean startInWriteAction() {
@@ -185,27 +194,28 @@ public class CreateNSDeclarationIntentionFix implements HintAction, LocalQuickFi
}
public boolean showHint(final Editor editor) {
if (myToken == null || !myToken.isValid()) return false;
if (!XmlSettings.getInstance().SHOW_XML_ADD_IMPORT_HINTS || !myElement.isValid() || myNamespacePrefix.length() == 0) {
XmlToken token = (XmlToken)myToken.retrieve();
if (token == null) return false;
if (!XmlSettings.getInstance().SHOW_XML_ADD_IMPORT_HINTS || myNamespacePrefix.length() == 0) {
return false;
}
final Set<String> namespaces = XmlExtension.getExtension(myFile).guessUnboundNamespaces(myElement, myFile);
PsiElement element = ObjectUtils.assertNotNull(myElement.retrieve());
final Set<String> namespaces = getXmlExtension().guessUnboundNamespaces(element, getFile());
if (!namespaces.isEmpty()) {
final String message = ShowAutoImportPass.getMessage(namespaces.size() > 1, namespaces.iterator().next());
final String title = getTitle();
final ImportNSAction action = new ImportNSAction(namespaces, myFile, myElement, editor, title);
if (myElement instanceof XmlTag) {
if (VisibleHighlightingPassFactory.calculateVisibleRange(editor).contains(myToken.getTextRange())) {
final ImportNSAction action = new ImportNSAction(namespaces, getFile(), element, editor, title);
if (element instanceof XmlTag) {
if (VisibleHighlightingPassFactory.calculateVisibleRange(editor).contains(token.getTextRange())) {
HintManager.getInstance().showQuestionHint(editor, message,
myToken.getTextOffset(),
myToken.getTextOffset() + myNamespacePrefix.length(), action);
token.getTextOffset(),
token.getTextOffset() + myNamespacePrefix.length(), action);
return true;
}
} else {
HintManager.getInstance().showQuestionHint(editor, message,
myElement.getTextOffset(),
myElement.getTextRange().getEndOffset(), action);
element.getTextOffset(),
element.getTextRange().getEndOffset(), action);
return true;
}
}
@@ -141,8 +141,7 @@ public class XmlUnboundNsPrefixInspection extends XmlSuppressableInspectionTool
final XmlTag tag = (XmlTag)element;
if (!XmlUtil.JSP_URI.equals(tag.getNamespace())) {
reportTagProblem(tag, localizedMessage, null, ProblemHighlightType.INFORMATION,
isOnTheFly ? new CreateNSDeclarationIntentionFix(context, namespacePrefix, token,
(XmlFile)context.getContainingFile()):null,
isOnTheFly ? new CreateNSDeclarationIntentionFix(context, namespacePrefix, token) : null,
holder);
}
return;
@@ -153,8 +152,7 @@ public class XmlUnboundNsPrefixInspection extends XmlSuppressableInspectionTool
final HighlightInfoType infoType = extension.getHighlightInfoType(containingFile);
final ProblemHighlightType highlightType = infoType == HighlightInfoType.ERROR ? ProblemHighlightType.ERROR : ProblemHighlightType.LIKE_UNKNOWN_SYMBOL;
if (element instanceof XmlTag) {
final CreateNSDeclarationIntentionFix fix = isOnTheFly ? new CreateNSDeclarationIntentionFix(context, namespacePrefix, token,
(XmlFile)context.getContainingFile()):null;
final CreateNSDeclarationIntentionFix fix = isOnTheFly ? new CreateNSDeclarationIntentionFix(context, namespacePrefix, token) : null;
reportTagProblem(element, localizedMessage, range, highlightType, fix, holder);
} else {
holder.registerProblem(element, localizedMessage, highlightType, range);