blob: e0775fd005736bb78937c55a1ff31e5bc7bc4d3b [file] [log] [blame]
/*
* Copyright 2000-2013 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 com.intellij.codeInspection;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.*;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author Dmitry Avdeev
*/
public class DefaultXmlSuppressionProvider extends XmlSuppressionProvider implements InspectionSuppressor {
public static final String SUPPRESS_MARK = "suppress";
@Override
public boolean isProviderAvailable(@NotNull PsiFile file) {
return true;
}
@Override
public boolean isSuppressedFor(@NotNull PsiElement element, @NotNull String inspectionId) {
final XmlTag tag = element instanceof XmlFile ? ((XmlFile)element).getRootTag() : PsiTreeUtil.getContextOfType(element, XmlTag.class, false);
return tag != null && findSuppression(tag, inspectionId, element) != null;
}
@Override
public void suppressForFile(@NotNull PsiElement element, @NotNull String inspectionId) {
final PsiFile file = element.getContainingFile();
final XmlDocument document = ((XmlFile)file).getDocument();
final PsiElement anchor = document != null ? document.getRootTag() : file.findElementAt(0);
assert anchor != null;
suppress(file, findFileSuppression(anchor, null, element), inspectionId, anchor.getTextRange().getStartOffset());
}
@Override
public void suppressForTag(@NotNull PsiElement element, @NotNull String inspectionId) {
final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
assert tag != null;
suppress(element.getContainingFile(), findSuppressionLeaf(tag, null, 0), inspectionId, tag.getTextRange().getStartOffset());
}
@Nullable
protected PsiElement findSuppression(final PsiElement anchor, final String id, PsiElement originalElement) {
final PsiElement element = findSuppressionLeaf(anchor, id, 0);
if (element != null) return element;
return findFileSuppression(anchor, id, originalElement);
}
@Nullable
protected PsiElement findFileSuppression(PsiElement anchor, String id, PsiElement originalElement) {
final PsiFile file = anchor.getContainingFile();
if (file instanceof XmlFile) {
final XmlDocument document = ((XmlFile)file).getDocument();
final XmlTag rootTag = document != null ? document.getRootTag() : null;
PsiElement leaf = rootTag != null ? rootTag.getPrevSibling() : file.findElementAt(0);
return findSuppressionLeaf(leaf, id, 0);
}
return null;
}
@Nullable
protected PsiElement findSuppressionLeaf(PsiElement leaf, @Nullable final String id, int offset) {
while (leaf != null && leaf.getTextOffset() >= offset) {
if (leaf instanceof PsiComment || leaf instanceof XmlProlog || leaf instanceof XmlText) {
@NonNls String text = leaf.getText();
if (isSuppressedFor(text, id)) return leaf;
}
leaf = leaf.getPrevSibling();
if (leaf instanceof XmlTag) {
return null;
}
}
return null;
}
private boolean isSuppressedFor(@NonNls final String text, @Nullable final String id) {
if (!text.contains(getPrefix())) {
return false;
}
if (id == null) {
return true;
}
@NonNls final String[] parts = text.split("[ ,]");
return ArrayUtil.find(parts, id) != -1 || ArrayUtil.find(parts, XmlSuppressableInspectionTool.ALL) != -1;
}
protected void suppress(PsiFile file, final PsiElement suppressionElement, String inspectionId, final int offset) {
final Project project = file.getProject();
if (!FileModificationService.getInstance().prepareFileForWrite(file)) {
return;
}
final Document doc = PsiDocumentManager.getInstance(project).getDocument(file);
assert doc != null;
if (suppressionElement != null) {
final TextRange textRange = suppressionElement.getTextRange();
String text = suppressionElement.getText();
final String suppressionText = getSuppressionText(inspectionId, text);
doc.replaceString(textRange.getStartOffset(), textRange.getEndOffset(), suppressionText);
} else {
final String suppressionText = getSuppressionText(inspectionId, null);
doc.insertString(offset, suppressionText);
CodeStyleManager.getInstance(project).adjustLineIndent(doc, offset + suppressionText.length());
UndoUtil.markPsiFileForUndo(file);
}
}
protected String getSuppressionText(String inspectionId, @Nullable String originalText) {
if (originalText == null) {
return getPrefix() + inspectionId + getSuffix();
} else if (inspectionId.equals(XmlSuppressableInspectionTool.ALL)) {
final int pos = originalText.indexOf(getPrefix());
return originalText.substring(0, pos) + getPrefix() + inspectionId + getSuffix();
}
return originalText.replace(getSuffix(), ", " + inspectionId + getSuffix());
}
@NonNls
protected String getPrefix() {
return "<!--" +
SUPPRESS_MARK +
" ";
}
@NonNls
protected String getSuffix() {
return " -->\n";
}
}