| /* |
| * 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"; |
| } |
| } |