Provide suppression fixes in injections for suppressing inspection in host file

This commit is contained in:
Alexander Zolotov
2015-01-30 18:08:40 +03:00
parent 4ae4833f60
commit 024f3f5039
5 changed files with 112 additions and 25 deletions
@@ -0,0 +1,18 @@
package com.intellij.codeInspection;
import com.intellij.psi.PsiElement;
import com.intellij.util.ThreeState;
/**
* This kind of suppression fix allows to clients to specify whether the fix should
* be invoked on injected elements or on elements of host files.
* <p/>
* By default suppression fixes on injected elements are able to make suppression inside injection only.
* Whereas implementation of this interface will be provided for suppressing inside injection and in injection host.
* See {@link InspectionProfileEntry#getBatchSuppressActions(PsiElement)} for details.
*/
public interface InjectionAwareSuppressQuickFix extends SuppressQuickFix {
ThreeState isShouldBeAppliedToInjectionHost();
void setShouldBeAppliedToInjectionHost(ThreeState shouldBeAppliedToInjectionHost);
}
@@ -17,6 +17,7 @@ package com.intellij.codeInspection;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.lang.Language;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
@@ -24,8 +25,10 @@ import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLanguageInjectionHost;
import com.intellij.psi.templateLanguages.TemplateLanguageFileViewProvider;
import com.intellij.util.ResourceUtil;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xmlb.SerializationFilter;
import com.intellij.util.xmlb.SkipDefaultValuesSerializationFilters;
@@ -44,14 +47,16 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* @author anna
* @since 28-Nov-2005
*/
@SuppressWarnings("JavadocReference")
public abstract class InspectionProfileEntry implements BatchSuppressableTool{
public abstract class InspectionProfileEntry implements BatchSuppressableTool {
public static final String GENERAL_GROUP_NAME = InspectionsBundle.message("inspection.general.tools.group.name");
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.InspectionProfileEntry");
@@ -93,22 +98,52 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
Set<SuppressQuickFix> fixes = new THashSet<SuppressQuickFix>(new TObjectHashingStrategy<SuppressQuickFix>() {
@Override
public int computeHashCode(SuppressQuickFix object) {
return object.getName().hashCode();
int result = object instanceof InjectionAwareSuppressQuickFix
? ((InjectionAwareSuppressQuickFix)object).isShouldBeAppliedToInjectionHost().hashCode()
: 0;
return 31 * result + object.getName().hashCode();
}
@Override
public boolean equals(SuppressQuickFix o1, SuppressQuickFix o2) {
if (o1 instanceof InjectionAwareSuppressQuickFix && o2 instanceof InjectionAwareSuppressQuickFix) {
if (((InjectionAwareSuppressQuickFix)o1).isShouldBeAppliedToInjectionHost() != ((InjectionAwareSuppressQuickFix)o2).isShouldBeAppliedToInjectionHost()) {
return false;
}
}
return o1.getName().equals(o2.getName());
}
});
Set<InspectionSuppressor> suppressors = getSuppressors(element);
final PsiLanguageInjectionHost injectionHost = InjectedLanguageManager.getInstance(element.getProject()).getInjectionHost(element);
if (injectionHost != null) {
Set<InspectionSuppressor> injectionHostSuppressors = getSuppressors(injectionHost);
for (InspectionSuppressor suppressor : injectionHostSuppressors) {
addAllSuppressActions(fixes, injectionHost, suppressor, ThreeState.YES, getShortName());
}
}
for (InspectionSuppressor suppressor : suppressors) {
SuppressQuickFix[] actions = suppressor.getSuppressActions(element, getShortName());
fixes.addAll(Arrays.asList(actions));
addAllSuppressActions(fixes, element, suppressor, injectionHost != null ? ThreeState.NO : ThreeState.UNSURE, getShortName());
}
return fixes.toArray(new SuppressQuickFix[fixes.size()]);
}
private static void addAllSuppressActions(Set<SuppressQuickFix> fixes,
PsiElement element,
InspectionSuppressor suppressor,
ThreeState appliedToInjectionHost,
String toolShortName) {
final SuppressQuickFix[] actions = suppressor.getSuppressActions(element, toolShortName);
for (SuppressQuickFix action : actions) {
if (action instanceof InjectionAwareSuppressQuickFix) {
((InjectionAwareSuppressQuickFix)action).setShouldBeAppliedToInjectionHost(appliedToInjectionHost);
}
fixes.add(action);
}
}
private boolean isSuppressed(@NotNull String toolId,
@NotNull InspectionSuppressor suppressor,
@NotNull PsiElement element) {
@@ -132,7 +167,9 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
ContainerUtil.addIfNotNull(suppressors, elementLanguageSuppressor);
return suppressors;
}
return elementLanguageSuppressor != null ? Collections.singleton(elementLanguageSuppressor) : Collections.<InspectionSuppressor>emptySet();
return elementLanguageSuppressor != null
? Collections.singleton(elementLanguageSuppressor)
: Collections.<InspectionSuppressor>emptySet();
}
public void cleanup(Project project) {
@@ -148,9 +185,9 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
protected volatile DefaultNameProvider myNameProvider = null;
/**
* @see com.intellij.codeInspection.InspectionEP#groupDisplayName
* @see com.intellij.codeInspection.InspectionEP#groupKey
* @see com.intellij.codeInspection.InspectionEP#groupBundle
* @see InspectionEP#groupDisplayName
* @see InspectionEP#groupKey
* @see InspectionEP#groupBundle
*/
@Nls
@NotNull
@@ -166,7 +203,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
}
/**
* @see com.intellij.codeInspection.InspectionEP#groupPath
* @see InspectionEP#groupPath
*/
@NotNull
public String[] getGroupPath() {
@@ -178,9 +215,9 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
}
/**
* @see com.intellij.codeInspection.InspectionEP#displayName
* @see com.intellij.codeInspection.InspectionEP#key
* @see com.intellij.codeInspection.InspectionEP#bundle
* @see InspectionEP#displayName
* @see InspectionEP#key
* @see InspectionEP#bundle
*/
@Nls
@NotNull
@@ -198,7 +235,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
/**
* DO NOT OVERRIDE this method.
*
* @see com.intellij.codeInspection.InspectionEP#shortName
* @see InspectionEP#shortName
*/
@NonNls
@NotNull
@@ -214,13 +251,13 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
@NotNull
public static String getShortName(@NotNull String className) {
return StringUtil.trimEnd(StringUtil.trimEnd(className, "Inspection"),"InspectionBase");
return StringUtil.trimEnd(StringUtil.trimEnd(className, "Inspection"), "InspectionBase");
}
/**
* DO NOT OVERRIDE this method.
*
* @see com.intellij.codeInspection.InspectionEP#level
* @see InspectionEP#level
*/
@NotNull
public HighlightDisplayLevel getDefaultLevel() {
@@ -230,7 +267,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
/**
* DO NOT OVERRIDE this method.
*
* @see com.intellij.codeInspection.InspectionEP#enabledByDefault
* @see InspectionEP#enabledByDefault
*/
public boolean isEnabledByDefault() {
return false;
@@ -238,6 +275,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
/**
* This method is called each time UI is shown.
*
* @return null if no UI options required.
*/
@Nullable
@@ -348,7 +386,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
* Initialize inspection with project. Is called on project opened for all profiles as well as on profile creation.
*
* @param project to be associated with this entry
* @deprecated this won't work for inspections configured via {@link com.intellij.codeInspection.InspectionEP}
* @deprecated this won't work for inspections configured via {@link InspectionEP}
*/
public void projectOpened(@NotNull Project project) {
}
@@ -357,7 +395,7 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
* Cleanup inspection settings corresponding to the project. Is called on project closed for all profiles as well as on profile deletion.
*
* @param project to be disassociated from this entry
* @deprecated this won't work for inspections configured via {@link com.intellij.codeInspection.InspectionEP}
* @deprecated this won't work for inspections configured via {@link InspectionEP}
*/
public void projectClosed(@NotNull Project project) {
}
@@ -411,7 +449,8 @@ public abstract class InspectionProfileEntry implements BatchSuppressableTool{
if (descriptionUrl == null) return null;
return ResourceUtil.loadText(descriptionUrl);
}
catch (IOException ignored) { }
catch (IOException ignored) {
}
return null;
}
@@ -17,9 +17,9 @@
package com.intellij.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInspection.InjectionAwareSuppressQuickFix;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.SuppressQuickFix;
import com.intellij.codeInspection.SuppressionUtil;
import com.intellij.icons.AllIcons;
import com.intellij.lang.Language;
@@ -32,6 +32,7 @@ import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -43,9 +44,10 @@ import java.util.List;
* @author Roman.Chernyatchik
* @date Aug 13, 2009
*/
public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements SuppressQuickFix, Iconable {
public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements InjectionAwareSuppressQuickFix, Iconable {
@NotNull protected final String myID;
private final boolean myReplaceOtherSuppressionIds;
private ThreeState myShouldBeAppliedToInjectionHost = ThreeState.UNSURE;
@Nullable
public abstract PsiElement getContainer(final PsiElement context);
@@ -60,6 +62,15 @@ public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements S
myReplaceOtherSuppressionIds = replaceOtherSuppressionIds;
}
public void setShouldBeAppliedToInjectionHost(ThreeState shouldBeAppliedToInjectionHost) {
myShouldBeAppliedToInjectionHost = shouldBeAppliedToInjectionHost;
}
@Override
public ThreeState isShouldBeAppliedToInjectionHost() {
return myShouldBeAppliedToInjectionHost;
}
@NotNull
@Override
public String getName() {
@@ -21,6 +21,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ThreeState;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -59,9 +60,15 @@ public class SuppressIntentionActionFromFix extends SuppressIntentionAction {
}
}
public ThreeState isShouldBeAppliedToInjectionHost() {
return myFix instanceof InjectionAwareSuppressQuickFix
? ((InjectionAwareSuppressQuickFix)myFix).isShouldBeAppliedToInjectionHost()
: ThreeState.UNSURE;
}
public PsiElement getContainer(PsiElement element) {
return myFix instanceof AbstractBatchSuppressByNoInspectionCommentFix
? ((AbstractBatchSuppressByNoInspectionCommentFix )myFix).getContainer(element) : null;
? ((AbstractBatchSuppressByNoInspectionCommentFix)myFix).getContainer(element) : null;
}
@Override
@@ -72,7 +79,7 @@ public class SuppressIntentionActionFromFix extends SuppressIntentionAction {
@NotNull
@Override
public String getText() {
return myFix.getName();
return myFix.getName() + (isShouldBeAppliedToInjectionHost() == ThreeState.NO ? " in injection" : "");
}
@NotNull
@@ -27,6 +27,7 @@ import com.intellij.codeInsight.lookup.LookupEx;
import com.intellij.codeInsight.lookup.LookupManager;
import com.intellij.codeInsight.template.impl.TemplateManagerImpl;
import com.intellij.codeInsight.template.impl.TemplateState;
import com.intellij.codeInspection.SuppressIntentionActionFromFix;
import com.intellij.featureStatistics.FeatureUsageTracker;
import com.intellij.featureStatistics.FeatureUsageTrackerImpl;
import com.intellij.injected.editor.EditorWindow;
@@ -45,6 +46,7 @@ import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PairProcessor;
import com.intellij.util.ThreeState;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -107,6 +109,16 @@ public class ShowIntentionActionsHandler implements CodeInsightActionHandler {
private static boolean isAvailableHere(Editor editor, PsiFile psiFile, PsiElement psiElement, boolean inProject, IntentionAction action) {
try {
Project project = psiFile.getProject();
if (action instanceof SuppressIntentionActionFromFix) {
final ThreeState shouldBeAppliedToInjectionHost = ((SuppressIntentionActionFromFix)action).isShouldBeAppliedToInjectionHost();
if (editor instanceof EditorWindow && shouldBeAppliedToInjectionHost == ThreeState.YES) {
return false;
}
if (!(editor instanceof EditorWindow) && shouldBeAppliedToInjectionHost == ThreeState.NO) {
return false;
}
}
if (action instanceof PsiElementBaseIntentionAction) {
if (!inProject || psiElement == null || !((PsiElementBaseIntentionAction)action).isAvailable(project, editor, psiElement)) return false;
}