Merge remote-tracking branch 'origin/master'
[idea/community.git] / platform / analysis-impl / src / com / intellij / codeInsight / daemon / impl / actions / AbstractBatchSuppressByNoInspectionCommentFix.java
1 /*
2  * Copyright 2000-2013 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.intellij.codeInsight.daemon.impl.actions;
18
19 import com.intellij.codeInsight.FileModificationService;
20 import com.intellij.codeInspection.InjectionAwareSuppressQuickFix;
21 import com.intellij.codeInspection.InspectionsBundle;
22 import com.intellij.codeInspection.ProblemDescriptor;
23 import com.intellij.codeInspection.SuppressionUtil;
24 import com.intellij.icons.AllIcons;
25 import com.intellij.lang.Language;
26 import com.intellij.openapi.command.undo.UndoUtil;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.util.Iconable;
29 import com.intellij.psi.PsiComment;
30 import com.intellij.psi.PsiElement;
31 import com.intellij.psi.PsiManager;
32 import com.intellij.psi.PsiWhiteSpace;
33 import com.intellij.psi.util.PsiTreeUtil;
34 import com.intellij.util.IncorrectOperationException;
35 import com.intellij.util.ThreeState;
36 import org.jetbrains.annotations.NotNull;
37 import org.jetbrains.annotations.Nullable;
38
39 import javax.swing.*;
40 import java.util.Collections;
41 import java.util.List;
42
43 /**
44  * @author Roman.Chernyatchik
45  * @date Aug 13, 2009
46  */
47 public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements InjectionAwareSuppressQuickFix, Iconable {
48   @NotNull protected final String myID;
49   private final boolean myReplaceOtherSuppressionIds;
50   private ThreeState myShouldBeAppliedToInjectionHost = ThreeState.UNSURE;
51
52   @Nullable
53   public abstract PsiElement getContainer(final PsiElement context);
54
55   /**
56    * @param ID                         Inspection ID
57    * @param replaceOtherSuppressionIds Merge suppression policy. If false new tool id will be append to the end
58    *                                   otherwise replace other ids
59    */
60   public AbstractBatchSuppressByNoInspectionCommentFix(@NotNull String ID, final boolean replaceOtherSuppressionIds) {
61     myID = ID;
62     myReplaceOtherSuppressionIds = replaceOtherSuppressionIds;
63   }
64
65   public void setShouldBeAppliedToInjectionHost(ThreeState shouldBeAppliedToInjectionHost) {
66     myShouldBeAppliedToInjectionHost = shouldBeAppliedToInjectionHost;
67   }
68
69   @Override
70   public ThreeState isShouldBeAppliedToInjectionHost() {
71     return myShouldBeAppliedToInjectionHost;
72   }
73
74   @NotNull
75   @Override
76   public String getName() {
77     return getText();
78   }
79
80   @Override
81   public Icon getIcon(int flags) {
82     return AllIcons.General.InspectionsOff;
83   }
84
85   private String myText = "";
86   @NotNull
87   public String getText() {
88     return myText;
89   }
90
91   protected void setText(@NotNull String text) {
92     myText = text;
93   }
94
95   public boolean startInWriteAction() {
96     return true;
97   }
98
99   @Override
100   public String toString() {
101     return getText();
102   }
103
104   @Override
105   public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
106     PsiElement element = descriptor.getStartElement();
107     if (element == null) return;
108     invoke(project, element);
109   }
110
111   protected final void replaceSuppressionComment(@NotNull final PsiElement comment) {
112     SuppressionUtil.replaceSuppressionComment(comment, myID, myReplaceOtherSuppressionIds, getCommentLanguage(comment));
113   }
114
115   protected void createSuppression(@NotNull Project project,
116                                    @NotNull PsiElement element,
117                                    @NotNull PsiElement container) throws IncorrectOperationException {
118     SuppressionUtil.createSuppression(project, container, myID, getCommentLanguage(element));
119   }
120
121   /**
122    * @param element quickfix target or existing comment element
123    * @return language that will be used for comment creating.
124    * In common case language will be the same as language of quickfix target
125    */
126   @NotNull
127   protected Language getCommentLanguage(@NotNull PsiElement element) {
128     return element.getLanguage();
129   }
130
131   @Override
132   public boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement context) {
133     return context.isValid() && PsiManager.getInstance(project).isInProject(context) && getContainer(context) != null;
134   }
135
136   public void invoke(@NotNull final Project project, @NotNull final PsiElement element) throws IncorrectOperationException {
137     if (!isAvailable(project, element)) return;
138     PsiElement container = getContainer(element);
139     if (container == null) return;
140
141     if (!FileModificationService.getInstance().preparePsiElementForWrite(container)) return;
142
143     if (replaceSuppressionComments(container)) return;
144
145     createSuppression(project, element, container);
146     UndoUtil.markPsiFileForUndo(element.getContainingFile());
147   }
148
149   protected boolean replaceSuppressionComments(PsiElement container) {
150     final List<? extends PsiElement> comments = getCommentsFor(container);
151     if (comments != null) {
152       for (PsiElement comment : comments) {
153         if (comment instanceof PsiComment && SuppressionUtil.isSuppressionComment(comment)) {
154           replaceSuppressionComment(comment);
155           return true;
156         }
157       }
158     }
159     return false;
160   }
161
162   @Nullable
163   protected List<? extends PsiElement> getCommentsFor(@NotNull final PsiElement container) {
164     final PsiElement prev = PsiTreeUtil.skipSiblingsBackward(container, PsiWhiteSpace.class);
165     if (prev == null) {
166       return null;
167     }
168     return Collections.singletonList(prev);
169   }
170
171
172   @Override
173   @NotNull
174   public String getFamilyName() {
175     return InspectionsBundle.message("suppress.inspection.family");
176   }
177 }