diff --git a/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/UnneededSuppressWarningsCleanUp.java b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/UnneededSuppressWarningsCleanUp.java new file mode 100644 index 00000000000..11d2cc9472d --- /dev/null +++ b/org.eclipse.jdt.core.manipulation/common/org/eclipse/jdt/internal/ui/fix/UnneededSuppressWarningsCleanUp.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2024 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.ui.fix; + +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.StringLiteral; + +import org.eclipse.jdt.internal.corext.fix.CleanUpConstants; +import org.eclipse.jdt.internal.corext.fix.UnneededSuppressWarningsFixCore; + +import org.eclipse.jdt.ui.cleanup.CleanUpRequirements; +import org.eclipse.jdt.ui.cleanup.ICleanUpFix; +import org.eclipse.jdt.ui.text.java.IProblemLocation; + +/** + * Create fix to remove unnecessary SuppressWarnings + * @see org.eclipse.jdt.internal.corext.fix.UnneededSuppressWarningsFixCore + */ +public class UnneededSuppressWarningsCleanUp extends AbstractMultiFix { + + public UnneededSuppressWarningsCleanUp(Map options) { + super(options); + } + + public UnneededSuppressWarningsCleanUp() { + super(); + } + + private StringLiteral fLiteral; + private CompilationUnit fSavedCompilationUnit= null; + + public void setLiteral(StringLiteral literal) { + fLiteral= literal; + } + + @Override + public CleanUpRequirements getRequirements() { + boolean requireAST= requireAST(); + Map requiredOptions= requireAST ? getRequiredOptions() : null; + return new CleanUpRequirements(requireAST, false, false, requiredOptions); + } + + private boolean requireAST() { + return isEnabled(CleanUpConstants.REMOVE_UNNECESSARY_SUPPRESS_WARNINGS); + } + + @Override + protected ICleanUpFix createFix(CompilationUnit compilationUnit) throws CoreException { + if (compilationUnit == null) + return null; + + ICleanUpFix coreFix= UnneededSuppressWarningsFixCore.createFix(fSavedCompilationUnit == null ? compilationUnit : fSavedCompilationUnit, + fLiteral); + return coreFix; + } + + @Override + protected ICleanUpFix createFix(CompilationUnit compilationUnit, IProblemLocation[] problems) throws CoreException { + if (compilationUnit == null) + return null; + + ICleanUpFix coreFix= UnneededSuppressWarningsFixCore.createFix(compilationUnit, fLiteral, problems); + return coreFix; + } + + private Map getRequiredOptions() { + Map result= new Hashtable<>(); + + if (isEnabled(CleanUpConstants.REMOVE_UNNECESSARY_SUPPRESS_WARNINGS)) + result.put(JavaCore.COMPILER_PB_SUPPRESS_WARNINGS, JavaCore.WARNING); + + return result; + } + + @Override + public String[] getStepDescriptions() { + return new String[0]; + } + + @Override + public String getPreview() { + // not used as traditional cleanup + return ""; //$NON-NLS-1$ + } + + @Override + public boolean canFix(ICompilationUnit compilationUnit, IProblemLocation problem) { + if (problem.getProblemId() == IProblem.UnusedWarningToken) + return isEnabled(CleanUpConstants.REMOVE_UNNECESSARY_SUPPRESS_WARNINGS); + + return false; + } + + @Override + public int computeNumberOfFixes(CompilationUnit compilationUnit) { + try { + ICompilationUnit cu= (ICompilationUnit)compilationUnit.getJavaElement(); + if (!cu.isStructureKnown()) + return 0; //[clean up] 'Remove unnecessary $NLS-TAGS$' removes necessary ones in case of syntax errors: https://bugs.eclipse.org/bugs/show_bug.cgi?id=285814 : + } catch (JavaModelException e) { + return 0; + } + + fSavedCompilationUnit= compilationUnit; + int result= 0; + IProblem[] problems= compilationUnit.getProblems(); + if (isEnabled(CleanUpConstants.REMOVE_UNNECESSARY_SUPPRESS_WARNINGS)) + result+= getNumberOfProblems(problems, IProblem.UnusedWarningToken); + + return result; + } +} diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java index 5967c1892f7..91d91756c20 100644 --- a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/CleanUpConstants.java @@ -1465,6 +1465,18 @@ public class CleanUpConstants { */ public static final String REMOVE_UNNECESSARY_NLS_TAGS= "cleanup.remove_unnecessary_nls_tags"; //$NON-NLS-1$ + /** + * Remove unnecessary SuppressWarnings specifiers. + *
+ * Possible values: {TRUE, FALSE}
+ *
+ * + * @see CleanUpOptions#TRUE + * @see CleanUpOptions#FALSE + * @since 4.34 + */ + public static final String REMOVE_UNNECESSARY_SUPPRESS_WARNINGS= "cleanup.remove_unnecessary_suppress_warnings"; //$NON-NLS-1$ + /** * Insert inferred type arguments for diamonds.
*
diff --git a/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/UnneededSuppressWarningsFixCore.java b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/UnneededSuppressWarningsFixCore.java new file mode 100644 index 00000000000..7664055bc8c --- /dev/null +++ b/org.eclipse.jdt.core.manipulation/core extension/org/eclipse/jdt/internal/corext/fix/UnneededSuppressWarningsFixCore.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2024 Red Hat Inc. and others. + * + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Red Hat Inc. - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.corext.fix; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.core.dom.ASTNode; +import org.eclipse.jdt.core.dom.ArrayInitializer; +import org.eclipse.jdt.core.dom.CompilationUnit; +import org.eclipse.jdt.core.dom.MemberValuePair; +import org.eclipse.jdt.core.dom.NormalAnnotation; +import org.eclipse.jdt.core.dom.SingleMemberAnnotation; +import org.eclipse.jdt.core.dom.StringLiteral; +import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; + +import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; +import org.eclipse.jdt.internal.corext.util.Messages; + +import org.eclipse.jdt.ui.text.java.IProblemLocation; + +import org.eclipse.jdt.internal.ui.text.correction.CorrectionMessages; +import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation; + +/** + * Remove unneeded SuppressWarnings annotations. + */ +public class UnneededSuppressWarningsFixCore extends CompilationUnitRewriteOperationsFixCore { + + public UnneededSuppressWarningsFixCore(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation operation) { + super(name, compilationUnit, operation); + } + + public static IProposableFix createFix(CompilationUnit compilationUnit, StringLiteral origLiteral) { + IProblem[] problems= compilationUnit.getProblems(); + List locationsList= new ArrayList<>(); + for (int i= 0; i < problems.length; i++) { + IProblemLocation location= new ProblemLocation(problems[i]); + if (location.getProblemId() == IProblem.UnusedWarningToken) { + ASTNode node= location.getCoveringNode(compilationUnit); + if (node instanceof StringLiteral literal) { + if (literal.getLiteralValue() == origLiteral.getLiteralValue()) { + locationsList.add(location); + } + } + } + } + IProblemLocation[] locations= locationsList.toArray(new IProblemLocation[0]); + return createFix(compilationUnit, origLiteral, locations); + } + + public static IProposableFix createFix(CompilationUnit compilationUnit, IProblemLocation problem) { + StringLiteral literal= (StringLiteral)problem.getCoveringNode(compilationUnit); + return createFix(compilationUnit, literal, new IProblemLocation[] { problem }); + } + + public static IProposableFix createFix(CompilationUnit compilationUnit, StringLiteral literal, IProblemLocation[] problems) { + ICompilationUnit cu= (ICompilationUnit)compilationUnit.getJavaElement(); + try { + if (!cu.isStructureKnown()) + return null; + } catch (JavaModelException e) { + return null; + } + String label= Messages.format(CorrectionMessages.SuppressWarningsSubProcessor_remove_annotation_label, literal.getLiteralValue()); + return new UnneededSuppressWarningsFixCore(label, compilationUnit, new RemoveUnneededSuppressWarningsOperation(problems)); + } + + private static class RemoveUnneededSuppressWarningsOperation extends CompilationUnitRewriteOperation { + + private IProblemLocation[] fLocations; + public RemoveUnneededSuppressWarningsOperation(IProblemLocation[] locations) { + this.fLocations= locations; + } + + @Override + public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModelCore linkedModel) throws CoreException { + + for (IProblemLocation location : fLocations) { + ASTNode coveringNode= location.getCoveringNode(cuRewrite.getRoot()); + if (!(coveringNode instanceof StringLiteral)) + continue; + + if (coveringNode.getParent() instanceof MemberValuePair) { + coveringNode= coveringNode.getParent(); + } + + ASTNode parent= coveringNode.getParent(); + ASTRewrite rewrite= cuRewrite.getASTRewrite(); + if (parent instanceof SingleMemberAnnotation) { + rewrite.remove(parent, null); + } else if (parent instanceof NormalAnnotation) { + NormalAnnotation annot= (NormalAnnotation) parent; + if (annot.values().size() == 1) { + rewrite.remove(annot, null); + } else { + rewrite.remove(coveringNode, null); + } + } else if (parent instanceof ArrayInitializer) { + rewrite.remove(coveringNode, null); + } + } + + } + + } + +} diff --git a/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/internal/ui/text/correction/SuppressWarningsBaseSubProcessor.java b/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/internal/ui/text/correction/SuppressWarningsBaseSubProcessor.java index 3246fbca6cb..be07dd24304 100644 --- a/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/internal/ui/text/correction/SuppressWarningsBaseSubProcessor.java +++ b/org.eclipse.jdt.core.manipulation/proposals/org/eclipse/jdt/internal/ui/text/correction/SuppressWarningsBaseSubProcessor.java @@ -16,7 +16,9 @@ package org.eclipse.jdt.internal.ui.text.correction; import java.util.Collection; +import java.util.Hashtable; import java.util.List; +import java.util.Map; import org.eclipse.jdt.core.CorrectionEngine; import org.eclipse.jdt.core.ICompilationUnit; @@ -48,12 +50,19 @@ import org.eclipse.jdt.internal.core.manipulation.util.BasicElementLabels; import org.eclipse.jdt.internal.corext.dom.ASTNodes; +import org.eclipse.jdt.internal.corext.fix.CleanUpConstants; +import org.eclipse.jdt.internal.corext.fix.IProposableFix; +import org.eclipse.jdt.internal.corext.fix.UnneededSuppressWarningsFixCore; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.corext.util.Messages; +import org.eclipse.jdt.ui.cleanup.CleanUpOptions; +import org.eclipse.jdt.ui.cleanup.ICleanUp; import org.eclipse.jdt.ui.text.java.IInvocationContext; import org.eclipse.jdt.ui.text.java.IProblemLocation; +import org.eclipse.jdt.internal.ui.fix.UnneededSuppressWarningsCleanUp; + public abstract class SuppressWarningsBaseSubProcessor { static final String ADD_SUPPRESSWARNINGS_ID= "org.eclipse.jdt.ui.correction.addSuppressWarnings"; //$NON-NLS-1$ @@ -224,30 +233,41 @@ public void getRemoveUnusedSuppressWarningProposals(IInvocationContext context, } ASTNode parent= coveringNode.getParent(); - - ASTRewrite rewrite= ASTRewrite.create(coveringNode.getAST()); - if (parent instanceof SingleMemberAnnotation) { - rewrite.remove(parent, null); - } else if (parent instanceof NormalAnnotation) { - NormalAnnotation annot= (NormalAnnotation) parent; - if (annot.values().size() == 1) { - rewrite.remove(annot, null); - } else { - rewrite.remove(coveringNode, null); - } - } else if (parent instanceof ArrayInitializer) { - rewrite.remove(coveringNode, null); - } else { +// +// ASTRewrite rewrite= ASTRewrite.create(coveringNode.getAST()); +// if (parent instanceof SingleMemberAnnotation) { +// rewrite.remove(parent, null); +// } else if (parent instanceof NormalAnnotation) { +// NormalAnnotation annot= (NormalAnnotation) parent; +// if (annot.values().size() == 1) { +// rewrite.remove(annot, null); +// } else { +// rewrite.remove(coveringNode, null); +// } +// } else if (parent instanceof ArrayInitializer) { +// rewrite.remove(coveringNode, null); +// } else { +// return; +// } +// String label= Messages.format(CorrectionMessages.SuppressWarningsSubProcessor_remove_annotation_label, literal.getLiteralValue()); +// T proposal= createASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.REMOVE_ANNOTATION); + if (!(parent instanceof SingleMemberAnnotation) && !(parent instanceof NormalAnnotation) && !(parent instanceof ArrayInitializer)) { return; } - String label= Messages.format(CorrectionMessages.SuppressWarningsSubProcessor_remove_annotation_label, literal.getLiteralValue()); - T proposal= createASTRewriteCorrectionProposal(label, context.getCompilationUnit(), rewrite, IProposalRelevance.REMOVE_ANNOTATION); - proposals.add(proposal); - return; + IProposableFix fix= UnneededSuppressWarningsFixCore.createFix(context.getASTRoot(), problem); + if (fix != null) { + Map options= new Hashtable<>(); + options.put(CleanUpConstants.REMOVE_UNNECESSARY_SUPPRESS_WARNINGS, CleanUpOptions.TRUE); + UnneededSuppressWarningsCleanUp cleanUp= new UnneededSuppressWarningsCleanUp(options); + cleanUp.setLiteral(literal); + T proposal= createFixCorrectionProposal(fix, cleanUp, IProposalRelevance.REMOVE_ANNOTATION, context); + proposals.add(proposal); + } } protected abstract T createSuppressWarningsProposal(String warningToken, String label, ICompilationUnit cu, ASTNode node, ChildListPropertyDescriptor property, int relevance); protected abstract T createASTRewriteCorrectionProposal(String name, ICompilationUnit cu, ASTRewrite rewrite, int relevance); + protected abstract T createFixCorrectionProposal(IProposableFix fix, ICleanUp cleanUp, int relevance, IInvocationContext context); } diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/SuppressWarningsSubProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/SuppressWarningsSubProcessor.java index 61d06658408..9aa42d8b4e1 100644 --- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/SuppressWarningsSubProcessor.java +++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/SuppressWarningsSubProcessor.java @@ -27,12 +27,16 @@ import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; +import org.eclipse.jdt.internal.corext.fix.IProposableFix; + +import org.eclipse.jdt.ui.cleanup.ICleanUp; import org.eclipse.jdt.ui.text.java.IInvocationContext; import org.eclipse.jdt.ui.text.java.IProblemLocation; import org.eclipse.jdt.ui.text.java.correction.ASTRewriteCorrectionProposal; import org.eclipse.jdt.ui.text.java.correction.ICommandAccess; import org.eclipse.jdt.internal.ui.JavaPluginImages; +import org.eclipse.jdt.internal.ui.text.correction.proposals.FixCorrectionProposal; public class SuppressWarningsSubProcessor extends SuppressWarningsBaseSubProcessor { @@ -73,6 +77,20 @@ protected ICommandAccess createASTRewriteCorrectionProposal(String name, ICompil return new ASTRewriteCorrectionProposal(name, cu, rewrite, relevance, image); } + @Override + protected ICommandAccess createFixCorrectionProposal(IProposableFix fix, ICleanUp cleanUp, int relevance, IInvocationContext context) { + // Initialize as default image, though it should always trigger one of the two if statements below + Image image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); + if(relevance == IProposalRelevance.FIX_SUPPRESS_TOKEN) { + image = JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE); + } else if (relevance == IProposalRelevance.REMOVE_ANNOTATION) { + image = PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_TOOL_DELETE); + } + FixCorrectionProposal proposal= new FixCorrectionProposal(fix, cleanUp, relevance, image, context); + proposal.setCommandId(ADD_SUPPRESSWARNINGS_ID); + return proposal; + } + SuppressWarningsSubProcessor() { }