Introduced BatchSuppressableTool which, unlike CustomSuppressableInspectionTool, provides SuppressQuickFixes, not SuppressIntentionActions.

SuppressQuickFix doesn't need Editor so it can work in batches.
These fixes are available via BatchSuppressManager.
Reworked some inspections to extend BatchSuppressableTool instead of CustomSuppressableInspectionTool since they don't need Editor anyway.
Similarly, instead of BaseJavaLocalInspectionTool there is BaseJavaBatchLocalInspectionTool.
This commit is contained in:
Alexey Kudravtsev
2013-05-08 11:43:48 +04:00
parent b5ef5dbd09
commit 8df07569f2
52 changed files with 2022 additions and 1117 deletions
@@ -25,7 +25,6 @@ import com.intellij.ide.errorTreeView.NewErrorTreeViewPanel;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.module.LanguageLevelUtil;
import com.intellij.openapi.module.Module;
@@ -86,7 +85,7 @@ public class CompilerErrorTreeView extends NewErrorTreeViewPanel {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
try {
suppressInspectionFix.invoke(project, null, file.findElementAt(navigatable.getOffset()));
suppressInspectionFix.invoke(project, file.findElementAt(navigatable.getOffset()));
}
catch (IncorrectOperationException e1) {
LOG.error(e1);
@@ -139,7 +138,7 @@ public class CompilerErrorTreeView extends NewErrorTreeViewPanel {
}
final String id = text[0].substring(1, text[0].indexOf("]"));
final SuppressFix suppressInspectionFix = getSuppressAction(id);
final boolean available = suppressInspectionFix.isAvailable(project, null, context);
final boolean available = suppressInspectionFix.isAvailable(project, context);
presentation.setEnabled(available);
presentation.setVisible(available);
if (available) {
@@ -151,13 +150,13 @@ public class CompilerErrorTreeView extends NewErrorTreeViewPanel {
}
}
protected SuppressFix getSuppressAction(final String id) {
protected SuppressFix getSuppressAction(@NotNull final String id) {
return new SuppressFix(id) {
@Override
@SuppressWarnings({"SimplifiableIfStatement"})
public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement context) {
public boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement context) {
if (getContainer(context) instanceof PsiClass) return false;
return super.isAvailable(project, editor, context);
return super.isAvailable(project, context);
}
@Override
@@ -170,7 +169,7 @@ public class CompilerErrorTreeView extends NewErrorTreeViewPanel {
private class SuppressJavacWarningForClassAction extends SuppressJavacWarningsAction {
@Override
protected SuppressFix getSuppressAction(final String id) {
protected SuppressFix getSuppressAction(@NotNull final String id) {
return new SuppressForClassFix(id){
@Override
protected boolean use15Suppressions(@NotNull final PsiDocCommentOwner container) {
@@ -0,0 +1,110 @@
/*
* 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.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class AbstractBaseJavaLocalInspectionTool extends LocalInspectionTool {
/**
* Override this to report problems at method level.
*
* @param method to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at method level.
*/
@Nullable
public ProblemDescriptor[] checkMethod(@NotNull PsiMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) {
return null;
}
/**
* Override this to report problems at class level.
*
* @param aClass to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at class level.
*/
@Nullable
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
return null;
}
/**
* Override this to report problems at field level.
*
* @param field to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at field level.
*/
@Nullable
public ProblemDescriptor[] checkField(@NotNull PsiField field, @NotNull InspectionManager manager, boolean isOnTheFly) {
return null;
}
/**
* Override this to report problems at file level.
*
* @param file to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at file level.
*/
@Override
@Nullable
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
return null;
}
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override public void visitMethod(PsiMethod method) {
addDescriptors(checkMethod(method, holder.getManager(), isOnTheFly));
}
@Override public void visitClass(PsiClass aClass) {
addDescriptors(checkClass(aClass, holder.getManager(), isOnTheFly));
}
@Override public void visitField(PsiField field) {
addDescriptors(checkField(field, holder.getManager(), isOnTheFly));
}
@Override public void visitFile(PsiFile file) {
addDescriptors(checkFile(file, holder.getManager(), isOnTheFly));
}
private void addDescriptors(final ProblemDescriptor[] descriptors) {
if (descriptors != null) {
for (ProblemDescriptor descriptor : descriptors) {
holder.registerProblem(descriptor);
}
}
}
};
}
@Override
public PsiNamedElement getProblemElement(final PsiElement psiElement) {
return PsiTreeUtil.getNonStrictParentOfType(psiElement, PsiFile.class, PsiClass.class, PsiMethod.class, PsiField.class);
}
}
@@ -0,0 +1,43 @@
/*
* 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.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class BaseJavaBatchLocalInspectionTool extends AbstractBaseJavaLocalInspectionTool implements BatchSuppressableTool {
@NotNull
@Override
public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
return SuppressQuickFix.EMPTY_ARRAY;
}
@Override
public boolean isSuppressedFor(@NotNull PsiElement element) {
return isSuppressedFor(element, this);
}
public static boolean isSuppressedFor(@NotNull PsiElement element, @NotNull LocalInspectionTool tool) {
final BatchSuppressManager manager = BatchSuppressManager.SERVICE.getInstance();
String alternativeId;
String id;
return manager.isSuppressedFor(element, id = tool.getID()) ||
(alternativeId = tool.getAlternativeID()) != null &&
!alternativeId.equals(id) &&
manager.isSuppressedFor(element, alternativeId);
}
}
@@ -0,0 +1,59 @@
/*
* 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.daemon.HighlightDisplayKey;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.psi.PsiDocCommentOwner;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiModifierListOwner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface BatchSuppressManager {
class SERVICE {
public static BatchSuppressManager getInstance() {
return ServiceManager.getService(BatchSuppressManager.class);
}
}
@NotNull
SuppressQuickFix[] createBatchSuppressActions(@NotNull HighlightDisplayKey key);
boolean isSuppressedFor(@NotNull PsiElement element, String toolId);
PsiElement getElementMemberSuppressedIn(@NotNull PsiDocCommentOwner owner, String inspectionToolID);
@Nullable
PsiElement getAnnotationMemberSuppressedIn(@NotNull PsiModifierListOwner owner, String inspectionToolID);
@Nullable
PsiElement getDocCommentToolSuppressedIn(@NotNull PsiDocCommentOwner owner, String inspectionToolID);
@NotNull
Collection<String> getInspectionIdsSuppressedInAnnotation(@NotNull PsiModifierListOwner owner);
@Nullable
String getSuppressedInspectionIdsIn(@NotNull PsiElement element);
@Nullable
PsiElement getElementToolSuppressedIn(@NotNull PsiElement place, String toolId);
boolean canHave15Suppressions(@NotNull PsiElement file);
boolean alreadyHas14Suppressions(@NotNull PsiDocCommentOwner commentOwner);
}
@@ -16,12 +16,10 @@
package com.intellij.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.SuppressManager;
import com.intellij.codeInspection.JavaSuppressionUtil;
import com.intellij.codeInspection.SuppressionUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
@@ -44,7 +42,7 @@ public class SuppressAllForClassFix extends SuppressFix {
@Override
@Nullable
protected PsiDocCommentOwner getContainer(final PsiElement element) {
public PsiDocCommentOwner getContainer(final PsiElement element) {
PsiDocCommentOwner container = super.getContainer(element);
if (container == null) {
return null;
@@ -66,17 +64,17 @@ public class SuppressAllForClassFix extends SuppressFix {
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
public void invoke(@NotNull final Project project, @NotNull final PsiElement element) throws IncorrectOperationException {
final PsiDocCommentOwner container = getContainer(element);
LOG.assertTrue(container != null);
if (!FileModificationService.getInstance().preparePsiElementForWrite(container)) return;
if (use15Suppressions(container)) {
final PsiModifierList modifierList = container.getModifierList();
if (modifierList != null) {
final PsiAnnotation annotation = modifierList.findAnnotation(SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
final PsiAnnotation annotation = modifierList.findAnnotation(JavaSuppressionUtil.SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
if (annotation != null) {
annotation.replace(JavaPsiFacade.getInstance(project).getElementFactory().createAnnotationFromText("@" +
SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "(\"" +
JavaSuppressionUtil.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "(\"" +
SuppressionUtil.ALL + "\")", container));
return;
}
@@ -89,12 +87,13 @@ public class SuppressAllForClassFix extends SuppressFix {
if (noInspectionTag != null) {
String tagText = "@" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + SuppressionUtil.ALL;
noInspectionTag.replace(JavaPsiFacade.getInstance(project).getElementFactory().createDocTagFromText(tagText));
DaemonCodeAnalyzer.getInstance(project).restart();
// todo suppress
//DaemonCodeAnalyzer.getInstance(project).restart();
return;
}
}
}
super.invoke(project, editor, element);
super.invoke(project, element);
}
}
@@ -0,0 +1,67 @@
/*
* 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.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInspection.JavaSuppressionUtil;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class SuppressByJavaCommentFix extends SuppressByCommentFix {
public SuppressByJavaCommentFix(@NotNull HighlightDisplayKey key) {
super(key, PsiStatement.class);
}
@Override
@Nullable
public PsiElement getContainer(PsiElement context) {
if (hasJspMethodCallAsParent(context)) return null;
return PsiTreeUtil.getParentOfType(context, PsiStatement.class, false);
}
private static boolean hasJspMethodCallAsParent(PsiElement context) {
while (true) {
PsiMethod method = PsiTreeUtil.getParentOfType(context, PsiMethod.class);
if (method == null) return false;
if (method instanceof SyntheticElement) return true;
context = method;
}
}
@Override
protected void createSuppression(@NotNull final Project project,
@NotNull final PsiElement element,
@NotNull final PsiElement container) throws IncorrectOperationException {
PsiElement declaredElement = JavaSuppressionUtil.getElementToAnnotate(element, container);
if (declaredElement == null) {
suppressWithComment(project, element, container);
}
else {
JavaSuppressionUtil.addSuppressAnnotation(project, container, (PsiLocalVariable)declaredElement, myID);
}
}
protected void suppressWithComment(Project project, PsiElement element, PsiElement container) {
super.createSuppression(project, element, container);
}
}
@@ -0,0 +1,159 @@
/*
* 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.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.JavaSuppressionUtil;
import com.intellij.codeInspection.SuppressionUtil;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.impl.storage.ClassPathStorageUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author ven
*/
public class SuppressFix extends AbstractBatchSuppressByNoInspectionCommentFix {
private String myAlternativeID;
public SuppressFix(@NotNull HighlightDisplayKey key) {
this(key.getID());
myAlternativeID = HighlightDisplayKey.getAlternativeID(key);
}
public SuppressFix(@NotNull String ID) {
super(ID, false);
}
@Override
@NotNull
public String getText() {
String myText = super.getText();
return StringUtil.isEmpty(myText) ? "Suppress for member" : myText;
}
@Override
@Nullable
public PsiDocCommentOwner getContainer(final PsiElement context) {
if (context == null || !context.getManager().isInProject(context)) {
return null;
}
final PsiFile containingFile = context.getContainingFile();
if (containingFile == null) {
// for PsiDirectory
return null;
}
if (!containingFile.getLanguage().isKindOf(JavaLanguage.INSTANCE) || context instanceof PsiFile) {
return null;
}
PsiElement container = context;
while (container instanceof PsiAnonymousClass || !(container instanceof PsiDocCommentOwner) || container instanceof PsiTypeParameter) {
container = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class);
if (container == null) return null;
}
return (PsiDocCommentOwner)container;
}
@Override
public boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement context) {
PsiDocCommentOwner container = getContainer(context);
boolean isValid = container != null && !(container instanceof PsiMethod && container instanceof SyntheticElement);
if (!isValid) {
return false;
}
setText(container instanceof PsiClass
? InspectionsBundle.message("suppress.inspection.class")
: container instanceof PsiMethod ? InspectionsBundle.message("suppress.inspection.method") : InspectionsBundle.message("suppress.inspection.field"));
return true;
}
@Override
public void invoke(@NotNull final Project project, @NotNull final PsiElement element) throws IncorrectOperationException {
if (doSuppress(project, getContainer(element))) return;
// todo suppress
//DaemonCodeAnalyzer.getInstance(project).restart();
UndoUtil.markPsiFileForUndo(element.getContainingFile());
}
private boolean doSuppress(@NotNull Project project, PsiDocCommentOwner container) {
assert container != null;
if (!FileModificationService.getInstance().preparePsiElementForWrite(container)) return true;
if (use15Suppressions(container)) {
final PsiModifierList modifierList = container.getModifierList();
if (modifierList != null) {
JavaSuppressionUtil.addSuppressAnnotation(project, container, container, getID(container));
}
}
else {
PsiDocComment docComment = container.getDocComment();
PsiManager manager = PsiManager.getInstance(project);
if (docComment == null) {
String commentText = "/** @" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + getID(container) + "*/";
docComment = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocCommentFromText(commentText);
PsiElement firstChild = container.getFirstChild();
container.addBefore(docComment, firstChild);
}
else {
PsiDocTag noInspectionTag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME);
if (noInspectionTag != null) {
String tagText = noInspectionTag.getText() + ", " + getID(container);
noInspectionTag.replace(JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocTagFromText(tagText));
}
else {
String tagText = "@" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + getID(container);
docComment.add(JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocTagFromText(tagText));
}
}
}
return false;
}
protected boolean use15Suppressions(@NotNull PsiDocCommentOwner container) {
return JavaSuppressionUtil.canHave15Suppressions(container) &&
!JavaSuppressionUtil.alreadyHas14Suppressions(container);
}
private String getID(@NotNull PsiElement place) {
String id = getID(place, myAlternativeID);
return id != null ? id : myID;
}
@Nullable
static String getID(@NotNull PsiElement place, String alternativeID) {
if (alternativeID != null) {
final Module module = ModuleUtilCore.findModuleForPsiElement(place);
if (module != null) {
if (!ClassPathStorageUtil.isDefaultStorage(module)) {
return alternativeID;
}
}
}
return null;
}
}
@@ -39,7 +39,8 @@ public class SuppressForClassFix extends SuppressFix {
}
@Override
@Nullable protected PsiDocCommentOwner getContainer(final PsiElement element) {
@Nullable
public PsiDocCommentOwner getContainer(final PsiElement element) {
PsiDocCommentOwner container = super.getContainer(element);
if (container == null || container instanceof PsiClass){
return null;
@@ -16,7 +16,7 @@
package com.intellij.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.openapi.editor.Editor;
import com.intellij.codeInspection.JavaSuppressionUtil;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.util.IncorrectOperationException;
@@ -27,25 +27,25 @@ import org.jetbrains.annotations.Nullable;
* User: anna
*/
public class SuppressLocalWithCommentFix extends SuppressByJavaCommentFix {
public SuppressLocalWithCommentFix(HighlightDisplayKey key) {
public SuppressLocalWithCommentFix(@NotNull HighlightDisplayKey key) {
super(key);
}
@Nullable
@Override
protected PsiElement getContainer(PsiElement context) {
public PsiElement getContainer(PsiElement context) {
final PsiElement container = super.getContainer(context);
if (container != null) {
final PsiElement elementToAnnotate = getElementToAnnotate(context, container);
final PsiElement elementToAnnotate = JavaSuppressionUtil.getElementToAnnotate(context, container);
if (elementToAnnotate == null) return null;
}
return container;
}
@Override
protected void createSuppression(Project project, Editor editor, PsiElement element, PsiElement container)
protected void createSuppression(@NotNull Project project, @NotNull PsiElement element, @NotNull PsiElement container)
throws IncorrectOperationException {
suppressWithComment(project, editor, element, container);
suppressWithComment(project, element, container);
}
@NotNull
@@ -15,35 +15,31 @@
*/
package com.intellij.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.SuppressManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.codeInspection.JavaSuppressionUtil;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiModifierList;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author ven
*/
public class SuppressParameterFix extends SuppressIntentionAction {
private final String myID;
public class SuppressParameterFix extends AbstractBatchSuppressByNoInspectionCommentFix {
private String myAlternativeID;
public SuppressParameterFix(HighlightDisplayKey key) {
public SuppressParameterFix(@NotNull HighlightDisplayKey key) {
this(key.getID());
myAlternativeID = HighlightDisplayKey.getAlternativeID(key);
}
public SuppressParameterFix(String ID) {
myID = ID;
super(ID, false);
}
@Override
@@ -52,28 +48,26 @@ public class SuppressParameterFix extends SuppressIntentionAction {
return "Suppress for parameter";
}
@Nullable
@Override
@NotNull
public String getFamilyName() {
return InspectionsBundle.message("suppress.inspection.family");
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement context) {
public PsiElement getContainer(PsiElement context) {
PsiParameter psiParameter = PsiTreeUtil.getParentOfType(context, PsiParameter.class, false);
return psiParameter != null && SuppressManager.getInstance().canHave15Suppressions(psiParameter);
return psiParameter != null && JavaSuppressionUtil.canHave15Suppressions(psiParameter) ? psiParameter : null;
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
PsiParameter container = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false);
assert container != null;
if (!FileModificationService.getInstance().preparePsiElementForWrite(container)) return;
protected boolean replaceSuppressionComments(PsiElement container) {
return false;
}
@Override
protected void createSuppression(@NotNull Project project, @NotNull PsiElement element, @NotNull PsiElement cont)
throws IncorrectOperationException {
PsiModifierListOwner container = (PsiModifierListOwner)cont;
final PsiModifierList modifierList = container.getModifierList();
if (modifierList != null) {
final String id = SuppressFix.getID(container, myAlternativeID);
SuppressFix.addSuppressAnnotation(project, editor, container, container, id != null ? id : myID);
JavaSuppressionUtil.addSuppressAnnotation(project, container, container, id != null ? id : myID);
}
DaemonCodeAnalyzer.getInstance(project).restart();
}
}
@@ -0,0 +1,93 @@
/*
* 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.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.actions.*;
import com.intellij.psi.PsiDocCommentOwner;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiModifierListOwner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public class BatchSuppressManagerImpl implements BatchSuppressManager {
@NotNull
@Override
public SuppressQuickFix[] createBatchSuppressActions(@NotNull HighlightDisplayKey displayKey) {
return new SuppressQuickFix[] {
new SuppressByJavaCommentFix(displayKey),
new SuppressLocalWithCommentFix(displayKey),
new SuppressParameterFix(displayKey),
new SuppressFix(displayKey),
new SuppressForClassFix(displayKey),
new SuppressAllForClassFix()
};
}
@Override
public boolean isSuppressedFor(@NotNull final PsiElement element, final String toolId) {
return JavaSuppressionUtil.getElementToolSuppressedIn(element, toolId) != null;
}
@Override
@Nullable
public PsiElement getElementMemberSuppressedIn(@NotNull final PsiDocCommentOwner owner, final String inspectionToolID) {
return JavaSuppressionUtil.getElementMemberSuppressedIn(owner, inspectionToolID);
}
@Override
@Nullable
public PsiElement getAnnotationMemberSuppressedIn(@NotNull final PsiModifierListOwner owner, final String inspectionToolID) {
return JavaSuppressionUtil.getAnnotationMemberSuppressedIn(owner, inspectionToolID);
}
@Override
@Nullable
public PsiElement getDocCommentToolSuppressedIn(@NotNull final PsiDocCommentOwner owner, final String inspectionToolID) {
return JavaSuppressionUtil.getDocCommentToolSuppressedIn(owner, inspectionToolID);
}
@Override
@NotNull
public Collection<String> getInspectionIdsSuppressedInAnnotation(@NotNull final PsiModifierListOwner owner) {
return JavaSuppressionUtil.getInspectionIdsSuppressedInAnnotation(owner);
}
@Override
@Nullable
public String getSuppressedInspectionIdsIn(@NotNull PsiElement element) {
return JavaSuppressionUtil.getSuppressedInspectionIdsIn(element);
}
@Override
@Nullable
public PsiElement getElementToolSuppressedIn(@NotNull final PsiElement place, final String toolId) {
return JavaSuppressionUtil.getElementToolSuppressedIn(place, toolId);
}
@Override
public boolean canHave15Suppressions(@NotNull final PsiElement file) {
return JavaSuppressionUtil.canHave15Suppressions(file);
}
@Override
public boolean alreadyHas14Suppressions(@NotNull final PsiDocCommentOwner commentOwner) {
return JavaSuppressionUtil.alreadyHas14Suppressions(commentOwner);
}
}
@@ -0,0 +1,320 @@
/*
* 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.AnnotationUtil;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.JdkVersionUtil;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiVariableEx;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Generated;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.regex.Matcher;
public class JavaSuppressionUtil {
public static final String SUPPRESS_INSPECTIONS_ANNOTATION_NAME = "java.lang.SuppressWarnings";
public static boolean alreadyHas14Suppressions(@NotNull PsiDocCommentOwner commentOwner) {
final PsiDocComment docComment = commentOwner.getDocComment();
return docComment != null && docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME) != null;
}
@Nullable
public static String getInspectionIdSuppressedInAnnotationAttribute(PsiElement element) {
if (element instanceof PsiLiteralExpression) {
final Object value = ((PsiLiteralExpression)element).getValue();
if (value instanceof String) {
return (String)value;
}
}
else if (element instanceof PsiReferenceExpression) {
final PsiElement psiElement = ((PsiReferenceExpression)element).resolve();
if (psiElement instanceof PsiVariableEx) {
final Object val = ((PsiVariableEx)psiElement).computeConstantValue(new HashSet<PsiVariable>());
if (val instanceof String) {
return (String)val;
}
}
}
return null;
}
@NotNull
public static Collection<String> getInspectionIdsSuppressedInAnnotation(final PsiModifierList modifierList) {
if (modifierList == null) {
return Collections.emptyList();
}
final PsiModifierListOwner owner = (PsiModifierListOwner)modifierList.getParent();
PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
if (annotation == null) {
return Collections.emptyList();
}
final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
if (attributes.length == 0) {
return Collections.emptyList();
}
final PsiAnnotationMemberValue attributeValue = attributes[0].getValue();
Collection<String> result = new ArrayList<String>();
if (attributeValue instanceof PsiArrayInitializerMemberValue) {
final PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)attributeValue).getInitializers();
for (PsiAnnotationMemberValue annotationMemberValue : initializers) {
final String id = getInspectionIdSuppressedInAnnotationAttribute(annotationMemberValue);
if (id != null) {
result.add(id);
}
}
}
else {
final String id = getInspectionIdSuppressedInAnnotationAttribute(attributeValue);
if (id != null) {
result.add(id);
}
}
return result;
}
static PsiElement getElementMemberSuppressedIn(@NotNull PsiDocCommentOwner owner, String inspectionToolID) {
PsiElement element = getDocCommentToolSuppressedIn(owner, inspectionToolID);
if (element != null) return element;
element = getAnnotationMemberSuppressedIn(owner, inspectionToolID);
if (element != null) return element;
PsiDocCommentOwner classContainer = PsiTreeUtil.getParentOfType(owner, PsiDocCommentOwner.class);
while (classContainer != null) {
element = getDocCommentToolSuppressedIn(classContainer, inspectionToolID);
if (element != null) return element;
element = getAnnotationMemberSuppressedIn(classContainer, inspectionToolID);
if (element != null) return element;
classContainer = PsiTreeUtil.getParentOfType(classContainer, PsiDocCommentOwner.class);
}
return null;
}
static PsiElement getAnnotationMemberSuppressedIn(@NotNull PsiModifierListOwner owner, String inspectionToolID) {
final PsiAnnotation generatedAnnotation = AnnotationUtil.findAnnotation(owner, Generated.class.getName());
if (generatedAnnotation != null) return generatedAnnotation;
PsiModifierList modifierList = owner.getModifierList();
Collection<String> suppressedIds = getInspectionIdsSuppressedInAnnotation(modifierList);
for (String ids : suppressedIds) {
if (SuppressionUtil.isInspectionToolIdMentioned(ids, inspectionToolID)) {
return modifierList != null ? AnnotationUtil.findAnnotation(owner, SUPPRESS_INSPECTIONS_ANNOTATION_NAME) : null;
}
}
return null;
}
static PsiElement getDocCommentToolSuppressedIn(@NotNull PsiDocCommentOwner owner, String inspectionToolID) {
PsiDocComment docComment = owner.getDocComment();
if (docComment == null && owner.getParent() instanceof PsiDeclarationStatement) {
final PsiElement el = PsiTreeUtil.skipSiblingsBackward(owner.getParent(), PsiWhiteSpace.class);
if (el instanceof PsiDocComment) {
docComment = (PsiDocComment)el;
}
}
if (docComment != null) {
PsiDocTag inspectionTag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME);
if (inspectionTag != null) {
final PsiElement[] dataElements = inspectionTag.getDataElements();
for (PsiElement dataElement : dataElements) {
String valueText = dataElement.getText();
if (SuppressionUtil.isInspectionToolIdMentioned(valueText, inspectionToolID)) {
return docComment;
}
}
}
}
return null;
}
static Collection<String> getInspectionIdsSuppressedInAnnotation(@NotNull PsiModifierListOwner owner) {
if (!PsiUtil.isLanguageLevel5OrHigher(owner)) return Collections.emptyList();
PsiModifierList modifierList = owner.getModifierList();
return getInspectionIdsSuppressedInAnnotation(modifierList);
}
static String getSuppressedInspectionIdsIn(@NotNull PsiElement element) {
if (element instanceof PsiComment) {
String text = element.getText();
Matcher matcher = SuppressionUtil.SUPPRESS_IN_LINE_COMMENT_PATTERN.matcher(text);
if (matcher.matches()) {
return matcher.group(1).trim();
}
}
if (element instanceof PsiDocCommentOwner) {
PsiDocComment docComment = ((PsiDocCommentOwner)element).getDocComment();
if (docComment != null) {
PsiDocTag inspectionTag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME);
if (inspectionTag != null) {
String valueText = "";
for (PsiElement dataElement : inspectionTag.getDataElements()) {
valueText += dataElement.getText();
}
return valueText;
}
}
}
if (element instanceof PsiModifierListOwner) {
Collection<String> suppressedIds = getInspectionIdsSuppressedInAnnotation((PsiModifierListOwner)element);
return suppressedIds.isEmpty() ? null : StringUtil.join(suppressedIds, ",");
}
return null;
}
static PsiElement getElementToolSuppressedIn(@NotNull final PsiElement place, final String toolId) {
if (place instanceof PsiFile) return null;
return ApplicationManager.getApplication().runReadAction(new Computable<PsiElement>() {
@Override
@Nullable
public PsiElement compute() {
final PsiElement statement = SuppressionUtil.getStatementToolSuppressedIn(place, toolId, PsiStatement.class);
if (statement != null) {
return statement;
}
PsiVariable local = PsiTreeUtil.getParentOfType(place, PsiVariable.class);
if (local != null && getAnnotationMemberSuppressedIn(local, toolId) != null) {
PsiModifierList modifierList = local.getModifierList();
return modifierList != null ? modifierList.findAnnotation(SUPPRESS_INSPECTIONS_ANNOTATION_NAME) : null;
}
PsiDocCommentOwner container = PsiTreeUtil.getNonStrictParentOfType(place, PsiDocCommentOwner.class);
while (true) {
if (!(container instanceof PsiTypeParameter)) break;
container = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class);
}
if (container != null) {
PsiElement element = getElementMemberSuppressedIn(container, toolId);
if (element != null) return element;
}
PsiDocCommentOwner classContainer = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class, true);
if (classContainer != null) {
PsiElement element = getElementMemberSuppressedIn(classContainer, toolId);
if (element != null) return element;
}
return null;
}
});
}
public static void addSuppressAnnotation(@NotNull Project project,
final PsiElement container,
final PsiModifierListOwner modifierOwner,
@NotNull String id) throws IncorrectOperationException {
PsiAnnotation annotation = AnnotationUtil.findAnnotation(modifierOwner, SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
final PsiAnnotation newAnnotation = createNewAnnotation(project, container, annotation, id);
if (newAnnotation != null) {
if (annotation != null && annotation.isPhysical()) {
annotation.replace(newAnnotation);
}
else {
final PsiNameValuePair[] attributes = newAnnotation.getParameterList().getAttributes();
new AddAnnotationPsiFix(SUPPRESS_INSPECTIONS_ANNOTATION_NAME, modifierOwner, attributes).applyFix();
}
}
}
private static PsiAnnotation createNewAnnotation(@NotNull Project project,
PsiElement container,
PsiAnnotation annotation,
@NotNull String id) throws IncorrectOperationException {
if (annotation == null) {
return JavaPsiFacade.getInstance(project).getElementFactory()
.createAnnotationFromText("@" + SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "(\"" + id + "\")", container);
}
final String currentSuppressedId = "\"" + id + "\"";
if (!annotation.getText().contains("{")) {
final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
if (attributes.length == 1) {
final String suppressedWarnings = attributes[0].getText();
if (suppressedWarnings.contains(currentSuppressedId)) return null;
return JavaPsiFacade.getInstance(project).getElementFactory().createAnnotationFromText(
"@" + SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({" + suppressedWarnings + ", " + currentSuppressedId + "})", container);
}
}
else {
final int curlyBraceIndex = annotation.getText().lastIndexOf("}");
if (curlyBraceIndex > 0) {
final String oldSuppressWarning = annotation.getText().substring(0, curlyBraceIndex);
if (oldSuppressWarning.contains(currentSuppressedId)) return null;
return JavaPsiFacade.getInstance(project).getElementFactory().createAnnotationFromText(
oldSuppressWarning + ", " + currentSuppressedId + "})", container);
}
else {
throw new IncorrectOperationException(annotation.getText());
}
}
return null;
}
public static boolean canHave15Suppressions(@NotNull PsiElement file) {
final Module module = ModuleUtilCore.findModuleForPsiElement(file);
if (module == null) return false;
final Sdk jdk = ModuleRootManager.getInstance(module).getSdk();
if (jdk == null) return false;
JavaSdkVersion version = getVersion(jdk);
if (version == null) return false;
final boolean is_1_5 = version.isAtLeast(JavaSdkVersion.JDK_1_5);
return DaemonCodeAnalyzerSettings.getInstance().isSuppressWarnings() && is_1_5 && PsiUtil.isLanguageLevel5OrHigher(file);
}
@Nullable
private static JavaSdkVersion getVersion(@NotNull Sdk sdk) {
String version = sdk.getVersionString();
if (version == null) return null;
return JdkVersionUtil.getVersion(version);
}
@Nullable
public static PsiElement getElementToAnnotate(PsiElement element, PsiElement container) {
if (container instanceof PsiDeclarationStatement && canHave15Suppressions(element)) {
final PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)container;
final PsiElement[] declaredElements = declarationStatement.getDeclaredElements();
for (PsiElement declaredElement : declaredElements) {
if (declaredElement instanceof PsiLocalVariable) {
final PsiModifierList modifierList = ((PsiLocalVariable)declaredElement).getModifierList();
if (modifierList != null) {
return declaredElement;
}
}
}
}
return null;
}
}
@@ -1,76 +0,0 @@
/*
* Copyright 2000-2009 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.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInspection.SuppressManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.jsp.jspJava.JspMethodCall;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nullable;
/**
* @author yole
*/
public class SuppressByJavaCommentFix extends SuppressByCommentFix {
public SuppressByJavaCommentFix(HighlightDisplayKey key) {
super(key, PsiStatement.class);
}
@Override
@Nullable
protected PsiElement getContainer(PsiElement context) {
if (context == null || PsiTreeUtil.getParentOfType(context, JspMethodCall.class) != null) return null;
return PsiTreeUtil.getParentOfType(context, PsiStatement.class, false);
}
@Override
protected void createSuppression(final Project project,
final Editor editor,
final PsiElement element,
final PsiElement container) throws IncorrectOperationException {
PsiElement declaredElement = getElementToAnnotate(element, container);
if (declaredElement != null) {
SuppressFix.addSuppressAnnotation(project, editor, container, (PsiLocalVariable)declaredElement, myID);
} else {
suppressWithComment(project, editor, element, container);
}
}
protected void suppressWithComment(Project project, Editor editor, PsiElement element, PsiElement container) {
super.createSuppression(project, editor, element, container);
}
@Nullable
protected static PsiElement getElementToAnnotate(PsiElement element, PsiElement container) {
if (container instanceof PsiDeclarationStatement && SuppressManager.getInstance().canHave15Suppressions(element)) {
final PsiDeclarationStatement declarationStatement = (PsiDeclarationStatement)container;
final PsiElement[] declaredElements = declarationStatement.getDeclaredElements();
for (PsiElement declaredElement : declaredElements) {
if (declaredElement instanceof PsiLocalVariable) {
final PsiModifierList modifierList = ((PsiLocalVariable)declaredElement).getModifierList();
if (modifierList != null) {
return declaredElement;
}
}
}
}
return null;
}
}
@@ -1,222 +0,0 @@
/*
* Copyright 2000-2011 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.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.SuppressManager;
import com.intellij.codeInspection.SuppressionUtil;
import com.intellij.lang.StdLanguages;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.impl.storage.ClasspathStorage;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.jsp.jspJava.JspHolderMethod;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author ven
*/
public class SuppressFix extends SuppressIntentionAction {
private final String myID;
private String myAlternativeID;
private String myText;
public SuppressFix(HighlightDisplayKey key) {
this(key.getID());
myAlternativeID = HighlightDisplayKey.getAlternativeID(key);
}
public SuppressFix(String ID) {
myID = ID;
}
@Override
@NotNull
public String getText() {
return myText == null ? "Suppress for member" : myText;
}
@Nullable
protected PsiDocCommentOwner getContainer(final PsiElement context) {
if (context == null || !context.getManager().isInProject(context)) {
return null;
}
final PsiFile containingFile = context.getContainingFile();
if (containingFile == null) {
// for PsiDirectory
return null;
}
if (!containingFile.getLanguage().isKindOf(StdLanguages.JAVA) || context instanceof PsiFile) {
return null;
}
PsiElement container = context;
while (container instanceof PsiAnonymousClass || !(container instanceof PsiDocCommentOwner) || container instanceof PsiTypeParameter) {
container = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class);
if (container == null) return null;
}
return (PsiDocCommentOwner)container;
}
@Override
@NotNull
public String getFamilyName() {
return InspectionsBundle.message("suppress.inspection.family");
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement context) {
PsiDocCommentOwner container = getContainer(context);
boolean isValid = container != null && !(container instanceof JspHolderMethod);
if (!isValid) {
return false;
}
myText = container instanceof PsiClass
? InspectionsBundle.message("suppress.inspection.class")
: container instanceof PsiMethod ? InspectionsBundle.message("suppress.inspection.method") : InspectionsBundle.message("suppress.inspection.field");
return true;
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
PsiDocCommentOwner container = getContainer(element);
assert container != null;
if (!FileModificationService.getInstance().preparePsiElementForWrite(container)) return;
if (use15Suppressions(container)) {
final PsiModifierList modifierList = container.getModifierList();
if (modifierList != null) {
addSuppressAnnotation(project, editor, container, container, getID(container));
}
}
else {
PsiDocComment docComment = container.getDocComment();
PsiManager manager = PsiManager.getInstance(project);
if (docComment == null) {
String commentText = "/** @" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + getID(container) + "*/";
docComment = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocCommentFromText(commentText);
PsiElement firstChild = container.getFirstChild();
container.addBefore(docComment, firstChild);
}
else {
PsiDocTag noInspectionTag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME);
if (noInspectionTag != null) {
String tagText = noInspectionTag.getText() + ", " + getID(container);
noInspectionTag.replace(JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocTagFromText(tagText));
}
else {
String tagText = "@" + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + getID(container);
docComment.add(JavaPsiFacade.getInstance(manager.getProject()).getElementFactory().createDocTagFromText(tagText));
}
}
}
DaemonCodeAnalyzer.getInstance(project).restart();
}
public static void addSuppressAnnotation(final Project project,
final Editor editor,
final PsiElement container,
final PsiModifierListOwner modifierOwner,
final String id) throws IncorrectOperationException {
PsiAnnotation annotation = AnnotationUtil.findAnnotation(modifierOwner, SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
final PsiAnnotation newAnnotation = createNewAnnotation(project, editor, container, annotation, id);
if (newAnnotation != null) {
if (annotation != null && annotation.isPhysical()) {
annotation.replace(newAnnotation);
}
else {
final PsiNameValuePair[] attributes = newAnnotation.getParameterList().getAttributes();
new AddAnnotationFix(SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME, modifierOwner, attributes).invoke(project, editor, container.getContainingFile());
}
}
}
private static PsiAnnotation createNewAnnotation(final Project project,
final Editor editor,
final PsiElement container,
@Nullable final PsiAnnotation annotation,
final String id) {
if (annotation != null) {
final String currentSuppressedId = "\"" + id + "\"";
if (!annotation.getText().contains("{")) {
final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
if (attributes.length == 1) {
final String suppressedWarnings = attributes[0].getText();
if (suppressedWarnings.contains(currentSuppressedId)) return null;
return JavaPsiFacade.getInstance(project).getElementFactory().createAnnotationFromText(
"@" + SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "({" + suppressedWarnings + ", " + currentSuppressedId + "})", container);
}
}
else {
final int curlyBraceIndex = annotation.getText().lastIndexOf("}");
if (curlyBraceIndex > 0) {
final String oldSuppressWarning = annotation.getText().substring(0, curlyBraceIndex);
if (oldSuppressWarning.contains(currentSuppressedId)) return null;
return JavaPsiFacade.getInstance(project).getElementFactory().createAnnotationFromText(
oldSuppressWarning + ", " + currentSuppressedId + "})", container);
}
else if (!ApplicationManager.getApplication().isUnitTestMode() && editor != null) {
Messages.showErrorDialog(editor.getComponent(),
InspectionsBundle.message("suppress.inspection.annotation.syntax.error", annotation.getText()));
}
}
}
else {
return JavaPsiFacade.getInstance(project).getElementFactory()
.createAnnotationFromText("@" + SuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME + "(\"" + id + "\")", container);
}
return null;
}
protected boolean use15Suppressions(final PsiDocCommentOwner container) {
return SuppressManager.getInstance().canHave15Suppressions(container) &&
!SuppressManager.getInstance().alreadyHas14Suppressions(container);
}
private String getID(PsiElement place) {
String id = getID(place, myAlternativeID);
return id != null ? id : myID;
}
@Nullable
static String getID(PsiElement place, String alternativeID) {
if (alternativeID != null) {
final Module module = ModuleUtilCore.findModuleForPsiElement(place);
if (module != null) {
if (!ClasspathStorage.getStorageType(module).equals(ClasspathStorage.DEFAULT_STORAGE)) {
return alternativeID;
}
}
}
return null;
}
}
@@ -16,139 +16,41 @@
package com.intellij.codeInsight.intention;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
import com.intellij.lang.findUsages.FindUsagesProvider;
import com.intellij.lang.findUsages.LanguageFindUsages;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.psi.PsiNameValuePair;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author ven
*/
public class AddAnnotationFix extends LocalQuickFixAndIntentionActionOnPsiElement {
protected final String myAnnotation;
private final String[] myAnnotationsToRemove;
private final PsiNameValuePair[] myPairs; // not used when registering local quick fix
private static final Logger LOG = Logger.getInstance("#" + AddAnnotationFix.class.getName());
private final String myText;
public class AddAnnotationFix extends AddAnnotationPsiFix implements IntentionAction {
public AddAnnotationFix(@NotNull String fqn, @NotNull PsiModifierListOwner modifierListOwner, @NotNull String... annotationsToRemove) {
this(fqn, modifierListOwner, PsiNameValuePair.EMPTY_ARRAY, annotationsToRemove);
}
public AddAnnotationFix(@NotNull String fqn, @NotNull PsiModifierListOwner modifierListOwner, @NotNull PsiNameValuePair[] values, @NotNull String... annotationsToRemove) {
super(modifierListOwner);
myAnnotation = fqn;
myAnnotationsToRemove = annotationsToRemove;
myPairs = values;
myText = calcText(modifierListOwner, myAnnotation);
}
public static String calcText(PsiModifierListOwner modifierListOwner, @NotNull String annotation) {
final String shortName = annotation.substring(annotation.lastIndexOf('.') + 1);
if (modifierListOwner instanceof PsiNamedElement) {
final String name = ((PsiNamedElement)modifierListOwner).getName();
if (name != null) {
FindUsagesProvider provider = LanguageFindUsages.INSTANCE.forLanguage(modifierListOwner.getLanguage());
return CodeInsightBundle
.message("inspection.i18n.quickfix.annotate.element.as", provider.getType(modifierListOwner), name, shortName);
}
}
return CodeInsightBundle.message("inspection.i18n.quickfix.annotate.as", shortName);
public AddAnnotationFix(@NotNull String fqn,
@NotNull PsiModifierListOwner modifierListOwner,
@NotNull PsiNameValuePair[] values,
@NotNull String... annotationsToRemove) {
super(fqn, modifierListOwner, values, annotationsToRemove);
}
@Override
@NotNull
public String getText() {
return myText;
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return isAvailable();
}
@Override
@NotNull
public String getFamilyName() {
return CodeInsightBundle.message("intention.add.annotation.family");
}
@Nullable
public static PsiModifierListOwner getContainer(final PsiElement element) {
PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false);
if (listOwner == null) {
final PsiIdentifier psiIdentifier = PsiTreeUtil.getParentOfType(element, PsiIdentifier.class, false);
if (psiIdentifier != null && psiIdentifier.getParent() instanceof PsiModifierListOwner) {
listOwner = (PsiModifierListOwner)psiIdentifier.getParent();
}
}
return listOwner;
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
applyFix();
}
@Override
public boolean isAvailable(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
if (!startElement.isValid()) return false;
if (!PsiUtil.isLanguageLevel5OrHigher(startElement)) return false;
final PsiModifierListOwner myModifierListOwner = (PsiModifierListOwner)startElement;
return !AnnotationUtil.isAnnotated(myModifierListOwner, myAnnotation, false, false);
}
@Override
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable("is null when called from inspection") Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
final PsiModifierListOwner myModifierListOwner = (PsiModifierListOwner)startElement;
final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project);
final PsiModifierList modifierList = myModifierListOwner.getModifierList();
LOG.assertTrue(modifierList != null);
if (modifierList.findAnnotation(myAnnotation) != null) return;
final ExternalAnnotationsManager.AnnotationPlace annotationAnnotationPlace = annotationsManager.chooseAnnotationsPlace(myModifierListOwner);
if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.NOWHERE) return;
if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.EXTERNAL) {
for (String fqn : myAnnotationsToRemove) {
annotationsManager.deannotate(myModifierListOwner, fqn);
}
annotationsManager.annotateExternally(myModifierListOwner, myAnnotation, file, myPairs);
}
else {
final PsiFile containingFile = myModifierListOwner.getContainingFile();
if (!FileModificationService.getInstance().preparePsiElementForWrite(containingFile)) return;
for (String fqn : myAnnotationsToRemove) {
PsiAnnotation annotation = AnnotationUtil.findAnnotation(myModifierListOwner, fqn);
if (annotation != null) {
annotation.delete();
}
}
PsiAnnotation inserted = modifierList.addAnnotation(myAnnotation);
for (PsiNameValuePair pair : myPairs) {
inserted.setDeclaredAttributeValue(pair.getName(), pair.getValue());
}
JavaCodeStyleManager.getInstance(project).shortenClassReferences(inserted);
if (containingFile != file) {
UndoUtil.markPsiFileForUndo(file);
}
}
}
@NotNull
public String[] getAnnotationsToRemove() {
return myAnnotationsToRemove;
public boolean startInWriteAction() {
return true;
}
}
@@ -25,6 +25,7 @@ package com.intellij.codeInsight.intention.impl;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
@@ -59,7 +60,7 @@ public abstract class AddAnnotationIntention extends BaseIntentionAction {
if (!PsiUtil.isLanguageLevel5OrHigher(element)) return false;
final PsiModifierListOwner owner;
if (!element.getManager().isInProject(element) || CodeStyleSettingsManager.getSettings(project).USE_EXTERNAL_ANNOTATIONS) {
owner = AddAnnotationFix.getContainer(element);
owner = AddAnnotationPsiFix.getContainer(element);
}
else {
return false;
@@ -69,7 +70,7 @@ public abstract class AddAnnotationIntention extends BaseIntentionAction {
String toAdd = annotations.first;
String[] toRemove = annotations.second;
if (toRemove.length > 0 && AnnotationUtil.isAnnotated(owner, toRemove[0], false, false)) return false;
setText(AddAnnotationFix.calcText(owner, toAdd));
setText(AddAnnotationPsiFix.calcText(owner, toAdd));
if (AnnotationUtil.isAnnotated(owner, toAdd, false, false)) return false;
if (owner instanceof PsiMethod) {
@@ -86,7 +87,7 @@ public abstract class AddAnnotationIntention extends BaseIntentionAction {
int position = caretModel.getOffset();
PsiElement element = file.findElementAt(position);
PsiModifierListOwner owner = AddAnnotationFix.getContainer(element);
PsiModifierListOwner owner = AddAnnotationPsiFix.getContainer(element);
if (owner == null || !owner.isValid()) return;
Pair<String, String[]> annotations = getAnnotations(project);
String toAdd = annotations.first;
@@ -20,260 +20,84 @@
*/
package com.intellij.codeInspection;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.actions.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.projectRoots.JavaSdk;
import com.intellij.openapi.projectRoots.JavaSdkVersion;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiVariableEx;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.codeInspection.ex.InspectionManagerEx;
import com.intellij.psi.PsiDocCommentOwner;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiModifierListOwner;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Generated;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.regex.Matcher;
public class SuppressManagerImpl extends SuppressManager {
@Override
@NotNull
public SuppressIntentionAction[] createSuppressActions(@NotNull final HighlightDisplayKey displayKey) {
return new SuppressIntentionAction[]{
new SuppressByJavaCommentFix(displayKey),
new SuppressLocalWithCommentFix(displayKey),
new SuppressParameterFix(displayKey),
new SuppressFix(displayKey),
new SuppressForClassFix(displayKey),
new SuppressAllForClassFix()
};
SuppressQuickFix[] batchSuppressActions = createBatchSuppressActions(displayKey);
return convertBatchToSuppressIntentionActions(batchSuppressActions);
}
@NotNull
private static SuppressIntentionAction[] convertBatchToSuppressIntentionActions(@NotNull SuppressQuickFix[] actions) {
return ContainerUtil.map2Array(actions, SuppressIntentionAction.class, new Function<SuppressQuickFix, SuppressIntentionAction>() {
@Override
public SuppressIntentionAction fun(SuppressQuickFix fix) {
return InspectionManagerEx.convertBatchToSuppressIntentionAction(fix);
}
});
}
@Override
public boolean isSuppressedFor(@NotNull final PsiElement element, final String toolId) {
return getElementToolSuppressedIn(element, toolId) != null;
return JavaSuppressionUtil.getElementToolSuppressedIn(element, toolId) != null;
}
@Override
@Nullable
public PsiElement getElementMemberSuppressedIn(@NotNull final PsiDocCommentOwner owner, final String inspectionToolID) {
PsiElement element = getDocCommentToolSuppressedIn(owner, inspectionToolID);
if (element != null) return element;
element = getAnnotationMemberSuppressedIn(owner, inspectionToolID);
if (element != null) return element;
PsiDocCommentOwner classContainer = PsiTreeUtil.getParentOfType(owner, PsiDocCommentOwner.class);
while (classContainer != null) {
element = getDocCommentToolSuppressedIn(classContainer, inspectionToolID);
if (element != null) return element;
element = getAnnotationMemberSuppressedIn(classContainer, inspectionToolID);
if (element != null) return element;
classContainer = PsiTreeUtil.getParentOfType(classContainer, PsiDocCommentOwner.class);
}
return null;
return JavaSuppressionUtil.getElementMemberSuppressedIn(owner, inspectionToolID);
}
@Override
@Nullable
public PsiElement getAnnotationMemberSuppressedIn(@NotNull final PsiModifierListOwner owner, final String inspectionToolID) {
final PsiAnnotation generatedAnnotation = AnnotationUtil.findAnnotation(owner, Generated.class.getName());
if (generatedAnnotation != null) return generatedAnnotation;
PsiModifierList modifierList = owner.getModifierList();
Collection<String> suppressedIds = getInspectionIdsSuppressedInAnnotation(modifierList);
for (String ids : suppressedIds) {
if (SuppressionUtil.isInspectionToolIdMentioned(ids, inspectionToolID)) {
return modifierList != null ? AnnotationUtil.findAnnotation(owner, SUPPRESS_INSPECTIONS_ANNOTATION_NAME) : null;
}
}
return null;
return JavaSuppressionUtil.getAnnotationMemberSuppressedIn(owner, inspectionToolID);
}
@Override
@Nullable
public PsiElement getDocCommentToolSuppressedIn(@NotNull final PsiDocCommentOwner owner, final String inspectionToolID) {
PsiDocComment docComment = owner.getDocComment();
if (docComment == null && owner.getParent() instanceof PsiDeclarationStatement) {
final PsiElement el = PsiTreeUtil.skipSiblingsBackward(owner.getParent(), PsiWhiteSpace.class);
if (el instanceof PsiDocComment) {
docComment = (PsiDocComment)el;
}
}
if (docComment != null) {
PsiDocTag inspectionTag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME);
if (inspectionTag != null) {
final PsiElement[] dataElements = inspectionTag.getDataElements();
for (PsiElement dataElement : dataElements) {
String valueText = dataElement.getText();
if (SuppressionUtil.isInspectionToolIdMentioned(valueText, inspectionToolID)) {
return docComment;
}
}
}
}
return null;
return JavaSuppressionUtil.getDocCommentToolSuppressedIn(owner, inspectionToolID);
}
@Override
@NotNull
public Collection<String> getInspectionIdsSuppressedInAnnotation(@NotNull final PsiModifierListOwner owner) {
if (!PsiUtil.isLanguageLevel5OrHigher(owner)) return Collections.emptyList();
PsiModifierList modifierList = owner.getModifierList();
return getInspectionIdsSuppressedInAnnotation(modifierList);
return JavaSuppressionUtil.getInspectionIdsSuppressedInAnnotation(owner);
}
@Override
@Nullable
public String getSuppressedInspectionIdsIn(@NotNull PsiElement element) {
if (element instanceof PsiComment) {
String text = element.getText();
Matcher matcher = SuppressionUtil.SUPPRESS_IN_LINE_COMMENT_PATTERN.matcher(text);
if (matcher.matches()) {
return matcher.group(1).trim();
}
}
if (element instanceof PsiDocCommentOwner) {
PsiDocComment docComment = ((PsiDocCommentOwner)element).getDocComment();
if (docComment != null) {
PsiDocTag inspectionTag = docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME);
if (inspectionTag != null) {
String valueText = "";
for (PsiElement dataElement : inspectionTag.getDataElements()) {
valueText += dataElement.getText();
}
return valueText;
}
}
}
if (element instanceof PsiModifierListOwner) {
Collection<String> suppressedIds = getInspectionIdsSuppressedInAnnotation((PsiModifierListOwner)element);
return suppressedIds.isEmpty() ? null : StringUtil.join(suppressedIds, ",");
}
return null;
return JavaSuppressionUtil.getSuppressedInspectionIdsIn(element);
}
@Override
@Nullable
public PsiElement getElementToolSuppressedIn(@NotNull final PsiElement place, final String toolId) {
if (place instanceof PsiFile) return null;
return ApplicationManager.getApplication().runReadAction(new Computable<PsiElement>() {
@Override
@Nullable
public PsiElement compute() {
final PsiElement statement = SuppressionUtil.getStatementToolSuppressedIn(place, toolId, PsiStatement.class);
if (statement != null) {
return statement;
}
PsiVariable local = PsiTreeUtil.getParentOfType(place, PsiVariable.class);
if (local != null && getAnnotationMemberSuppressedIn(local, toolId) != null) {
PsiModifierList modifierList = local.getModifierList();
return modifierList != null ? modifierList.findAnnotation(SUPPRESS_INSPECTIONS_ANNOTATION_NAME) : null;
}
PsiDocCommentOwner container = PsiTreeUtil.getNonStrictParentOfType(place, PsiDocCommentOwner.class);
while (true) {
if (!(container instanceof PsiTypeParameter)) break;
container = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class);
}
if (container != null) {
PsiElement element = getElementMemberSuppressedIn(container, toolId);
if (element != null) return element;
}
PsiDocCommentOwner classContainer = PsiTreeUtil.getParentOfType(container, PsiDocCommentOwner.class, true);
if (classContainer != null) {
PsiElement element = getElementMemberSuppressedIn(classContainer, toolId);
if (element != null) return element;
}
return null;
}
});
}
@NotNull
public static Collection<String> getInspectionIdsSuppressedInAnnotation(final PsiModifierList modifierList) {
if (modifierList == null) {
return Collections.emptyList();
}
final PsiModifierListOwner owner = (PsiModifierListOwner)modifierList.getParent();
PsiAnnotation annotation = AnnotationUtil.findAnnotation(owner, SUPPRESS_INSPECTIONS_ANNOTATION_NAME);
if (annotation == null) {
return Collections.emptyList();
}
final PsiNameValuePair[] attributes = annotation.getParameterList().getAttributes();
if (attributes.length == 0) {
return Collections.emptyList();
}
final PsiAnnotationMemberValue attributeValue = attributes[0].getValue();
Collection<String> result = new ArrayList<String>();
if (attributeValue instanceof PsiArrayInitializerMemberValue) {
final PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)attributeValue).getInitializers();
for (PsiAnnotationMemberValue annotationMemberValue : initializers) {
final String id = getInspectionIdSuppressedInAnnotationAttribute(annotationMemberValue);
if (id != null) {
result.add(id);
}
}
}
else {
final String id = getInspectionIdSuppressedInAnnotationAttribute(attributeValue);
if (id != null) {
result.add(id);
}
}
return result;
}
@Nullable
public static String getInspectionIdSuppressedInAnnotationAttribute(PsiElement element) {
if (element instanceof PsiLiteralExpression) {
final Object value = ((PsiLiteralExpression)element).getValue();
if (value instanceof String) {
return (String)value;
}
}
else if (element instanceof PsiReferenceExpression) {
final PsiElement psiElement = ((PsiReferenceExpression)element).resolve();
if (psiElement instanceof PsiVariableEx) {
final Object val = ((PsiVariableEx)psiElement).computeConstantValue(new HashSet<PsiVariable>());
if (val instanceof String) {
return (String)val;
}
}
}
return null;
return JavaSuppressionUtil.getElementToolSuppressedIn(place, toolId);
}
@Override
public boolean canHave15Suppressions(@NotNull final PsiElement file) {
final Module module = ModuleUtilCore.findModuleForPsiElement(file);
if (module == null) return false;
final Sdk jdk = ModuleRootManager.getInstance(module).getSdk();
if (jdk == null) return false;
final boolean is_1_5 = JavaSdk.getInstance().isOfVersionOrHigher(jdk, JavaSdkVersion.JDK_1_5);
return DaemonCodeAnalyzerSettings.getInstance().SUPPRESS_WARNINGS && is_1_5 && PsiUtil.isLanguageLevel5OrHigher(file);
return JavaSuppressionUtil.canHave15Suppressions(file);
}
@Override
public boolean alreadyHas14Suppressions(@NotNull final PsiDocCommentOwner commentOwner) {
final PsiDocComment docComment = commentOwner.getDocComment();
return docComment != null && docComment.findTagByName(SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME) != null;
return JavaSuppressionUtil.alreadyHas14Suppressions(commentOwner);
}
}
@@ -56,21 +56,8 @@ public class JavaSdkImpl extends JavaSdk {
@NonNls private final Pattern myVersionStringPattern = Pattern.compile("^(.*)java version \"([1234567890_.]*)\"(.*)$");
@NonNls private static final String JAVA_VERSION_PREFIX = "java version ";
@NonNls private static final String OPENJDK_VERSION_PREFIX = "openjdk version ";
private static final Map<JavaSdkVersion, String[]> VERSION_STRINGS = new EnumMap<JavaSdkVersion, String[]>(JavaSdkVersion.class);
public static final DataKey<Boolean> KEY = DataKey.create("JavaSdk");
static {
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_0, new String[]{"1.0"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_1, new String[]{"1.1"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_2, new String[]{"1.2"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_3, new String[]{"1.3"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_4, new String[]{"1.4"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_5, new String[]{"1.5", "5.0"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_6, new String[]{"1.6", "6.0"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_7, new String[]{"1.7", "7.0"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_8, new String[]{"1.8", "8.0"});
}
public JavaSdkImpl() {
super("JavaSDK");
}
@@ -264,11 +251,11 @@ public class JavaSdkImpl extends JavaSdk {
if (SystemInfo.isMac) {
File home = new File(homePath, MAC_HOME_PATH);
if (home.exists()) return home.getPath();
home = new File(new File(homePath, "Contents"), "Home");
if (home.exists()) return home.getPath();
}
return homePath;
}
@@ -302,7 +289,7 @@ public class JavaSdkImpl extends JavaSdk {
@NotNull
private static String getVersionNumber(@NotNull String versionString) {
if (versionString.startsWith(JAVA_VERSION_PREFIX) || versionString.startsWith(OPENJDK_VERSION_PREFIX)) {
boolean openJdk = versionString.startsWith(OPENJDK_VERSION_PREFIX);
boolean openJdk = versionString.startsWith(OPENJDK_VERSION_PREFIX);
versionString = versionString.substring(openJdk ? OPENJDK_VERSION_PREFIX.length() : JAVA_VERSION_PREFIX.length());
if (versionString.startsWith("\"") && versionString.endsWith("\"")) {
versionString = versionString.substring(1, versionString.length() - 1);
@@ -440,22 +427,19 @@ public class JavaSdkImpl extends JavaSdk {
@Override
public JavaSdkVersion getVersion(@NotNull Sdk sdk) {
return getVersion1(sdk);
}
private static JavaSdkVersion getVersion1(Sdk sdk) {
String version = sdk.getVersionString();
if (version == null) return null;
return getVersion(version);
return JdkVersionUtil.getVersion(version);
}
@Override
@Nullable
public JavaSdkVersion getVersion(@NotNull String versionString) {
for (Map.Entry<JavaSdkVersion, String[]> entry : VERSION_STRINGS.entrySet()) {
for (String s : entry.getValue()) {
if (versionString.contains(s)) {
return entry.getKey();
}
}
}
return null;
return JdkVersionUtil.getVersion(versionString);
}
@Override
@@ -0,0 +1,48 @@
/*
* 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.openapi.projectRoots;
import org.jetbrains.annotations.NotNull;
import java.util.EnumMap;
import java.util.Map;
public class JdkVersionUtil {
private static final Map<JavaSdkVersion, String[]> VERSION_STRINGS = new EnumMap<JavaSdkVersion, String[]>(JavaSdkVersion.class);
static {
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_0, new String[]{"1.0"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_1, new String[]{"1.1"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_2, new String[]{"1.2"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_3, new String[]{"1.3"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_4, new String[]{"1.4"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_5, new String[]{"1.5", "5.0"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_6, new String[]{"1.6", "6.0"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_7, new String[]{"1.7", "7.0"});
VERSION_STRINGS.put(JavaSdkVersion.JDK_1_8, new String[]{"1.8", "8.0"});
}
public static JavaSdkVersion getVersion(@NotNull String versionString) {
for (Map.Entry<JavaSdkVersion, String[]> entry : VERSION_STRINGS.entrySet()) {
for (String s : entry.getValue()) {
if (versionString.contains(s)) {
return entry.getKey();
}
}
}
return null;
}
}
@@ -0,0 +1,146 @@
/*
* 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.codeInsight.intention;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInspection.LocalQuickFixOnPsiElement;
import com.intellij.lang.findUsages.FindUsagesProvider;
import com.intellij.lang.findUsages.LanguageFindUsages;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class AddAnnotationPsiFix extends LocalQuickFixOnPsiElement {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.intention.AddAnnotationPsiFix");
protected final String myAnnotation;
protected final String[] myAnnotationsToRemove;
protected final PsiNameValuePair[] myPairs; // not used when registering local quick fix
protected final String myText;
public AddAnnotationPsiFix(@NotNull String fqn,
@NotNull PsiModifierListOwner modifierListOwner,
@NotNull PsiNameValuePair[] values,
@NotNull String... annotationsToRemove) {
super(modifierListOwner);
myAnnotation = fqn;
myPairs = values;
myAnnotationsToRemove = annotationsToRemove;
myText = calcText(modifierListOwner, myAnnotation);
}
public static String calcText(PsiModifierListOwner modifierListOwner, @NotNull String annotation) {
final String shortName = annotation.substring(annotation.lastIndexOf('.') + 1);
if (modifierListOwner instanceof PsiNamedElement) {
final String name = ((PsiNamedElement)modifierListOwner).getName();
if (name != null) {
FindUsagesProvider provider = LanguageFindUsages.INSTANCE.forLanguage(modifierListOwner.getLanguage());
return CodeInsightBundle
.message("inspection.i18n.quickfix.annotate.element.as", provider.getType(modifierListOwner), name, shortName);
}
}
return CodeInsightBundle.message("inspection.i18n.quickfix.annotate.as", shortName);
}
@Nullable
public static PsiModifierListOwner getContainer(final PsiElement element) {
PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false);
if (listOwner == null) {
final PsiIdentifier psiIdentifier = PsiTreeUtil.getParentOfType(element, PsiIdentifier.class, false);
if (psiIdentifier != null && psiIdentifier.getParent() instanceof PsiModifierListOwner) {
listOwner = (PsiModifierListOwner)psiIdentifier.getParent();
}
}
return listOwner;
}
@Override
@NotNull
public String getText() {
return myText;
}
@Override
@NotNull
public String getFamilyName() {
return CodeInsightBundle.message("intention.add.annotation.family");
}
@Override
public boolean isAvailable(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
if (!startElement.isValid()) return false;
if (!PsiUtil.isLanguageLevel5OrHigher(startElement)) return false;
final PsiModifierListOwner myModifierListOwner = (PsiModifierListOwner)startElement;
return !AnnotationUtil.isAnnotated(myModifierListOwner, myAnnotation, false, false);
}
@Override
public void invoke(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
final PsiModifierListOwner myModifierListOwner = (PsiModifierListOwner)startElement;
final ExternalAnnotationsManager annotationsManager = ExternalAnnotationsManager.getInstance(project);
final PsiModifierList modifierList = myModifierListOwner.getModifierList();
LOG.assertTrue(modifierList != null);
if (modifierList.findAnnotation(myAnnotation) != null) return;
final ExternalAnnotationsManager.AnnotationPlace annotationAnnotationPlace = annotationsManager.chooseAnnotationsPlace(myModifierListOwner);
if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.NOWHERE) return;
if (annotationAnnotationPlace == ExternalAnnotationsManager.AnnotationPlace.EXTERNAL) {
for (String fqn : myAnnotationsToRemove) {
annotationsManager.deannotate(myModifierListOwner, fqn);
}
annotationsManager.annotateExternally(myModifierListOwner, myAnnotation, file, myPairs);
}
else {
final PsiFile containingFile = myModifierListOwner.getContainingFile();
if (!FileModificationService.getInstance().preparePsiElementForWrite(containingFile)) return;
for (String fqn : myAnnotationsToRemove) {
PsiAnnotation annotation = AnnotationUtil.findAnnotation(myModifierListOwner, fqn);
if (annotation != null) {
annotation.delete();
}
}
PsiAnnotation inserted = modifierList.addAnnotation(myAnnotation);
for (PsiNameValuePair pair : myPairs) {
inserted.setDeclaredAttributeValue(pair.getName(), pair.getValue());
}
JavaCodeStyleManager.getInstance(project).shortenClassReferences(inserted);
if (containingFile != file) {
UndoUtil.markPsiFileForUndo(file);
}
}
}
@NotNull
public String[] getAnnotationsToRemove() {
return myAnnotationsToRemove;
}
}
@@ -4,7 +4,7 @@
*/
package com.intellij.codeInsight;
import com.intellij.codeInsight.intention.AddAnnotationFix;
import com.intellij.codeInsight.intention.AddAnnotationPsiFix;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.impl.DeannotateIntentionAction;
import com.intellij.openapi.application.ApplicationManager;
@@ -110,7 +110,7 @@ public class AddAnnotationFixTest extends UsefulTestCase {
int position = caretModel.getOffset();
PsiElement element = myFixture.getFile().findElementAt(position);
assert element != null;
PsiModifierListOwner container = AddAnnotationFix.getContainer(element);
PsiModifierListOwner container = AddAnnotationPsiFix.getContainer(element);
assert container != null;
return container;
}
@@ -16,10 +16,8 @@
package com.intellij.codeInspection;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Implement this abstract class in order to provide new inspection tool functionality. The major API limitation here is
@@ -30,94 +28,7 @@ import org.jetbrains.annotations.Nullable;
*
* @see GlobalInspectionTool
*/
public abstract class BaseJavaLocalInspectionTool extends LocalInspectionTool implements CustomSuppressableInspectionTool {
/**
* Override this to report problems at method level.
*
* @param method to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at method level.
*/
@Nullable
public ProblemDescriptor[] checkMethod(@NotNull PsiMethod method, @NotNull InspectionManager manager, boolean isOnTheFly) {
return null;
}
/**
* Override this to report problems at class level.
*
* @param aClass to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at class level.
*/
@Nullable
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
return null;
}
/**
* Override this to report problems at field level.
*
* @param field to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at field level.
*/
@Nullable
public ProblemDescriptor[] checkField(@NotNull PsiField field, @NotNull InspectionManager manager, boolean isOnTheFly) {
return null;
}
/**
* Override this to report problems at file level.
*
* @param file to check.
* @param manager InspectionManager to ask for ProblemDescriptors from.
* @param isOnTheFly true if called during on the fly editor highlighting. Called from Inspect Code action otherwise.
* @return <code>null</code> if no problems found or not applicable at file level.
*/
@Override
@Nullable
public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull InspectionManager manager, boolean isOnTheFly) {
return null;
}
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new JavaElementVisitor() {
@Override public void visitMethod(PsiMethod method) {
addDescriptors(checkMethod(method, holder.getManager(), isOnTheFly));
}
@Override public void visitClass(PsiClass aClass) {
addDescriptors(checkClass(aClass, holder.getManager(), isOnTheFly));
}
@Override public void visitField(PsiField field) {
addDescriptors(checkField(field, holder.getManager(), isOnTheFly));
}
@Override public void visitFile(PsiFile file) {
addDescriptors(checkFile(file, holder.getManager(), isOnTheFly));
}
private void addDescriptors(final ProblemDescriptor[] descriptors) {
if (descriptors != null) {
for (ProblemDescriptor descriptor : descriptors) {
holder.registerProblem(descriptor);
}
}
}
};
}
@Override
public PsiNamedElement getProblemElement(final PsiElement psiElement) {
return PsiTreeUtil.getNonStrictParentOfType(psiElement, PsiFile.class, PsiClass.class, PsiMethod.class, PsiField.class);
}
public abstract class BaseJavaLocalInspectionTool extends AbstractBaseJavaLocalInspectionTool implements CustomSuppressableInspectionTool {
@Override
public SuppressIntentionAction[] getSuppressActions(final PsiElement element) {
return SuppressManager.getInstance().createSuppressActions(HighlightDisplayKey.find(getShortName()));
@@ -129,12 +40,6 @@ public abstract class BaseJavaLocalInspectionTool extends LocalInspectionTool i
}
public static boolean isSuppressedFor(@NotNull PsiElement element, @NotNull LocalInspectionTool tool) {
final SuppressManager manager = SuppressManager.getInstance();
String alternativeId;
String id;
return manager.isSuppressedFor(element, id = tool.getID()) ||
(alternativeId = tool.getAlternativeID()) != null &&
!alternativeId.equals(id) &&
manager.isSuppressedFor(element, alternativeId);
return BaseJavaBatchLocalInspectionTool.isSuppressedFor(element, tool);
}
}
@@ -22,48 +22,31 @@ package com.intellij.codeInspection;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.psi.*;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiCodeBlock;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiLiteralExpression;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public abstract class SuppressManager {
public abstract class SuppressManager implements BatchSuppressManager {
public static final String SUPPRESS_INSPECTIONS_ANNOTATION_NAME = "java.lang.SuppressWarnings";
public static SuppressManager getInstance() {
return ServiceManager.getService(SuppressManager.class);
}
@NotNull
public abstract SuppressIntentionAction[] createSuppressActions(@NotNull HighlightDisplayKey key);
public abstract boolean isSuppressedFor(@NotNull PsiElement element, final String toolId);
public abstract PsiElement getElementMemberSuppressedIn(@NotNull PsiDocCommentOwner owner, final String inspectionToolID);
@Nullable
public abstract PsiElement getAnnotationMemberSuppressedIn(@NotNull PsiModifierListOwner owner, String inspectionToolID);
@Nullable
public abstract PsiElement getDocCommentToolSuppressedIn(@NotNull PsiDocCommentOwner owner, String inspectionToolID);
@NotNull
public abstract Collection<String> getInspectionIdsSuppressedInAnnotation(@NotNull PsiModifierListOwner owner);
@Nullable
public abstract String getSuppressedInspectionIdsIn(@NotNull PsiElement element);
@Nullable
public abstract PsiElement getElementToolSuppressedIn(@NotNull PsiElement place, String toolId);
public abstract boolean canHave15Suppressions(@NotNull PsiElement file);
public abstract boolean alreadyHas14Suppressions(@NotNull PsiDocCommentOwner commentOwner);
public static boolean isSuppressedInspectionName(PsiLiteralExpression expression) {
PsiAnnotation annotation = PsiTreeUtil.getParentOfType(expression, PsiAnnotation.class, true, PsiCodeBlock.class, PsiField.class);
return annotation != null && SUPPRESS_INSPECTIONS_ANNOTATION_NAME.equals(annotation.getQualifiedName());
}
@NotNull
@Override
public SuppressQuickFix[] createBatchSuppressActions(@NotNull HighlightDisplayKey key) {
return BatchSuppressManager.SERVICE.getInstance().createBatchSuppressActions(key);
}
@NotNull
public abstract SuppressIntentionAction[] createSuppressActions(@NotNull HighlightDisplayKey key);
}
@@ -0,0 +1,42 @@
/*
* 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.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface BatchSuppressableTool {
/**
* Checks if the inspection is suppressed for the specified element.
*
* @param element the element to check
* @return true if the inspection is suppressed, false otherwise.
*/
boolean isSuppressedFor(@NotNull PsiElement element);
/**
* Returns the list of suppression actions for the specified element.
*
* @param element the element on which Alt-Enter is pressed, or null if getting the list of available suppression actions in
* Inspections tool window
* @return the list of suppression actions.
*/
@NotNull
SuppressQuickFix[] getBatchSuppressActions(@Nullable final PsiElement element);
}
@@ -0,0 +1,110 @@
/*
* 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.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
import org.jetbrains.annotations.NotNull;
public abstract class LocalQuickFixOnPsiElement implements LocalQuickFix {
protected static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.LocalQuickFixAndIntentionAction");
protected final SmartPsiElementPointer<PsiElement> myStartElement;
protected final SmartPsiElementPointer<PsiElement> myEndElement;
protected LocalQuickFixOnPsiElement(@NotNull PsiElement element) {
this(element, element);
}
public LocalQuickFixOnPsiElement(PsiElement startElement, PsiElement endElement) {
if (startElement == null || endElement == null) {
myStartElement = myEndElement = null;
return;
}
LOG.assertTrue(startElement.isValid());
PsiFile startContainingFile = startElement.getContainingFile();
PsiFile endContainingFile = startElement == endElement ? startContainingFile : endElement.getContainingFile();
if (startElement != endElement) {
LOG.assertTrue(endElement.isValid());
LOG.assertTrue(startContainingFile == endContainingFile, "Both elements must be from the same file");
}
Project project = startContainingFile == null ? startElement.getProject() : startContainingFile.getProject(); // containingFile can be null for a directory
myStartElement = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(startElement, startContainingFile);
myEndElement = endElement == startElement ? null : SmartPointerManager.getInstance(project).createSmartPsiElementPointer(endElement, endContainingFile);
}
@NotNull
@Override
public final String getName() {
return getText();
}
public boolean isAvailable(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
return true;
}
protected boolean isAvailable() {
if (myStartElement == null) return false;
final PsiElement startElement = myStartElement.getElement();
final PsiElement endElement = myEndElement == null ? startElement : myEndElement.getElement();
PsiFile file = myStartElement.getContainingFile();
Project project = myStartElement.getProject();
return startElement != null &&
endElement != null &&
startElement.isValid() &&
(endElement == startElement || endElement.isValid()) &&
file != null &&
isAvailable(project, file, startElement, endElement);
}
public PsiElement getStartElement() {
return myStartElement == null ? null : myStartElement.getElement();
}
public PsiElement getEndElement() {
return myEndElement == null ? null : myEndElement.getElement();
}
@NotNull
public abstract String getText();
@Override
public final void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
applyFix();
}
public void applyFix() {
if (myStartElement == null) return;
final PsiElement startElement = myStartElement.getElement();
final PsiElement endElement = myEndElement == null ? startElement : myEndElement.getElement();
if (startElement == null || endElement == null) return;
PsiFile file = startElement.getContainingFile();
if (file == null) return;
invoke(file.getProject(), file, startElement, endElement);
}
public abstract void invoke(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement);
}
@@ -0,0 +1,25 @@
/*
* 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.openapi.project.Project;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
public interface SuppressQuickFix extends LocalQuickFix {
SuppressQuickFix[] EMPTY_ARRAY = new SuppressQuickFix[0];
boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement context);
}
@@ -0,0 +1,155 @@
/*
* 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.codeInsight.daemon.impl.actions;
import com.intellij.codeInsight.FileModificationService;
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.openapi.command.undo.UndoUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Collections;
import java.util.List;
/**
* @author Roman.Chernyatchik
* @date Aug 13, 2009
*/
public abstract class AbstractBatchSuppressByNoInspectionCommentFix implements SuppressQuickFix, Iconable {
@NotNull protected final String myID;
private final boolean myReplaceOtherSuppressionIds;
@Nullable
public abstract PsiElement getContainer(final PsiElement context);
/**
* @param ID Inspection ID
* @param replaceOtherSuppressionIds Merge suppression policy. If false new tool id will be append to the end
* otherwise replace other ids
*/
public AbstractBatchSuppressByNoInspectionCommentFix(@NotNull String ID, final boolean replaceOtherSuppressionIds) {
myID = ID;
myReplaceOtherSuppressionIds = replaceOtherSuppressionIds;
}
@NotNull
@Override
public String getName() {
return getText();
}
@Override
public Icon getIcon(int flags) {
return AllIcons.General.InspectionsOff;
}
private String myText = "";
@NotNull
public String getText() {
return myText;
}
protected void setText(@NotNull String text) {
myText = text;
}
public boolean startInWriteAction() {
return true;
}
@Override
public String toString() {
return getText();
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getStartElement();
if (element == null) return;
invoke(project, element);
}
protected final void replaceSuppressionComment(@NotNull final PsiElement comment) {
SuppressionUtil.replaceSuppressionComment(comment, myID, myReplaceOtherSuppressionIds);
}
protected void createSuppression(@NotNull Project project,
@NotNull PsiElement element,
@NotNull PsiElement container) throws IncorrectOperationException {
SuppressionUtil.createSuppression(project, element, container, myID);
}
@Override
public boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement context) {
return context.isValid() && PsiManager.getInstance(project).isInProject(context) && getContainer(context) != null;
}
public void invoke(@NotNull final Project project, @NotNull final PsiElement element) throws IncorrectOperationException {
if (!isAvailable(project, element)) return;
PsiElement container = getContainer(element);
if (container == null) return;
if (!FileModificationService.getInstance().preparePsiElementForWrite(container)) return;
if (replaceSuppressionComments(container)) return;
createSuppression(project, element, container);
UndoUtil.markPsiFileForUndo(element.getContainingFile());
}
protected boolean replaceSuppressionComments(PsiElement container) {
final List<? extends PsiElement> comments = getCommentsFor(container);
if (comments != null) {
for (PsiElement comment : comments) {
if (comment instanceof PsiComment && SuppressionUtil.isSuppressionComment(comment)) {
replaceSuppressionComment(comment);
return true;
}
}
}
return false;
}
@Nullable
protected List<? extends PsiElement> getCommentsFor(@NotNull final PsiElement container) {
final PsiElement prev = PsiTreeUtil.skipSiblingsBackward(container, PsiWhiteSpace.class);
if (prev == null) {
return null;
}
return Collections.singletonList(prev);
}
@Override
@NotNull
public String getFamilyName() {
return InspectionsBundle.message("suppress.inspection.family");
}
}
@@ -26,7 +26,7 @@ import org.jetbrains.annotations.Nullable;
/**
* @author ven
*/
public class SuppressByCommentFix extends AbstractSuppressByNoInspectionCommentFix {
public class SuppressByCommentFix extends AbstractBatchSuppressByNoInspectionCommentFix {
protected Class<? extends PsiElement> mySuppressionHolderClass;
public SuppressByCommentFix(@NotNull HighlightDisplayKey key, @NotNull Class<? extends PsiElement> suppressionHolderClass) {
@@ -46,7 +46,7 @@ public class SuppressByCommentFix extends AbstractSuppressByNoInspectionCommentF
@Override
@Nullable
protected PsiElement getContainer(PsiElement context) {
public PsiElement getContainer(PsiElement context) {
return PsiTreeUtil.getParentOfType(context, mySuppressionHolderClass);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
* 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.
@@ -16,11 +16,16 @@
package com.intellij.codeInspection;
import com.intellij.lang.Commenter;
import com.intellij.lang.LanguageCommenters;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.NullableComputable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiParserFacade;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NonNls;
@@ -100,4 +105,80 @@ public class SuppressionUtil {
}
}) != null;
}
@NotNull
public static PsiComment createComment(@NotNull Project project, @NotNull PsiElement element, @NotNull String commentText) {
final PsiParserFacade parserFacade = PsiParserFacade.SERVICE.getInstance(project);
return parserFacade.createLineOrBlockCommentFromText(element.getLanguage(), commentText);
}
@Nullable
public static Pair<String, String> getBlockPrefixSuffixPair(PsiElement comment) {
final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(comment.getLanguage());
if (commenter != null) {
final String prefix = commenter.getBlockCommentPrefix();
final String suffix = commenter.getBlockCommentSuffix();
if (prefix != null || suffix != null) {
return Pair.create(StringUtil.notNullize(prefix), StringUtil.notNullize(suffix));
}
}
return null;
}
@Nullable
public static String getLineCommentPrefix(@NotNull final PsiElement comment) {
final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(comment.getLanguage());
return commenter == null ? null : commenter.getLineCommentPrefix();
}
public static boolean isSuppressionComment(@NotNull PsiElement comment) {
final String prefix = getLineCommentPrefix(comment);
final String commentText = comment.getText();
if (prefix != null) {
return commentText.startsWith(prefix + SUPPRESS_INSPECTIONS_TAG_NAME);
}
final Pair<String, String> prefixSuffixPair = getBlockPrefixSuffixPair(comment);
return prefixSuffixPair != null
&& commentText.startsWith(prefixSuffixPair.first + SUPPRESS_INSPECTIONS_TAG_NAME)
&& commentText.endsWith(prefixSuffixPair.second);
}
public static void replaceSuppressionComment(@NotNull PsiElement comment, @NotNull String id, boolean replaceOtherSuppressionIds) {
final String oldSuppressionCommentText = comment.getText();
final String lineCommentPrefix = getLineCommentPrefix(comment);
Pair<String, String> blockPrefixSuffix = null;
if (lineCommentPrefix == null) {
blockPrefixSuffix = getBlockPrefixSuffixPair(comment);
}
assert blockPrefixSuffix != null
&& oldSuppressionCommentText.startsWith(blockPrefixSuffix.first)
&& oldSuppressionCommentText.endsWith(blockPrefixSuffix.second)
|| lineCommentPrefix != null && oldSuppressionCommentText.startsWith(lineCommentPrefix)
: "Unexpected suppression comment " + oldSuppressionCommentText;
// append new suppression tool id or replace
final String newText;
if(replaceOtherSuppressionIds) {
newText = SUPPRESS_INSPECTIONS_TAG_NAME + " " + id;
}
else if (lineCommentPrefix == null) {
newText = oldSuppressionCommentText.substring(blockPrefixSuffix.first.length(),
oldSuppressionCommentText.length() - blockPrefixSuffix.second.length()) + "," + id;
}
else {
newText = oldSuppressionCommentText.substring(lineCommentPrefix.length()) + "," + id;
}
PsiElement parent = comment.getParent();
comment.replace(createComment(comment.getProject(), parent != null ? parent : comment, newText));
}
public static void createSuppression(@NotNull Project project,
@NotNull PsiElement element,
@NotNull PsiElement container,
@NotNull String id) {
final String text = SUPPRESS_INSPECTIONS_TAG_NAME + " " + id;
PsiComment comment = createComment(project, element, text);
container.getParent().addBefore(comment, container);
}
}
@@ -16,46 +16,20 @@
package com.intellij.codeInspection;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.SmartPointerManager;
import com.intellij.psi.SmartPsiElementPointer;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class LocalQuickFixAndIntentionActionOnPsiElement implements LocalQuickFix, IntentionAction {
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInspection.LocalQuickFixAndIntentionAction");
private final SmartPsiElementPointer<PsiElement> myStartElement;
private final SmartPsiElementPointer<PsiElement> myEndElement;
public abstract class LocalQuickFixAndIntentionActionOnPsiElement extends LocalQuickFixOnPsiElement implements IntentionAction {
protected LocalQuickFixAndIntentionActionOnPsiElement(@Nullable PsiElement element) {
this(element, element);
}
protected LocalQuickFixAndIntentionActionOnPsiElement(@Nullable PsiElement startElement, @Nullable PsiElement endElement) {
if (startElement == null || endElement == null) {
myStartElement = myEndElement = null;
return;
}
LOG.assertTrue(startElement.isValid());
PsiFile startContainingFile = startElement.getContainingFile();
PsiFile endContainingFile = startElement == endElement ? startContainingFile : endElement.getContainingFile();
if (startElement != endElement) {
LOG.assertTrue(endElement.isValid());
LOG.assertTrue(startContainingFile == endContainingFile, "Both elements must be from the same file");
}
Project project = startContainingFile == null ? startElement.getProject() : startContainingFile.getProject(); // containingFile can be null for a directory
myStartElement = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(startElement, startContainingFile);
myEndElement = endElement == startElement ? null : SmartPointerManager.getInstance(project).createSmartPsiElementPointer(endElement, endContainingFile);
}
@NotNull
@Override
public final String getName() {
return getText();
super(startElement, endElement);
}
@Override
@@ -67,17 +41,6 @@ public abstract class LocalQuickFixAndIntentionActionOnPsiElement implements Loc
invoke(project, file, editor, startElement, endElement);
}
@Override
public final void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
if (myStartElement == null) return;
final PsiElement startElement = myStartElement.getElement();
final PsiElement endElement = myEndElement == null ? startElement : myEndElement.getElement();
if (startElement == null || endElement == null) return;
PsiFile file = startElement.getContainingFile();
if (file == null) return;
invoke(project, file, null, startElement, endElement);
}
@Override
public final boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (myStartElement == null) return false;
@@ -91,23 +54,17 @@ public abstract class LocalQuickFixAndIntentionActionOnPsiElement implements Loc
isAvailable(project, file, startElement, endElement);
}
public boolean isAvailable(@NotNull Project project,
@NotNull PsiFile file,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
return true;
}
public PsiElement getStartElement() {
return myStartElement == null ? null : myStartElement.getElement();
}
public abstract void invoke(@NotNull Project project,
@NotNull PsiFile file,
@Nullable("is null when called from inspection") Editor editor,
@NotNull PsiElement startElement,
@NotNull PsiElement endElement);
@Override
public void invoke(@NotNull Project project, @NotNull PsiFile file, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
invoke(project, file, null, startElement, endElement);
}
@Override
public boolean startInWriteAction() {
return true;
@@ -0,0 +1,61 @@
/*
* 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.intention.IntentionAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiFile;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
public class LocalQuickFixAsIntentionAdapter implements IntentionAction {
private final LocalQuickFix myFix;
@NotNull private final ProblemDescriptor myProblemDescriptor;
public LocalQuickFixAsIntentionAdapter(@NotNull LocalQuickFix fix, @NotNull ProblemDescriptor problemDescriptor) {
myFix = fix;
myProblemDescriptor = problemDescriptor;
}
@NotNull
@Override
public String getText() {
return myFix.getName();
}
@NotNull
@Override
public String getFamilyName() {
return myFix.getFamilyName();
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return myProblemDescriptor.getStartElement() != null;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
myFix.applyFix(project, myProblemDescriptor);
}
@Override
public boolean startInWriteAction() {
return true;
}
}
@@ -20,16 +20,95 @@
*/
package com.intellij.codeInspection;
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Iconable;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public abstract class SuppressIntentionAction extends PsiElementBaseIntentionAction implements Iconable {
public abstract class SuppressIntentionAction implements Iconable, IntentionAction {
private String myText = "";
public static SuppressIntentionAction[] EMPTY_ARRAY = new SuppressIntentionAction[0];
@Override
public Icon getIcon(int flags) {
return AllIcons.General.InspectionsOff;
}
@Override
@NotNull
public String getText() {
return myText;
}
protected void setText(@NotNull String text) {
myText = text;
}
@Override
public boolean startInWriteAction() {
return true;
}
@Override
public String toString() {
return getText();
}
@Override
public final void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
if (!file.getManager().isInProject(file)) return;
final PsiElement element = getElement(editor, file);
if (element != null) {
invoke(project, editor, element);
}
}
/**
* Invokes intention action for the element under caret.
*
* @param project the project in which the file is opened.
* @param editor the editor for the file.
* @param element the element under cursor.
* @throws com.intellij.util.IncorrectOperationException
*
*/
public abstract void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException;
@Override
public final boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
if (file == null) return false;
final PsiManager manager = file.getManager();
if (manager == null) return false;
if (!manager.isInProject(file)) return false;
final PsiElement element = getElement(editor, file);
return element != null && isAvailable(project, editor, element);
}
/**
* Checks whether this intention is available at a caret offset in file.
* If this method returns true, a light bulb for this intention is shown.
*
* @param project the project in which the availability is checked.
* @param editor the editor in which the intention will be invoked.
* @param element the element under caret.
* @return true if the intention is available, false otherwise.
*/
public abstract boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element);
@Nullable
private static PsiElement getElement(@NotNull Editor editor, @NotNull PsiFile file) {
CaretModel caretModel = editor.getCaretModel();
int position = caretModel.getOffset();
return file.findElementAt(position);
}
}
@@ -17,8 +17,7 @@ package com.intellij.lang.annotation;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.codeInspection.*;
import com.intellij.openapi.editor.HighlighterColors;
import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.openapi.editor.colors.TextAttributesKey;
@@ -75,7 +74,7 @@ public final class Annotation implements Segment {
this.options = options;
}
public QuickFixInfo(final IntentionAction fix, final TextRange range, @Nullable final HighlightDisplayKey key) {
public QuickFixInfo(@NotNull IntentionAction fix, final TextRange range, @Nullable final HighlightDisplayKey key) {
this.key = key;
quickFix = fix;
textRange = range;
@@ -123,6 +122,16 @@ public final class Annotation implements Segment {
registerFix(fix,range, null);
}
public void registerFix(@NotNull LocalQuickFix fix, TextRange range, HighlightDisplayKey key, @NotNull ProblemDescriptor problemDescriptor) {
if (range == null) {
range = new TextRange(myStartOffset, myEndOffset);
}
if (myQuickFixes == null) {
myQuickFixes = new ArrayList<QuickFixInfo>();
}
myQuickFixes.add(new QuickFixInfo(new LocalQuickFixAsIntentionAdapter(fix, problemDescriptor), range, key));
}
/**
* Registers a quick fix for the annotation which is only available on a particular range of text
* within the annotation.
@@ -159,8 +168,8 @@ public final class Annotation implements Segment {
}
/**
* Registers a quickfix which would be available during batch mode only,
* in particular during com.intellij.codeInspection.DefaultHighlightVisitorBasedInspection run
* Registers a quickfix which would be available during batch mode only,
* in particular during com.intellij.codeInspection.DefaultHighlightVisitorBasedInspection run
*/
public <T extends IntentionAction & LocalQuickFix> void registerBatchFix(@NotNull T fix, @Nullable TextRange range, @Nullable final HighlightDisplayKey key) {
if (range == null) {
@@ -302,7 +311,7 @@ public final class Annotation implements Segment {
public List<QuickFixInfo> getQuickFixes() {
return myQuickFixes;
}
@Nullable
public List<QuickFixInfo> getBatchFixes() {
return myBatchFixes;
@@ -22,9 +22,7 @@ import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.IntentionManager;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.actions.CleanupInspectionIntention;
import com.intellij.codeInspection.ex.GlobalInspectionToolWrapper;
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.codeInspection.ex.QuickFixWrapper;
import com.intellij.codeInspection.ex.*;
import com.intellij.lang.ASTNode;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.HighlightSeverity;
@@ -48,6 +46,7 @@ import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.xml.util.XmlStringUtil;
import org.intellij.lang.annotations.MagicConstant;
@@ -727,11 +726,18 @@ public class HighlightInfo implements Segment {
this(action, null, null, icon);
}
public IntentionActionDescriptor(@NotNull IntentionAction action, @Nullable final List<IntentionAction> options, @Nullable final String displayName, @Nullable Icon icon) {
public IntentionActionDescriptor(@NotNull IntentionAction action,
@Nullable final List<IntentionAction> options,
@Nullable final String displayName,
@Nullable Icon icon) {
this(action, options, displayName, icon, null);
}
public IntentionActionDescriptor(@NotNull IntentionAction action, @Nullable final List<IntentionAction> options, @Nullable final String displayName, @Nullable Icon icon, @Nullable HighlightDisplayKey key) {
public IntentionActionDescriptor(@NotNull IntentionAction action,
@Nullable final List<IntentionAction> options,
@Nullable final String displayName,
@Nullable Icon icon,
@Nullable HighlightDisplayKey key) {
myAction = action;
myOptions = options;
myDisplayName = displayName;
@@ -788,6 +794,15 @@ public class HighlightInfo implements Segment {
ContainerUtil.addAll(newOptions, suppressActions);
}
}
if (wrappedTool instanceof BatchSuppressableTool) {
final SuppressQuickFix[] suppressActions = ((BatchSuppressableTool)wrappedTool).getBatchSuppressActions(element);
ContainerUtil.addAll(newOptions, ContainerUtil.map(suppressActions, new Function<SuppressQuickFix, IntentionAction>() {
@Override
public IntentionAction fun(SuppressQuickFix fix) {
return InspectionManagerEx.convertBatchToSuppressIntentionAction(fix);
}
}));
}
synchronized (this) {
options = myOptions;
@@ -16,20 +16,17 @@
package com.intellij.codeInsight.daemon.impl.actions;
import com.google.common.base.Strings;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.SuppressionUtil;
import com.intellij.lang.Commenter;
import com.intellij.lang.LanguageCommenters;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiParserFacade;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
@@ -44,7 +41,7 @@ import java.util.List;
* @date Aug 13, 2009
*/
public abstract class AbstractSuppressByNoInspectionCommentFix extends SuppressIntentionAction {
protected final String myID;
@NotNull protected final String myID;
private final boolean myReplaceOtherSuppressionIds;
@Nullable
@@ -55,71 +52,19 @@ public abstract class AbstractSuppressByNoInspectionCommentFix extends SuppressI
* @param replaceOtherSuppressionIds Merge suppression policy. If false new tool id will be append to the end
* otherwise replace other ids
*/
public AbstractSuppressByNoInspectionCommentFix(final String ID, final boolean replaceOtherSuppressionIds) {
public AbstractSuppressByNoInspectionCommentFix(@NotNull String ID, final boolean replaceOtherSuppressionIds) {
myID = ID;
myReplaceOtherSuppressionIds = replaceOtherSuppressionIds;
}
protected final void replaceSuppressionComment(@NotNull final PsiElement comment) {
final String oldSuppressionCommentText = comment.getText();
final String lineCommentPrefix = getLineCommentPrefix(comment);
Pair<String, String> blockPrefixSuffix = null;
if (lineCommentPrefix == null) {
blockPrefixSuffix = getBlockPrefixSuffixPair(comment);
}
assert (blockPrefixSuffix != null && oldSuppressionCommentText.startsWith(blockPrefixSuffix.first)) && oldSuppressionCommentText.endsWith(blockPrefixSuffix.second)
|| (lineCommentPrefix != null && oldSuppressionCommentText.startsWith(lineCommentPrefix))
: "Unexpected suppression comment " + oldSuppressionCommentText;
// append new suppression tool id or replace
final String newText;
if(myReplaceOtherSuppressionIds) {
newText = SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + myID;
} else {
if (lineCommentPrefix != null) {
newText = oldSuppressionCommentText.substring(lineCommentPrefix.length()) + "," + myID;
} else {
newText = oldSuppressionCommentText.substring(blockPrefixSuffix.first.length(),
oldSuppressionCommentText.length() - blockPrefixSuffix.second.length()) + "," + myID;
}
}
PsiElement parent = comment.getParent();
comment.replace(createComment(comment.getProject(), parent != null ? parent : comment, newText));
SuppressionUtil.replaceSuppressionComment(comment, myID, myReplaceOtherSuppressionIds);
}
@Nullable
private static String getLineCommentPrefix(@NotNull final PsiElement comment) {
final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(comment.getLanguage());
return commenter == null ? null : commenter.getLineCommentPrefix();
}
@Nullable
private static Pair<String, String> getBlockPrefixSuffixPair(PsiElement comment) {
final Commenter commenter = LanguageCommenters.INSTANCE.forLanguage(comment.getLanguage());
if (commenter != null) {
final String prefix = commenter.getBlockCommentPrefix();
final String suffix = commenter.getBlockCommentSuffix();
if (prefix != null || suffix != null) {
return Pair.create(Strings.nullToEmpty(prefix), Strings.nullToEmpty(suffix));
}
}
return null;
}
protected void createSuppression(final Project project,
final Editor editor,
final PsiElement element,
final PsiElement container) throws IncorrectOperationException {
final String text = SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME + " " + myID;
PsiComment comment = createComment(project, element, text);
container.getParent().addBefore(comment, container);
}
@NotNull
protected PsiComment createComment(Project project, PsiElement element, String commentText) {
final PsiParserFacade parserFacade = PsiParserFacade.SERVICE.getInstance(project);
return parserFacade.createLineOrBlockCommentFromText(element.getLanguage(), commentText);
protected void createSuppression(@NotNull Project project,
@NotNull PsiElement element,
@NotNull PsiElement container) throws IncorrectOperationException {
SuppressionUtil.createSuppression(project, element, container, myID);
}
@Override
@@ -137,7 +82,7 @@ public abstract class AbstractSuppressByNoInspectionCommentFix extends SuppressI
final List<? extends PsiElement> comments = getCommentsFor(container);
if (comments != null) {
for (PsiElement comment : comments) {
if (comment instanceof PsiComment && isSuppressionComment(comment)) {
if (comment instanceof PsiComment && SuppressionUtil.isSuppressionComment(comment)) {
replaceSuppressionComment(comment);
return;
}
@@ -145,7 +90,15 @@ public abstract class AbstractSuppressByNoInspectionCommentFix extends SuppressI
}
boolean caretWasBeforeStatement = editor != null && editor.getCaretModel().getOffset() == container.getTextRange().getStartOffset();
createSuppression(project, editor, element, container);
try {
createSuppression(project, element, container);
}
catch (IncorrectOperationException e) {
if (!ApplicationManager.getApplication().isUnitTestMode() && editor != null) {
Messages.showErrorDialog(editor.getComponent(),
InspectionsBundle.message("suppress.inspection.annotation.syntax.error", e.getMessage()));
}
}
if (caretWasBeforeStatement) {
editor.getCaretModel().moveToOffset(container.getTextRange().getStartOffset());
@@ -153,18 +106,6 @@ public abstract class AbstractSuppressByNoInspectionCommentFix extends SuppressI
UndoUtil.markPsiFileForUndo(element.getContainingFile());
}
public static boolean isSuppressionComment(PsiElement comment) {
final String prefix = getLineCommentPrefix(comment);
final String commentText = comment.getText();
if (prefix != null) {
return commentText.startsWith(prefix + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME);
}
final Pair<String, String> prefixSuffixPair = getBlockPrefixSuffixPair(comment);
return prefixSuffixPair != null
&& commentText.startsWith(prefixSuffixPair.first + SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)
&& commentText.endsWith(prefixSuffixPair.second);
}
@Nullable
protected List<? extends PsiElement> getCommentsFor(@NotNull final PsiElement container) {
final PsiElement prev = PsiTreeUtil.skipSiblingsBackward(container, PsiWhiteSpace.class);
@@ -105,7 +105,7 @@ public class FileReferenceQuickFixProvider {
final VirtualFile virtualFile = context.getVirtualFile();
if (virtualFile == null) return Collections.emptyList();
final PsiDirectory directory = context.getManager().findDirectory(virtualFile);
if (directory == null) return Collections.emptyList();
@@ -147,25 +147,7 @@ public class FileReferenceQuickFixProvider {
isdirectory = false;
}
final CreateFileFix action = new CreateFileFix(isdirectory, newFileName, directory) {
@Override
protected String getFileText() {
if (!isdirectory) {
String templateName = reference.getNewFileTemplateName();
if (templateName != null) {
FileTemplate template = FileTemplateManager.getInstance().getTemplate(templateName);
if (template != null) {
try {
return template.getText(FileTemplateManager.getInstance().getDefaultProperties(directory.getProject()));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
}
return super.getFileText();
}
};
final CreateFileFix action = new MyCreateFileFix(isdirectory, newFileName, directory, reference);
QuickFixAction.registerQuickFixAction(info, action);
return Arrays.asList(action);
}
@@ -176,4 +158,35 @@ public class FileReferenceQuickFixProvider {
VirtualFile file = context.getVirtualFile();
return file != null ? ModuleUtil.findModuleForFile(file, context.getProject()) : null;
}
private static class MyCreateFileFix extends CreateFileFix {
private final boolean isDirectory;
private final PsiDirectory myDirectory;
private final FileReference myReference;
public MyCreateFileFix(boolean isdirectory, String newFileName, PsiDirectory directory, FileReference reference) {
super(isdirectory, newFileName, directory);
isDirectory = isdirectory;
myDirectory = directory;
myReference = reference;
}
@Override
protected String getFileText() {
if (!isDirectory) {
String templateName = myReference.getNewFileTemplateName();
if (templateName != null) {
FileTemplate template = FileTemplateManager.getInstance().getTemplate(templateName);
if (template != null) {
try {
return template.getText(FileTemplateManager.getInstance().getDefaultProperties(myDirectory.getProject()));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
}
}
return super.getFileText();
}
}
}
@@ -22,13 +22,16 @@
package com.intellij.codeInspection.ex;
import com.intellij.codeInsight.daemon.impl.actions.AbstractBatchSuppressByNoInspectionCommentFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.lang.InspectionExtensionsFactory;
import com.intellij.icons.AllIcons;
import com.intellij.ide.impl.ContentManagerWatcher;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.NotNullLazyValue;
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
@@ -40,6 +43,7 @@ import com.intellij.psi.PsiElement;
import com.intellij.ui.content.ContentFactory;
import com.intellij.ui.content.ContentManager;
import com.intellij.ui.content.TabbedPaneContentUI;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -82,6 +86,53 @@ public class InspectionManagerEx extends InspectionManagerBase {
}
}
@NotNull
public static SuppressIntentionAction convertBatchToSuppressIntentionAction(@NotNull final SuppressQuickFix fix) {
return new SuppressIntentionAction() {
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
PsiElement container = fix instanceof AbstractBatchSuppressByNoInspectionCommentFix
? ((AbstractBatchSuppressByNoInspectionCommentFix )fix).getContainer(element) : null;
boolean caretWasBeforeStatement = editor != null && container != null && editor.getCaretModel().getOffset() == container.getTextRange().getStartOffset();
try {
ProblemDescriptor descriptor =
new ProblemDescriptorImpl(element, element, "", null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false, null, false);
fix.applyFix(project, descriptor);
}
catch (IncorrectOperationException e) {
if (!ApplicationManager.getApplication().isUnitTestMode() && editor != null) {
Messages.showErrorDialog(editor.getComponent(),
InspectionsBundle.message("suppress.inspection.annotation.syntax.error", e.getMessage()));
}
else {
throw e;
}
}
if (caretWasBeforeStatement) {
editor.getCaretModel().moveToOffset(container.getTextRange().getStartOffset());
}
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
return fix.isAvailable(project, element);
}
@NotNull
@Override
public String getText() {
return fix.getName();
}
@NotNull
@Override
public String getFamilyName() {
return fix.getFamilyName();
}
};
}
@NotNull
public ProblemDescriptor createProblemDescriptor(@NotNull final PsiElement psiElement,
@@ -133,6 +184,9 @@ public class InspectionManagerEx extends InspectionManagerBase {
if (tool instanceof CustomSuppressableInspectionTool) {
return ((CustomSuppressableInspectionTool)tool).isSuppressedFor(place);
}
if (tool instanceof BatchSuppressableTool) {
return ((BatchSuppressableTool)tool).isSuppressedFor(place);
}
String alternativeId;
String id;
@@ -16,15 +16,14 @@
package com.intellij.codeInspection.ex;
import com.intellij.codeHighlighting.HighlightDisplayLevel;
import com.intellij.codeInspection.CustomSuppressableInspectionTool;
import com.intellij.codeInspection.InspectionEP;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.*;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -185,14 +184,23 @@ public abstract class InspectionToolWrapper<T extends InspectionProfileEntry, E
return super.getDescriptionUrl();
}
String fileName = getDescriptionFileName();
if (fileName == null) return null;
return myEP.getLoaderForClass().getResource("/inspectionDescriptions/" + fileName);
}
@Override
public SuppressIntentionAction[] getSuppressActions() {
if (getTool() instanceof CustomSuppressableInspectionTool) {
return ((CustomSuppressableInspectionTool)getTool()).getSuppressActions(null);
T tool = getTool();
if (tool instanceof CustomSuppressableInspectionTool) {
return ((CustomSuppressableInspectionTool)tool).getSuppressActions(null);
}
if (tool instanceof BatchSuppressableTool) {
LocalQuickFix[] actions = ((BatchSuppressableTool)tool).getBatchSuppressActions(null);
return ContainerUtil.map2Array(actions, SuppressIntentionAction.class, new Function<LocalQuickFix, SuppressIntentionAction>() {
@Override
public SuppressIntentionAction fun(final LocalQuickFix fix) {
return InspectionManagerEx.convertBatchToSuppressIntentionAction((SuppressQuickFix)fix);
}
});
}
return super.getSuppressActions();
}
@@ -26,6 +26,7 @@ import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.ModuleRootModel;
import com.intellij.openapi.roots.impl.storage.ClassPathStorageUtil;
import com.intellij.openapi.roots.impl.storage.ClasspathStorage;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
@@ -65,7 +66,7 @@ public class ExportEclipseProjectsAction extends AnAction implements DumbAware {
final List<Module> modules = new ArrayList<Module>();
final List<Module> incompatibleModules = new ArrayList<Module>();
for (Module module : ModuleManager.getInstance(project).getModules()) {
if (!JpsEclipseClasspathSerializer.CLASSPATH_STORAGE_ID.equals(ClasspathStorage.getStorageType(module))) {
if (!JpsEclipseClasspathSerializer.CLASSPATH_STORAGE_ID.equals(ClassPathStorageUtil.getStorageType(module))) {
try {
ClasspathStorage.getProvider(JpsEclipseClasspathSerializer.CLASSPATH_STORAGE_ID).assertCompatible(ModuleRootManager.getInstance(module));
modules.add(module);
@@ -44,22 +44,24 @@ import java.util.regex.Matcher;
/**
* @author peter
*/
public abstract class GroovySuppressableInspectionTool extends LocalInspectionTool implements CustomSuppressableInspectionTool {
@Nullable
public SuppressIntentionAction[] getSuppressActions(final PsiElement element) {
public abstract class GroovySuppressableInspectionTool extends LocalInspectionTool implements BatchSuppressableTool {
@NotNull
@Override
public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
return getSuppressActions(getShortName());
}
public static SuppressIntentionAction[] getSuppressActions(String name) {
public static SuppressQuickFix[] getSuppressActions(String name) {
final HighlightDisplayKey displayKey = HighlightDisplayKey.find(name);
return new SuppressIntentionAction[]{
return new SuppressQuickFix[] {
new SuppressByGroovyCommentFix(displayKey),
new SuppressForMemberFix(displayKey, false),
new SuppressForMemberFix(displayKey, true),
};
}
@Override
public boolean isSuppressedFor(@NotNull final PsiElement element) {
return isElementToolSuppressedIn(element, getID());
}
@@ -31,8 +31,9 @@ public class SuppressByGroovyCommentFix extends SuppressByCommentFix {
super(key, GrStatement.class);
}
@Override
@Nullable
protected PsiElement getContainer(PsiElement context) {
public PsiElement getContainer(PsiElement context) {
return PsiUtil.findEnclosingStatement(context);
}
@@ -16,13 +16,11 @@
package org.jetbrains.plugins.groovy.codeInspection;
import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInsight.daemon.impl.actions.AbstractBatchSuppressByNoInspectionCommentFix;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.SuppressManager;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
@@ -43,18 +41,18 @@ import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeParameter;
/**
* @author peter
*/
public class SuppressForMemberFix extends SuppressIntentionAction {
private final String myID;
public class SuppressForMemberFix extends AbstractBatchSuppressByNoInspectionCommentFix {
private String myKey;
private final boolean myForClass;
public SuppressForMemberFix(HighlightDisplayKey key, boolean forClass) {
myID = key.getID();
public SuppressForMemberFix(@NotNull HighlightDisplayKey key, boolean forClass) {
super(key.getID(), false);
myForClass = forClass;
}
@Override
@Nullable
protected GrDocCommentOwner getContainer(final PsiElement context) {
public GrDocCommentOwner getContainer(final PsiElement context) {
if (context == null || context instanceof PsiFile) {
return null;
}
@@ -76,7 +74,7 @@ public class SuppressForMemberFix extends SuppressIntentionAction {
if (myForClass) {
while (container != null ) {
final GrTypeDefinition parentClass = PsiTreeUtil.getParentOfType(container, GrTypeDefinition.class);
if ((parentClass == null) && container instanceof GrTypeDefinition){
if (parentClass == null && container instanceof GrTypeDefinition){
return container;
}
container = parentClass;
@@ -85,28 +83,29 @@ public class SuppressForMemberFix extends SuppressIntentionAction {
return container;
}
@Override
@NotNull
public String getText() {
return myKey != null ? InspectionsBundle.message(myKey) : "Suppress for member";
}
@NotNull
public String getFamilyName() {
return InspectionsBundle.message("suppress.inspection.family");
}
public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement context) {
@Override
public boolean isAvailable(@NotNull final Project project, @NotNull final PsiElement context) {
final GrDocCommentOwner container = getContainer(context);
myKey = container instanceof PsiClass ? "suppress.inspection.class" : container instanceof PsiMethod ? "suppress.inspection.method" : "suppress.inspection.field";
return container != null && context.getManager().isInProject(context);
}
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
GrDocCommentOwner container = getContainer(element);
assert container != null;
if (!FileModificationService.getInstance().preparePsiElementForWrite(container)) return;
final GrModifierList modifierList = (GrModifierList)container.getModifierList();
@Override
protected boolean replaceSuppressionComments(PsiElement container) {
return false;
}
@Override
protected void createSuppression(@NotNull Project project, @NotNull PsiElement element, @NotNull PsiElement container)
throws IncorrectOperationException {
final GrModifierList modifierList = (GrModifierList)((PsiModifierListOwner)container).getModifierList();
if (modifierList != null) {
addSuppressAnnotation(project, modifierList, myID);
}
@@ -15,7 +15,7 @@
*/
package org.jetbrains.plugins.groovy.codeInspection.spellchecker;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.SuppressQuickFix;
import com.intellij.psi.PsiElement;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.spellchecker.inspections.PlainTextSplitter;
@@ -34,7 +34,7 @@ import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
*/
public class GroovySpellcheckingStrategy extends SuppressibleSpellcheckingStrategy {
private final GrDocCommentTokenizer myDocCommentTokenizer = new GrDocCommentTokenizer();
private Tokenizer<PsiElement> myStringTokenizer = new Tokenizer<PsiElement>() {
private final Tokenizer<PsiElement> myStringTokenizer = new Tokenizer<PsiElement>() {
@Override
public void tokenize(@NotNull PsiElement literal, TokenConsumer consumer) {
String text = GrStringUtil.removeQuotes(literal.getText());
@@ -73,7 +73,7 @@ public class GroovySpellcheckingStrategy extends SuppressibleSpellcheckingStrate
}
@Override
public SuppressIntentionAction[] getSuppressActions(@NotNull PsiElement element, @NotNull String name) {
public SuppressQuickFix[] getSuppressActions(@NotNull PsiElement element, @NotNull String name) {
return GroovySuppressableInspectionTool.getSuppressActions(name);
}
}
@@ -19,7 +19,7 @@ import com.intellij.codeInsight.FileModificationService;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInspection.InspectionsBundle;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.lang.StdLanguages;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
@@ -76,13 +76,13 @@ class SuppressByCommentOutAction extends SuppressIntentionAction {
if (!element.isValid()) {
return false;
}
// find java code up there, going through injecttions if necessary
// find java code up there, going through injections if necessary
return findJavaCodeUpThere(element) != null;
}
private static PsiElement findJavaCodeUpThere(PsiElement element) {
while (element != null) {
if (element.getLanguage() == StdLanguages.JAVA) return element;
if (element.getLanguage() == JavaLanguage.INSTANCE) return element;
element = element.getContext();
}
return null;
@@ -16,8 +16,9 @@
package com.intellij.spellchecker;
import com.intellij.codeInsight.daemon.HighlightDisplayKey;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.BatchSuppressManager;
import com.intellij.codeInspection.SuppressManager;
import com.intellij.codeInspection.SuppressQuickFix;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiLiteralExpression;
import com.intellij.psi.PsiMethod;
@@ -64,7 +65,7 @@ public class JavaSpellcheckingStrategy extends SuppressibleSpellcheckingStrategy
}
@Override
public SuppressIntentionAction[] getSuppressActions(@NotNull PsiElement element, @NotNull String name) {
return SuppressManager.getInstance().createSuppressActions(HighlightDisplayKey.find(name));
public SuppressQuickFix[] getSuppressActions(@NotNull PsiElement element, @NotNull String name) {
return BatchSuppressManager.SERVICE.getInstance().createBatchSuppressActions(HighlightDisplayKey.find(name));
}
}
+2
View File
@@ -1078,6 +1078,8 @@
<applicationService serviceInterface="com.intellij.codeInspection.SuppressManager"
serviceImplementation="com.intellij.codeInspection.SuppressManagerImpl"/>
<applicationService serviceInterface="com.intellij.codeInspection.BatchSuppressManager"
serviceImplementation="com.intellij.codeInspection.BatchSuppressManagerImpl"/>
<declarationRangeHandler key="com.intellij.psi.PsiMethod"
implementationClass="com.intellij.codeInsight.hint.MethodDeclarationRangeHandler"/>
@@ -40,8 +40,7 @@ import java.awt.*;
import java.util.Set;
public class SpellCheckingInspection extends LocalInspectionTool implements CustomSuppressableInspectionTool {
public class SpellCheckingInspection extends LocalInspectionTool implements BatchSuppressableTool {
public static final String SPELL_CHECKING_INSPECTION_TOOL_NAME = "SpellCheckingInspection";
@Override
@@ -58,15 +57,16 @@ public class SpellCheckingInspection extends LocalInspectionTool implements Cust
return SpellCheckerBundle.message("spellchecking.inspection.name");
}
@NotNull
@Override
public SuppressIntentionAction[] getSuppressActions(@Nullable PsiElement element) {
public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
if (element != null) {
SpellcheckingStrategy strategy = LanguageSpellchecking.INSTANCE.forLanguage(element.getLanguage());
if(strategy instanceof SuppressibleSpellcheckingStrategy) {
return ((SuppressibleSpellcheckingStrategy)strategy).getSuppressActions(element, getShortName());
}
}
return SuppressIntentionAction.EMPTY_ARRAY;
return SuppressQuickFix.EMPTY_ARRAY;
}
@Override
@@ -15,7 +15,7 @@
*/
package com.intellij.spellchecker.tokenizer;
import com.intellij.codeInsight.daemon.impl.actions.AbstractSuppressByNoInspectionCommentFix;
import com.intellij.codeInspection.SuppressionUtil;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
@@ -51,7 +51,7 @@ public class SpellcheckingStrategy {
public Tokenizer getTokenizer(PsiElement element) {
if (element instanceof PsiNameIdentifierOwner) return new PsiIdentifierOwnerTokenizer();
if (element instanceof PsiComment) {
if (AbstractSuppressByNoInspectionCommentFix.isSuppressionComment(element)) {
if (SuppressionUtil.isSuppressionComment(element)) {
return EMPTY_TOKENIZER;
}
return myCommentTokenizer;
@@ -15,7 +15,7 @@
*/
package com.intellij.spellchecker.tokenizer;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.SuppressQuickFix;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
@@ -30,7 +30,7 @@ public abstract class SuppressibleSpellcheckingStrategy extends SpellcheckingStr
public abstract boolean isSuppressedFor(@NotNull PsiElement element, @NotNull String name);
/**
* @see com.intellij.codeInspection.CustomSuppressableInspectionTool#getSuppressActions(com.intellij.psi.PsiElement)
* @see com.intellij.codeInspection.BatchSuppressableTool#getBatchSuppressActions(com.intellij.psi.PsiElement)
*/
public abstract SuppressIntentionAction[] getSuppressActions(@NotNull PsiElement element, @NotNull String name);
public abstract SuppressQuickFix[] getSuppressActions(@NotNull PsiElement element, @NotNull String name);
}
@@ -1,6 +1,6 @@
package com.intellij.spellchecker.xml;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.SuppressQuickFix;
import com.intellij.psi.PsiElement;
import com.intellij.spellchecker.tokenizer.SuppressibleSpellcheckingStrategy;
import com.intellij.util.xml.DomElement;
@@ -25,7 +25,7 @@ public class XmlSpellcheckingStrategy extends SuppressibleSpellcheckingStrategy
}
@Override
public SuppressIntentionAction[] getSuppressActions(@NotNull PsiElement element, @NotNull String name) {
return SuppressIntentionAction.EMPTY_ARRAY;
public SuppressQuickFix[] getSuppressActions(@NotNull PsiElement element, @NotNull String name) {
return SuppressQuickFix.EMPTY_ARRAY;
}
}
@@ -16,22 +16,22 @@
package com.intellij.codeInspection;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool implements CustomSuppressableInspectionTool {
public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool implements BatchSuppressableTool {
@NonNls static final String ALL = "ALL";
@NotNull
@Override
public SuppressIntentionAction[] getSuppressActions(final PsiElement element) {
return new SuppressIntentionAction[]{new SuppressTag(), new SuppressForFile(getID()), new SuppressAllForFile()};
public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
return new SuppressQuickFix[]{new SuppressTag(), new SuppressForFile(getID()), new SuppressAllForFile()};
}
@Override
@@ -40,81 +40,83 @@ public abstract class XmlSuppressableInspectionTool extends LocalInspectionTool
}
public class SuppressTag extends SuppressTagStatic {
public SuppressTag() {
super(getID());
}
}
public static class SuppressTagStatic extends SuppressIntentionAction {
public static class SuppressTagStatic implements SuppressQuickFix {
private final String id;
public SuppressTagStatic(@NotNull String id) {
this.id = id;
}
@Override
@NotNull
public String getText() {
@Override
public String getName() {
return InspectionsBundle.message("xml.suppressable.for.tag.title");
}
@Override
public boolean isAvailable(@NotNull Project project, @NotNull PsiElement context) {
return context.isValid();
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
if (PsiTreeUtil.getParentOfType(element, XmlTag.class) == null) return;
XmlSuppressionProvider.getProvider(element.getContainingFile()).suppressForTag(element, id);
}
@Override
@NotNull
public String getFamilyName() {
return getText();
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) {
return PsiTreeUtil.getParentOfType(element, XmlTag.class) != null;
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
XmlSuppressionProvider.getProvider(element.getContainingFile()).suppressForTag(element, id);
return getName();
}
}
public static class SuppressForFile extends SuppressIntentionAction {
public static class SuppressForFile implements SuppressQuickFix {
private final String myInspectionId;
public SuppressForFile(@NotNull String inspectionId) {
myInspectionId = inspectionId;
}
@Override
@NotNull
public String getText() {
@Override
public String getName() {
return InspectionsBundle.message("xml.suppressable.for.file.title");
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
if (element == null || !element.isValid() || !(element.getContainingFile() instanceof XmlFile)) return;
XmlSuppressionProvider.getProvider(element.getContainingFile()).suppressForFile(element, myInspectionId);
}
@Override
public boolean isAvailable(@NotNull Project project, @NotNull PsiElement context) {
return context.isValid();
}
@Override
@NotNull
public String getFamilyName() {
return getText();
}
@Override
public void invoke(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) throws IncorrectOperationException {
XmlSuppressionProvider.getProvider(element.getContainingFile()).suppressForFile(element, myInspectionId);
}
@Override
public boolean isAvailable(@NotNull final Project project, final Editor editor, @NotNull final PsiElement element) {
return element.isValid() && element.getContainingFile() instanceof XmlFile;
return getName();
}
}
public static class SuppressAllForFile extends SuppressForFile {
public SuppressAllForFile() {
super(ALL);
}
@Override
@NotNull
public String getText() {
@Override
public String getName() {
return InspectionsBundle.message("xml.suppressable.all.for.file.title");
}
}
@@ -16,11 +16,8 @@
package org.intellij.plugins.relaxNG.inspections;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.codeInspection.SuppressIntentionAction;
import com.intellij.codeInspection.XmlSuppressableInspectionTool;
import com.intellij.codeInspection.*;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
@@ -31,7 +28,6 @@ import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.intellij.plugins.relaxNG.compact.psi.*;
import org.jetbrains.annotations.Nls;
@@ -45,6 +41,7 @@ import org.jetbrains.annotations.Nullable;
* Date: 25.11.2007
*/
public abstract class BaseInspection extends XmlSuppressableInspectionTool {
@Override
@Nls
@NotNull
public final String getGroupDisplayName() {
@@ -88,65 +85,69 @@ public abstract class BaseInspection extends XmlSuppressableInspectionTool {
return false;
}
@NotNull
@Override
@Nullable
public SuppressIntentionAction[] getSuppressActions(PsiElement element) {
public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
if (element.getContainingFile() instanceof RncFile) {
return ArrayUtil.mergeArrays(new SuppressIntentionAction[]{
return ArrayUtil.mergeArrays(new SuppressQuickFix[] {
new SuppressAction("Define") {
@Override
protected PsiElement getTarget(PsiElement element) {
return PsiTreeUtil.getParentOfType(element, RncDefine.class, false);
}
},
new SuppressAction("Grammar") {
@Override
protected PsiElement getTarget(PsiElement element) {
final RncDefine define = PsiTreeUtil.getParentOfType(element, RncDefine.class, false);
return define != null ? PsiTreeUtil.getParentOfType(define, RncGrammar.class, false) : null;
}
@SuppressWarnings({ "SSBasedInspection" })
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
return super.isAvailable(project, editor, element) && getTarget(element).getText().startsWith("grammar ");
RncGrammar target = define != null ? PsiTreeUtil.getParentOfType(define, RncGrammar.class, false) : null;
return target != null && target.getText().startsWith("grammar ") ? target : null;
}
}
}, getXmlOnlySuppressions(element));
} else {
return super.getSuppressActions(element);
}
else {
return super.getBatchSuppressActions(element);
}
}
private SuppressIntentionAction[] getXmlOnlySuppressions(PsiElement element) {
return ContainerUtil.map(super.getSuppressActions(element), new Function<SuppressIntentionAction, SuppressIntentionAction>() {
public SuppressIntentionAction fun(final SuppressIntentionAction action) {
return new SuppressIntentionAction() {
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
action.invoke(project, editor, element);
}
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
return element.getContainingFile().getFileType() == StdFileTypes.XML && action.isAvailable(project, editor, element);
}
private SuppressQuickFix[] getXmlOnlySuppressions(PsiElement element) {
return ContainerUtil.map(super.getBatchSuppressActions(element), new Function<SuppressQuickFix, SuppressQuickFix>() {
@Override
public SuppressQuickFix fun(final SuppressQuickFix action) {
return new SuppressQuickFix() {
@NotNull
public String getText() {
return action.getText();
@Override
public String getName() {
return action.getName();
}
public boolean startInWriteAction() {
return action.startInWriteAction();
@Override
public boolean isAvailable(@NotNull Project project, @NotNull PsiElement context) {
return context.isValid();
}
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
PsiFile file = element == null ? null : element.getContainingFile();
if (file == null || file.getFileType() != StdFileTypes.XML) return;
action.applyFix(project, descriptor);
}
@Override
@NotNull
public String getFamilyName() {
return action.getFamilyName();
}
};
}
}, new SuppressIntentionAction[0]);
}, SuppressQuickFix.EMPTY_ARRAY);
}
private void suppress(PsiFile file, @NotNull PsiElement location) {
suppress(file, location, "#suppress " + getID(), new Function<String, String>() {
@Override
public String fun(final String text) {
return text + ", " + getID();
}
@@ -160,7 +161,7 @@ public abstract class BaseInspection extends XmlSuppressableInspectionTool {
if (vfile == null || ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(vfile).hasReadonlyFiles()) {
return;
}
final Document doc = PsiDocumentManager.getInstance(project).getDocument(file);
assert doc != null;
@@ -188,7 +189,7 @@ public abstract class BaseInspection extends XmlSuppressableInspectionTool {
@NotNull
public abstract RncElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly);
private abstract class SuppressAction extends SuppressIntentionAction {
private abstract class SuppressAction implements SuppressQuickFix {
private final String myLocation;
public SuppressAction(String location) {
@@ -196,21 +197,28 @@ public abstract class BaseInspection extends XmlSuppressableInspectionTool {
}
@NotNull
public String getText() {
@Override
public String getName() {
return "Suppress for " + myLocation;
}
@Override
@NotNull
public String getFamilyName() {
return getDisplayName();
}
public void invoke(@NotNull Project project, Editor editor, @NotNull PsiElement element) throws IncorrectOperationException {
suppress(element.getContainingFile(), getTarget(element));
@Override
public boolean isAvailable(@NotNull Project project, @NotNull PsiElement context) {
return context.isValid();
}
public boolean isAvailable(@NotNull Project project, Editor editor, @NotNull PsiElement element) {
return getTarget(element) != null;
@Override
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
PsiElement element = descriptor.getPsiElement();
PsiElement target = getTarget(element);
if (target == null) return;
suppress(element.getContainingFile(), target);
}
protected abstract PsiElement getTarget(PsiElement element);