summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephan Herrmann2012-04-29 08:58:23 (EDT)
committer Markus Keller2012-04-29 08:58:23 (EDT)
commitf63a426a0aa77b391bf2116dcd4eb3749abad092 (patch)
tree3c6d62bae4d55c4db93a1a4ece83de22e36c87c6
parent1268e822c591927d3bf64956a8e483c4a1499f6b (diff)
downloadeclipse.jdt.ui-f63a426a0aa77b391bf2116dcd4eb3749abad092.zip
eclipse.jdt.ui-f63a426a0aa77b391bf2116dcd4eb3749abad092.tar.gz
eclipse.jdt.ui-f63a426a0aa77b391bf2116dcd4eb3749abad092.tar.bz2
Bug 337977: [quick fix] Add quickfixes for null annotations
Patch from https://bugs.eclipse.org/bugs/show_bug.cgi?id=337977#c6 integrated into existing QuickFixProcessor Implementation not thoroughly reviewed!
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullAnnotationsCleanUp.java157
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullFixMessages.java36
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullFixMessages.properties18
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullQuickFixes.java270
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullRewriteOperations.java541
-rw-r--r--org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickFixProcessor.java26
6 files changed, 1048 insertions, 0 deletions
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullAnnotationsCleanUp.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullAnnotationsCleanUp.java
new file mode 100644
index 0000000..d23ba59
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullAnnotationsCleanUp.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 GK Software AG and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stephan Herrmann <stephan@cs.tu-berlin.de> - [quick fix] Add quick fixes for null annotations - https://bugs.eclipse.org/337977
+ * IBM Corporation - bug fixes
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+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.compiler.IProblem;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+
+import org.eclipse.jdt.ui.cleanup.CleanUpRequirements;
+import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
+import org.eclipse.jdt.ui.text.java.IProblemLocation;
+
+/**
+ * Cleanup for adding required null annotations.
+ *
+ * Crafted after the lead of Java50CleanUp
+ */
+public class NullAnnotationsCleanUp extends AbstractMultiFix {
+
+ private int handledProblemID;
+
+ public NullAnnotationsCleanUp(Map<String, String> options, int handledProblemID) {
+ super(options);
+ this.handledProblemID = handledProblemID;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public CleanUpRequirements getRequirements() {
+ Map<String, String> requiredOptions= getRequiredOptions();
+ return new CleanUpRequirements(true, false, false, requiredOptions);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ICleanUpFix createFix(CompilationUnit compilationUnit) throws CoreException {
+ return this.createFix(compilationUnit, null);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected ICleanUpFix createFix(CompilationUnit compilationUnit, IProblemLocation[] problems) throws CoreException {
+ if (compilationUnit == null)
+ return null;
+ IProblemLocation[] locations = null;
+ ArrayList<IProblemLocation> filteredLocations = new ArrayList<IProblemLocation>();
+ if (problems != null) {
+ for (int i = 0; i < problems.length; i++) {
+ if (problems[i].getProblemId() == this.handledProblemID)
+ filteredLocations.add(problems[i]);
+ }
+ locations = filteredLocations.toArray(new IProblemLocation[filteredLocations.size()]);
+ }
+ return NullQuickFixes.createCleanUp(compilationUnit, locations, this.handledProblemID);
+ }
+
+ private Map<String, String> getRequiredOptions() {
+ Map<String, String> result= new Hashtable<String, String>();
+ // TODO(SH): might set depending on this.handledProblemID, not sure about the benefit
+ result.put(JavaCore.COMPILER_PB_NULL_SPECIFICATION_VIOLATION, JavaCore.WARNING);
+ result.put(JavaCore.COMPILER_PB_REDUNDANT_NULL_CHECK, JavaCore.WARNING);
+ return result;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String[] getStepDescriptions() {
+ List<String> result= new ArrayList<String>();
+ switch (this.handledProblemID) {
+ case IProblem.NonNullLocalVariableComparisonYieldsFalse:
+ case IProblem.RedundantNullCheckOnNonNullLocalVariable:
+ case IProblem.RequiredNonNullButProvidedNull:
+ case IProblem.RequiredNonNullButProvidedPotentialNull:
+ case IProblem.RequiredNonNullButProvidedUnknown:
+ case IProblem.ParameterLackingNullableAnnotation:
+ result.add(NullFixMessages.NullAnnotationsCleanUp_add_nullable_annotation);
+ break;
+ case IProblem.IllegalDefinitionToNonNullParameter:
+ case IProblem.IllegalRedefinitionToNonNullParameter:
+ case IProblem.ParameterLackingNonNullAnnotation:
+ result.add(NullFixMessages.NullAnnotationsCleanUp_add_nonnull_annotation);
+ break;
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getPreview() {
+ // not used when not provided as a true cleanup(?)
+ return "No preview available"; //$NON-NLS-1$
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean canFix(ICompilationUnit compilationUnit, IProblemLocation problem) {
+ int id= problem.getProblemId();
+
+ if (id == this.handledProblemID) {
+ // FIXME search specifically: return param (which??)
+// if (QuickFixes.hasExplicitNullnessAnnotation(compilationUnit, problem.getOffset()))
+// return false;
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int computeNumberOfFixes(CompilationUnit compilationUnit) {
+ int result= 0;
+
+ IProblem[] problems= compilationUnit.getProblems();
+ for (int i= 0; i < problems.length; i++) {
+ int id= problems[i].getID();
+ if (id == this.handledProblemID) {
+ // FIXME search specifically: return param (which??)
+// if (!QuickFixes.hasExplicitNullnessAnnotation(compilationUnit, problems[i].getSourceStart()))
+ result++;
+ }
+ }
+ return result;
+ }
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullFixMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullFixMessages.java
new file mode 100644
index 0000000..3fd05d4
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullFixMessages.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 GK Software AG and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stephan Herrmann <stephan@cs.tu-berlin.de> - [quick fix] Add quick fixes for null annotations - https://bugs.eclipse.org/337977
+ * IBM Corporation - bug fixes
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import org.eclipse.osgi.util.NLS;
+
+public class NullFixMessages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.jdt.internal.ui.fix.NullFixMessages"; //$NON-NLS-1$
+
+
+ public static String NullAnnotationsCleanUp_add_nullable_annotation;
+ public static String NullAnnotationsCleanUp_add_nonnull_annotation;
+
+ public static String QuickFixes_add_annotation_change_name;
+ public static String QuickFixes_declare_method_parameter_nullness;
+ public static String QuickFixes_declare_method_return_nullness;
+ public static String QuickFixes_declare_overridden_parameter_as_nonnull;
+ public static String QuickFixes_declare_overridden_return_as_nullable;
+
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, NullFixMessages.class);
+ }
+
+ private NullFixMessages() {
+ }
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullFixMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullFixMessages.properties
new file mode 100644
index 0000000..172c9cb
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullFixMessages.properties
@@ -0,0 +1,18 @@
+###############################################################################
+# Copyright (c) 2011, 2012 GK Software AG and others.
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Eclipse Public License v1.0
+# which accompanies this distribution, and is available at
+# http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Stephan Herrmann <stephan@cs.tu-berlin.de> - [quick fix] Add quick fixes for null annotations - https://bugs.eclipse.org/337977
+# IBM Corporation - bug fixes
+###############################################################################
+NullAnnotationsCleanUp_add_nullable_annotation=Add missing @Nullable annotation
+NullAnnotationsCleanUp_add_nonnull_annotation=Add missing @NonNull annotation
+QuickFixes_add_annotation_change_name=Add Annotations
+QuickFixes_declare_method_parameter_nullness=Declare method parameter as @{0}
+QuickFixes_declare_method_return_nullness=Declare method return as @{0}
+QuickFixes_declare_overridden_parameter_as_nonnull=Adjust overridden method from {1}, mark parameter as @{0}
+QuickFixes_declare_overridden_return_as_nullable=Adjust overridden method from {1}, mark as returning @{0}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullQuickFixes.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullQuickFixes.java
new file mode 100644
index 0000000..610a138
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullQuickFixes.java
@@ -0,0 +1,270 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 GK Software AG and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stephan Herrmann <stephan@cs.tu-berlin.de> - [quick fix] Add quick fixes for null annotations - https://bugs.eclipse.org/337977
+ * IBM Corporation - bug fixes
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.swt.graphics.Image;
+
+import org.eclipse.jdt.core.ICompilationUnit;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.compiler.IProblem;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IVariableBinding;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.VariableDeclaration;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix;
+import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix.CompilationUnitRewriteOperation;
+import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
+
+import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
+import org.eclipse.jdt.ui.text.java.IInvocationContext;
+import org.eclipse.jdt.ui.text.java.IProblemLocation;
+import org.eclipse.jdt.ui.text.java.correction.ICommandAccess;
+
+import org.eclipse.jdt.internal.ui.JavaPluginImages;
+import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
+import org.eclipse.jdt.internal.ui.text.correction.proposals.FixCorrectionProposal;
+
+/**
+ * Quick Fixes for null-annotation related problems.
+ */
+public class NullQuickFixes {
+
+ /** Small adaptation just to make available the 'compilationUnit' passed at instantiation time. */
+ private static class MyCURewriteOperationsFix extends CompilationUnitRewriteOperationsFix {
+ CompilationUnit cu;
+ public MyCURewriteOperationsFix(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation[] operations) {
+ super(name, compilationUnit, operations);
+ this.cu = compilationUnit;
+ }
+ }
+
+ public static void addReturnAndArgumentTypeProposal(IInvocationContext context, IProblemLocation problem, Collection<ICommandAccess> proposals) {
+ CompilationUnit astRoot= context.getASTRoot();
+ ASTNode selectedNode= problem.getCoveringNode(astRoot);
+
+ if (isComplainingAboutArgument(selectedNode) || isComplainingAboutReturn(selectedNode))
+ addNullAnnotationInSignatureProposal(context, problem, proposals, false);
+ }
+
+ public static void addNullAnnotationInSignatureProposal(IInvocationContext context,
+ IProblemLocation problem,
+ Collection<ICommandAccess> proposals,
+ boolean modifyOverridden) {
+ MyCURewriteOperationsFix fix= createNullAnnotationInSignatureFix(context.getASTRoot(), problem, modifyOverridden);
+
+ if (fix != null) {
+ Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
+ Map<String, String> options= new Hashtable<String, String>();
+ if (fix.cu != context.getASTRoot()) {
+ // workaround: adjust the unit to operate on, depending on the findings of RewriteOperations.createAddAnnotationOperation(..)
+ final CompilationUnit cu = fix.cu;
+ final IInvocationContext originalContext = context;
+ context = new IInvocationContext() {
+ public int getSelectionOffset() {
+ return originalContext.getSelectionOffset();
+ }
+ public int getSelectionLength() {
+ return originalContext.getSelectionLength();
+ }
+ public ASTNode getCoveringNode() {
+ return originalContext.getCoveringNode();
+ }
+ public ASTNode getCoveredNode() {
+ return originalContext.getCoveredNode();
+ }
+ public ICompilationUnit getCompilationUnit() {
+ return (ICompilationUnit) cu.getJavaElement();
+ }
+
+ public CompilationUnit getASTRoot() {
+ return cu;
+ }
+ };
+ }
+ int relevance = modifyOverridden ? 15 : 20; // TODO(SH): insert suitable values, just raise local change above change in overridden method
+ FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new NullAnnotationsCleanUp(options, problem.getProblemId()), relevance, image, context);
+ proposals.add(proposal);
+ }
+ }
+
+ private static boolean isComplainingAboutArgument(ASTNode selectedNode) {
+ if (!(selectedNode instanceof SimpleName)) {
+ return false;
+ }
+ SimpleName nameNode= (SimpleName) selectedNode;
+ IBinding binding = nameNode.resolveBinding();
+ if (binding.getKind() == IBinding.VARIABLE && ((IVariableBinding) binding).isParameter())
+ return true;
+ VariableDeclaration argDecl = (VariableDeclaration) ASTNodes.getParent(selectedNode, VariableDeclaration.class);
+ if (argDecl != null)
+ binding = argDecl.resolveBinding();
+ if (binding.getKind() == IBinding.VARIABLE && ((IVariableBinding) binding).isParameter())
+ return true;
+ return false;
+ }
+
+ private static boolean isComplainingAboutReturn(ASTNode selectedNode) {
+ return selectedNode.getParent().getNodeType() == ASTNode.RETURN_STATEMENT;
+ }
+
+ static MyCURewriteOperationsFix createNullAnnotationInSignatureFix(CompilationUnit compilationUnit, IProblemLocation problem, boolean modifyOverridden) {
+ String nullableAnnotationName = getNullableAnnotationName(compilationUnit.getJavaElement(), false);
+ String nonNullAnnotationName = getNonNullAnnotationName(compilationUnit.getJavaElement(), false);
+ String annotationToAdd = nullableAnnotationName;
+ String annotationToRemove = nonNullAnnotationName;
+
+ switch (problem.getProblemId()) {
+ case IProblem.IllegalDefinitionToNonNullParameter:
+ case IProblem.IllegalRedefinitionToNonNullParameter:
+ // case ParameterLackingNullableAnnotation: // never proposed with modifyOverridden
+ if (modifyOverridden) {
+ annotationToAdd = nonNullAnnotationName;
+ annotationToRemove = nullableAnnotationName;
+ }
+ break;
+ case IProblem.ParameterLackingNonNullAnnotation:
+ case IProblem.IllegalReturnNullityRedefinition:
+ if (!modifyOverridden) {
+ annotationToAdd = nonNullAnnotationName;
+ annotationToRemove = nullableAnnotationName;
+ }
+ break;
+ // all others propose to add @Nullable
+ }
+
+ // when performing one change at a time we can actually modify another CU than the current one:
+ NullRewriteOperations.SignatureAnnotationRewriteOperation operation =
+ NullRewriteOperations.createAddAnnotationOperation(
+ compilationUnit, problem, annotationToAdd, annotationToRemove, null,
+ false/*thisUnitOnly*/, true/*allowRemove*/, modifyOverridden);
+ if (operation == null)
+ return null;
+
+ return new MyCURewriteOperationsFix(operation.getMessage(),
+ operation.getCompilationUnit(), // note that this uses the findings from createAddAnnotationOperation(..)
+ new NullRewriteOperations.SignatureAnnotationRewriteOperation[] {operation});
+ }
+
+ // Entry for NullAnnotationsCleanup:
+ public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit, IProblemLocation[] locations, int problemID) {
+
+ ICompilationUnit cu= (ICompilationUnit)compilationUnit.getJavaElement();
+ if (!JavaModelUtil.is50OrHigher(cu.getJavaProject()))
+ return null;
+
+ List<CompilationUnitRewriteOperation> operations= new ArrayList<CompilationUnitRewriteOperation>();
+
+ if (locations == null) {
+ org.eclipse.jdt.core.compiler.IProblem[] problems= compilationUnit.getProblems();
+ locations= new IProblemLocation[problems.length];
+ for (int i= 0; i < problems.length; i++) {
+ if (problems[i].getID() == problemID)
+ locations[i]= new ProblemLocation(problems[i]);
+ }
+ }
+
+ createAddNullAnnotationOperations(compilationUnit, locations, operations);
+
+ if (operations.size() == 0)
+ return null;
+
+ CompilationUnitRewriteOperation[] operationsArray= operations.toArray(new CompilationUnitRewriteOperation[operations.size()]);
+ return new MyCURewriteOperationsFix(NullFixMessages.QuickFixes_add_annotation_change_name, compilationUnit, operationsArray);
+ }
+
+ private static void createAddNullAnnotationOperations(CompilationUnit compilationUnit, IProblemLocation[] locations, List<CompilationUnitRewriteOperation> result) {
+ String nullableAnnotationName = getNullableAnnotationName(compilationUnit.getJavaElement(), false);
+ String nonNullAnnotationName = getNonNullAnnotationName(compilationUnit.getJavaElement(), false);
+ Set<String> handledPositions = new HashSet<String>();
+ for (int i= 0; i < locations.length; i++) {
+ IProblemLocation problem= locations[i];
+ if (problem == null) continue; // problem was filtered out by createCleanUp()
+ String annotationToAdd = nullableAnnotationName;
+ String annotationToRemove = nonNullAnnotationName;
+ switch (problem.getProblemId()) {
+ case IProblem.IllegalDefinitionToNonNullParameter:
+ case IProblem.IllegalRedefinitionToNonNullParameter:
+ case IProblem.ParameterLackingNonNullAnnotation:
+ case IProblem.IllegalReturnNullityRedefinition:
+ annotationToAdd = nonNullAnnotationName;
+ annotationToRemove = nullableAnnotationName;
+ // all others propose to add @Nullable
+ }
+ // when performing multiple changes we can only modify the one CU that the CleanUp infrastructure provides to the operation.
+ CompilationUnitRewriteOperation fix = NullRewriteOperations.createAddAnnotationOperation(
+ compilationUnit, problem, annotationToAdd, annotationToRemove,
+ handledPositions, true/*thisUnitOnly*/, false/*allowRemove*/, false/*modifyOverridden*/);
+ if (fix != null)
+ result.add(fix);
+ }
+ }
+
+ public static boolean isMissingNullAnnotationProblem(int id) {
+ return id == IProblem.RequiredNonNullButProvidedNull || id == IProblem.RequiredNonNullButProvidedPotentialNull
+ || id == IProblem.IllegalReturnNullityRedefinition
+ || mayIndicateParameterNullcheck(id);
+ }
+
+ public static boolean mayIndicateParameterNullcheck(int problemId) {
+ return problemId == IProblem.NonNullLocalVariableComparisonYieldsFalse || problemId == IProblem.RedundantNullCheckOnNonNullLocalVariable;
+ }
+
+ public static boolean hasExplicitNullAnnotation(ICompilationUnit compilationUnit, int offset) {
+// FIXME(SH): check for existing annotations disabled due to lack of precision:
+// should distinguish what is actually annotated (return? param? which?)
+// try {
+// IJavaElement problemElement = compilationUnit.getElementAt(offset);
+// if (problemElement.getElementType() == IJavaElement.METHOD) {
+// IMethod method = (IMethod) problemElement;
+// String nullable = getNullableAnnotationName(compilationUnit, true);
+// String nonnull = getNonNullAnnotationName(compilationUnit, true);
+// for (IAnnotation annotation : method.getAnnotations()) {
+// if ( annotation.getElementName().equals(nonnull)
+// || annotation.getElementName().equals(nullable))
+// return true;
+// }
+// }
+// } catch (JavaModelException jme) {
+// /* nop */
+// }
+ return false;
+ }
+
+ public static String getNullableAnnotationName(IJavaElement javaElement, boolean makeSimple) {
+ String qualifiedName = javaElement.getJavaProject().getOption(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME, true);
+ int lastDot;
+ if (makeSimple && qualifiedName != null && (lastDot = qualifiedName.lastIndexOf('.')) != -1)
+ return qualifiedName.substring(lastDot+1);
+ return qualifiedName;
+ }
+
+ public static String getNonNullAnnotationName(IJavaElement javaElement, boolean makeSimple) {
+ String qualifiedName = javaElement.getJavaProject().getOption(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME, true);
+ int lastDot;
+ if (makeSimple && qualifiedName != null && (lastDot = qualifiedName.lastIndexOf('.')) != -1)
+ return qualifiedName.substring(lastDot+1);
+ return qualifiedName;
+ }
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullRewriteOperations.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullRewriteOperations.java
new file mode 100644
index 0000000..5f282c7
--- /dev/null
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/fix/NullRewriteOperations.java
@@ -0,0 +1,541 @@
+/*******************************************************************************
+ * Copyright (c) 2011, 2012 GK Software AG and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Stephan Herrmann <stephan@cs.tu-berlin.de> - [quick fix] Add quick fixes for null annotations - https://bugs.eclipse.org/337977
+ * IBM Corporation - bug fixes
+ *******************************************************************************/
+package org.eclipse.jdt.internal.ui.fix;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.runtime.CoreException;
+
+import org.eclipse.text.edits.TextEditGroup;
+
+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.AST;
+import org.eclipse.jdt.core.dom.ASTNode;
+import org.eclipse.jdt.core.dom.Annotation;
+import org.eclipse.jdt.core.dom.BodyDeclaration;
+import org.eclipse.jdt.core.dom.CompilationUnit;
+import org.eclipse.jdt.core.dom.IBinding;
+import org.eclipse.jdt.core.dom.IExtendedModifier;
+import org.eclipse.jdt.core.dom.IMethodBinding;
+import org.eclipse.jdt.core.dom.ITypeBinding;
+import org.eclipse.jdt.core.dom.IVariableBinding;
+import org.eclipse.jdt.core.dom.MarkerAnnotation;
+import org.eclipse.jdt.core.dom.MethodDeclaration;
+import org.eclipse.jdt.core.dom.MethodInvocation;
+import org.eclipse.jdt.core.dom.Name;
+import org.eclipse.jdt.core.dom.SimpleName;
+import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
+import org.eclipse.jdt.core.dom.VariableDeclaration;
+import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
+import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
+
+import org.eclipse.jdt.internal.corext.dom.ASTNodes;
+import org.eclipse.jdt.internal.corext.dom.Bindings;
+import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix.CompilationUnitRewriteOperation;
+import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
+import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
+import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
+import org.eclipse.jdt.internal.corext.util.Messages;
+
+import org.eclipse.jdt.ui.text.java.IProblemLocation;
+
+import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
+import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
+
+public class NullRewriteOperations {
+
+ static abstract class SignatureAnnotationRewriteOperation extends CompilationUnitRewriteOperation {
+ String fAnnotationToAdd;
+ String fAnnotationToRemove;
+ boolean fAllowRemove;
+ CompilationUnit fUnit;
+
+ protected String fKey;
+ protected String fMessage;
+
+ /** A globally unique key that identifies the position being annotated (for avoiding double annotations). */
+ public String getKey() { return this.fKey; }
+
+ public CompilationUnit getCompilationUnit() {
+ return fUnit;
+ }
+
+
+ boolean checkExisting(@SuppressWarnings("rawtypes") List existingModifiers,
+ ListRewrite listRewrite,
+ TextEditGroup editGroup)
+ {
+ for (Object mod : existingModifiers) {
+ if (mod instanceof MarkerAnnotation) {
+ MarkerAnnotation annotation = (MarkerAnnotation) mod;
+ String existingName = annotation.getTypeName().getFullyQualifiedName();
+ int lastDot = fAnnotationToRemove.lastIndexOf('.');
+ if ( existingName.equals(fAnnotationToRemove)
+ || (lastDot != -1 && fAnnotationToRemove.substring(lastDot+1).equals(existingName)))
+ {
+ if (!fAllowRemove)
+ return false; // veto this change
+ listRewrite.remove(annotation, editGroup);
+ return true;
+ }
+ // paranoia: check if by accident the annotation is already present (shouldn't happen):
+ lastDot = fAnnotationToAdd.lastIndexOf('.');
+ if ( existingName.equals(fAnnotationToAdd)
+ || (lastDot != -1 && fAnnotationToAdd.substring(lastDot+1).equals(existingName)))
+ {
+ return false; // already present
+ }
+ }
+ }
+ return true;
+ }
+
+ public String getMessage() {
+ return fMessage;
+ }
+ }
+
+ /**
+ * Rewrite operation that inserts an annotation into a method signature.
+ *
+ * Crafted after the lead of Java50Fix.AnnotationRewriteOperation
+ */
+ static class ReturnAnnotationRewriteOperation extends SignatureAnnotationRewriteOperation {
+
+ private final BodyDeclaration fBodyDeclaration;
+
+ ReturnAnnotationRewriteOperation(CompilationUnit unit,
+ MethodDeclaration method,
+ String annotationToAdd,
+ String annotationToRemove,
+ boolean allowRemove,
+ String message)
+ {
+ fUnit = unit;
+ fKey= method.resolveBinding().getKey()+"<return>"; //$NON-NLS-1$
+ fBodyDeclaration= method;
+ fAnnotationToAdd= annotationToAdd;
+ fAnnotationToRemove= annotationToRemove;
+ fAllowRemove= allowRemove;
+ fMessage = message;
+ }
+
+ @Override
+ public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
+ AST ast= cuRewrite.getRoot().getAST();
+ ListRewrite listRewrite= cuRewrite.getASTRewrite().getListRewrite(fBodyDeclaration, fBodyDeclaration.getModifiersProperty());
+ TextEditGroup group= createTextEditGroup(fMessage, cuRewrite);
+ if (!checkExisting(fBodyDeclaration.modifiers(), listRewrite, group))
+ return;
+ Annotation newAnnotation= ast.newMarkerAnnotation();
+ ImportRewrite importRewrite = cuRewrite.getImportRewrite();
+ String resolvableName = importRewrite.addImport(fAnnotationToAdd);
+ newAnnotation.setTypeName(ast.newName(resolvableName));
+ listRewrite.insertLast(newAnnotation, group); // null annotation is last modifier, directly preceding the return type
+ }
+ }
+
+ static class ParameterAnnotationRewriteOperation extends SignatureAnnotationRewriteOperation {
+
+ private SingleVariableDeclaration fArgument;
+
+ ParameterAnnotationRewriteOperation(CompilationUnit unit,
+ MethodDeclaration method,
+ String annotationToAdd,
+ String annotationToRemove,
+ String paramName,
+ boolean allowRemove,
+ String message)
+ {
+ fUnit= unit;
+ fKey= method.resolveBinding().getKey();
+ fAnnotationToAdd= annotationToAdd;
+ fAnnotationToRemove= annotationToRemove;
+ fAllowRemove= allowRemove;
+ fMessage = message;
+ for (Object param : method.parameters()) {
+ SingleVariableDeclaration argument = (SingleVariableDeclaration) param;
+ if (argument.getName().getIdentifier().equals(paramName)) {
+ fArgument= argument;
+ fKey += argument.getName().getIdentifier();
+ return;
+ }
+ }
+ // shouldn't happen, we've checked that paramName indeed denotes a parameter.
+ throw new RuntimeException("Argument "+paramName+" not found in method "+method.getName().getIdentifier()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ ParameterAnnotationRewriteOperation(CompilationUnit unit,
+ MethodDeclaration method,
+ String annotationToAdd,
+ String annotationToRemove,
+ int paramIdx,
+ boolean allowRemove,
+ String message)
+ {
+ fUnit= unit;
+ fKey= method.resolveBinding().getKey();
+ fAnnotationToAdd= annotationToAdd;
+ fAnnotationToRemove= annotationToRemove;
+ fAllowRemove= allowRemove;
+ fArgument = (SingleVariableDeclaration) method.parameters().get(paramIdx);
+ fKey += fArgument.getName().getIdentifier();
+ fMessage = message;
+ }
+
+ @Override
+ public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel linkedModel) throws CoreException {
+ AST ast= cuRewrite.getRoot().getAST();
+ ListRewrite listRewrite= cuRewrite.getASTRewrite().getListRewrite(fArgument, SingleVariableDeclaration.MODIFIERS2_PROPERTY);
+ TextEditGroup group= createTextEditGroup(fMessage, cuRewrite);
+ if (!checkExisting(fArgument.modifiers(), listRewrite, group))
+ return;
+ Annotation newAnnotation= ast.newMarkerAnnotation();
+ ImportRewrite importRewrite = cuRewrite.getImportRewrite();
+ String resolvableName = importRewrite.addImport(fAnnotationToAdd);
+ newAnnotation.setTypeName(ast.newName(resolvableName));
+ listRewrite.insertLast(newAnnotation, group); // null annotation is last modifier, directly preceding the type
+ }
+ }
+
+ // Entry for QuickFixes:
+ public static SignatureAnnotationRewriteOperation createAddAnnotationOperation(CompilationUnit compilationUnit,
+ IProblemLocation problem,
+ String annotationToAdd,
+ String annotationToRemove,
+ Set<String> handledPositions,
+ boolean thisUnitOnly,
+ boolean allowRemove,
+ boolean modifyOverridden)
+ {
+ SignatureAnnotationRewriteOperation result = modifyOverridden
+ ? createAddAnnotationToOverriddenOperation(compilationUnit, problem, annotationToAdd, annotationToRemove,
+ handledPositions, thisUnitOnly, allowRemove)
+ : createAddAnnotationOperation(compilationUnit, problem, annotationToAdd, annotationToRemove,
+ handledPositions, thisUnitOnly, allowRemove);
+ if (handledPositions != null && result != null) {
+ if (handledPositions.contains(result.getKey()))
+ return null;
+ handledPositions.add(result.getKey());
+ }
+ return result;
+ }
+ static SignatureAnnotationRewriteOperation createAddAnnotationOperation(CompilationUnit compilationUnit,
+ IProblemLocation problem,
+ String annotationToAdd,
+ String annotationToRemove,
+ Set<String> handledPositions,
+ boolean thisUnitOnly,
+ boolean allowRemove)
+ {
+ ICompilationUnit cu= (ICompilationUnit)compilationUnit.getJavaElement();
+ if (!JavaModelUtil.is50OrHigher(cu.getJavaProject()))
+ return null;
+
+ ASTNode selectedNode= problem.getCoveringNode(compilationUnit);
+ if (selectedNode == null)
+ return null;
+
+ ASTNode declaringNode= getDeclaringNode(selectedNode);
+
+ switch (problem.getProblemId()) {
+ case IProblem.IllegalDefinitionToNonNullParameter:
+// case IllegalRedefinitionToNonNullParameter:
+ // these affect another method
+ break;
+ case IProblem.IllegalReturnNullityRedefinition:
+ if (declaringNode == null)
+ declaringNode = selectedNode;
+ break; // do propose changes even if we already have an annotation
+ default:
+ // if this method has annotations, don't change'em
+ if (NullQuickFixes.hasExplicitNullAnnotation(cu, problem.getOffset()))
+ return null;
+ }
+
+ SignatureAnnotationRewriteOperation result = null;
+ String message = null;
+ String annotationNameLabel = annotationToAdd;
+ int lastDot = annotationToAdd.lastIndexOf('.');
+ if (lastDot != -1)
+ annotationNameLabel = annotationToAdd.substring(lastDot+1);
+ annotationNameLabel = BasicElementLabels.getJavaElementName(annotationNameLabel);
+
+ if (selectedNode.getParent() instanceof MethodInvocation) {
+ // DefiniteNullToNonNullParameter || PotentialNullToNonNullParameter
+ MethodInvocation methodInvocation = (MethodInvocation)selectedNode.getParent();
+ int paramIdx = methodInvocation.arguments().indexOf(selectedNode);
+ IMethodBinding methodBinding = methodInvocation.resolveMethodBinding();
+ compilationUnit = findCUForMethod(compilationUnit, cu, methodBinding);
+ if (compilationUnit == null)
+ return null;
+ if (thisUnitOnly && !compilationUnit.getJavaElement().equals(cu))
+ return null;
+ ASTNode methodDecl = compilationUnit.findDeclaringNode(methodBinding.getKey());
+ if (methodDecl == null)
+ return null;
+ message = Messages.format(NullFixMessages.QuickFixes_declare_method_parameter_nullness, annotationNameLabel);
+ result = new ParameterAnnotationRewriteOperation(compilationUnit,
+ (MethodDeclaration) methodDecl,
+ annotationToAdd,
+ annotationToRemove,
+ paramIdx,
+ allowRemove,
+ message);
+ } else if (declaringNode instanceof MethodDeclaration) {
+
+ // complaint is in signature of this method
+
+ MethodDeclaration declaration= (MethodDeclaration) declaringNode;
+
+ switch (problem.getProblemId()) {
+ case IProblem.ParameterLackingNonNullAnnotation:
+ case IProblem.ParameterLackingNullableAnnotation:
+ case IProblem.IllegalDefinitionToNonNullParameter:
+ case IProblem.IllegalRedefinitionToNonNullParameter:
+ case IProblem.NonNullLocalVariableComparisonYieldsFalse:
+ case IProblem.RedundantNullCheckOnNonNullLocalVariable:
+ // statements suggest changing parameters:
+ if (declaration.getNodeType() == ASTNode.METHOD_DECLARATION) {
+ String paramName = findAffectedParameterName(selectedNode);
+ if (paramName != null) {
+ message = Messages.format(NullFixMessages.QuickFixes_declare_method_parameter_nullness, annotationNameLabel);
+ result = new ParameterAnnotationRewriteOperation(compilationUnit,
+ declaration,
+ annotationToAdd,
+ annotationToRemove,
+ paramName,
+ allowRemove,
+ message);
+ }
+ }
+ break;
+ case IProblem.IllegalReturnNullityRedefinition:
+ case IProblem.RequiredNonNullButProvidedNull:
+ case IProblem.RequiredNonNullButProvidedPotentialNull:
+ case IProblem.RequiredNonNullButProvidedUnknown:
+ message = Messages.format(NullFixMessages.QuickFixes_declare_method_return_nullness, annotationNameLabel);
+ result = new ReturnAnnotationRewriteOperation(compilationUnit,
+ declaration,
+ annotationToAdd,
+ annotationToRemove,
+ allowRemove,
+ message);
+ break;
+ }
+
+ }
+ return result;
+ }
+ static SignatureAnnotationRewriteOperation createAddAnnotationToOverriddenOperation(CompilationUnit compilationUnit,
+ IProblemLocation problem,
+ String annotationToAdd,
+ String annotationToRemove,
+ Set<String> handledPositions,
+ boolean thisUnitOnly,
+ boolean allowRemove)
+ {
+ ICompilationUnit cu = (ICompilationUnit) compilationUnit.getJavaElement();
+ if (!JavaModelUtil.is50OrHigher(cu.getJavaProject()))
+ return null;
+
+ ASTNode selectedNode = problem.getCoveringNode(compilationUnit);
+ if (selectedNode == null)
+ return null;
+
+ ASTNode declaringNode = getDeclaringNode(selectedNode);
+
+ switch (problem.getProblemId()) {
+ case IProblem.IllegalDefinitionToNonNullParameter:
+ case IProblem.IllegalRedefinitionToNonNullParameter:
+ break;
+ case IProblem.IllegalReturnNullityRedefinition:
+ if (declaringNode == null)
+ declaringNode = selectedNode;
+ break;
+ default:
+ return null;
+ }
+
+ String annotationNameLabel = annotationToAdd;
+ int lastDot = annotationToAdd.lastIndexOf('.');
+ if (lastDot != -1)
+ annotationNameLabel = annotationToAdd.substring(lastDot + 1);
+ annotationNameLabel = BasicElementLabels.getJavaElementName(annotationNameLabel);
+
+ if (declaringNode instanceof MethodDeclaration) {
+
+ // complaint is in signature of this method
+
+ MethodDeclaration declaration = (MethodDeclaration) declaringNode;
+
+ switch (problem.getProblemId()) {
+ case IProblem.IllegalDefinitionToNonNullParameter:
+ case IProblem.IllegalRedefinitionToNonNullParameter:
+ return createChangeOverriddenParameterOperation(compilationUnit, cu, declaration, selectedNode,
+ allowRemove, annotationToAdd, annotationToRemove, annotationNameLabel);
+ case IProblem.IllegalReturnNullityRedefinition:
+ if (hasNullAnnotation(declaration)) { // don't adjust super if local has no explicit annotation (?)
+ return createChangeOverriddenReturnOperation(compilationUnit, cu, declaration, allowRemove,
+ annotationToAdd, annotationToRemove, annotationNameLabel);
+ }
+ }
+
+ }
+ return null;
+ }
+
+ static SignatureAnnotationRewriteOperation createChangeOverriddenParameterOperation(CompilationUnit compilationUnit,
+ ICompilationUnit cu,
+ MethodDeclaration declaration,
+ ASTNode selectedNode,
+ boolean allowRemove,
+ String annotationToAdd,
+ String annotationToRemove,
+ String annotationNameLabel)
+ {
+ SignatureAnnotationRewriteOperation result;
+ String message;
+ IMethodBinding methodDeclBinding= declaration.resolveBinding();
+ if (methodDeclBinding == null)
+ return null;
+
+ IMethodBinding overridden= Bindings.findOverriddenMethod(methodDeclBinding, false);
+ if (overridden == null)
+ return null;
+ compilationUnit = findCUForMethod(compilationUnit, cu, overridden);
+ if (compilationUnit == null)
+ return null;
+ ASTNode methodDecl = compilationUnit.findDeclaringNode(overridden.getKey());
+ if (methodDecl == null)
+ return null;
+ declaration = (MethodDeclaration) methodDecl;
+ message = Messages.format(NullFixMessages.QuickFixes_declare_overridden_parameter_as_nonnull,
+ new String[] {
+ annotationNameLabel,
+ BasicElementLabels.getJavaElementName(overridden.getDeclaringClass().getName())
+ });
+ String paramName = findAffectedParameterName(selectedNode);
+ result = new ParameterAnnotationRewriteOperation(compilationUnit,
+ declaration,
+ annotationToAdd,
+ annotationToRemove,
+ paramName,
+ allowRemove,
+ message);
+ return result;
+ }
+
+ static String findAffectedParameterName(ASTNode selectedNode) {
+ VariableDeclaration argDecl = selectedNode instanceof VariableDeclaration
+ ? (VariableDeclaration) selectedNode
+ : (VariableDeclaration) ASTNodes.getParent(selectedNode, VariableDeclaration.class);
+ if (argDecl != null)
+ return argDecl.getName().getIdentifier();
+ if (selectedNode.getNodeType() == ASTNode.SIMPLE_NAME) {
+ IBinding binding = ((SimpleName)selectedNode).resolveBinding();
+ if (binding.getKind() == IBinding.VARIABLE && ((IVariableBinding)binding).isParameter())
+ return ((SimpleName)selectedNode).getIdentifier();
+ }
+ return null;
+ }
+
+ static boolean hasNullAnnotation(MethodDeclaration decl) {
+ List<IExtendedModifier> modifiers = decl.modifiers();
+ String nonnull = NullQuickFixes.getNonNullAnnotationName(decl.resolveBinding().getJavaElement(), false);
+ String nullable = NullQuickFixes.getNullableAnnotationName(decl.resolveBinding().getJavaElement(), false);
+ for (Object mod : modifiers) {
+ if (mod instanceof Annotation) {
+ Name annotationName = ((Annotation) mod).getTypeName();
+ String fullyQualifiedName = annotationName.getFullyQualifiedName();
+ if (annotationName.isSimpleName()
+ ? nonnull.endsWith(fullyQualifiedName)
+ : fullyQualifiedName.equals(nonnull))
+ return true;
+ if (annotationName.isSimpleName()
+ ? nullable.endsWith(fullyQualifiedName)
+ : fullyQualifiedName.equals(nullable))
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static SignatureAnnotationRewriteOperation createChangeOverriddenReturnOperation(CompilationUnit compilationUnit,
+ ICompilationUnit cu,
+ MethodDeclaration declaration,
+ boolean allowRemove,
+ String annotationToAdd,
+ String annotationToRemove,
+ String annotationNameLabel)
+ {
+ SignatureAnnotationRewriteOperation result;
+ String message;
+ IMethodBinding methodDeclBinding= declaration.resolveBinding();
+ if (methodDeclBinding == null)
+ return null;
+
+ IMethodBinding overridden= Bindings.findOverriddenMethod(methodDeclBinding, false);
+ if (overridden == null)
+ return null;
+ compilationUnit = findCUForMethod(compilationUnit, cu, overridden);
+ if (compilationUnit == null)
+ return null;
+ ASTNode methodDecl = compilationUnit.findDeclaringNode(overridden.getKey());
+ if (methodDecl == null)
+ return null;
+ declaration = (MethodDeclaration) methodDecl;
+// TODO(SH): decide whether we want to propose overwriting existing annotations in super
+// if (hasNullAnnotation(declaration)) // if overridden has explicit declaration don't propose to change it
+// return null;
+ message = Messages.format(NullFixMessages.QuickFixes_declare_overridden_return_as_nullable,
+ new String[] {
+ annotationNameLabel,
+ BasicElementLabels.getJavaElementName(overridden.getDeclaringClass().getName())
+ });
+ result = new ReturnAnnotationRewriteOperation(compilationUnit,
+ declaration,
+ annotationToAdd,
+ annotationToRemove,
+ allowRemove,
+ message);
+ return result;
+ }
+
+ static CompilationUnit findCUForMethod(CompilationUnit compilationUnit, ICompilationUnit cu, IMethodBinding methodBinding)
+ {
+ ASTNode methodDecl= compilationUnit.findDeclaringNode(methodBinding.getMethodDeclaration());
+ if (methodDecl == null) {
+ // is methodDecl defined in another CU?
+ ITypeBinding declaringTypeDecl= methodBinding.getDeclaringClass().getTypeDeclaration();
+ if (declaringTypeDecl.isFromSource()) {
+ ICompilationUnit targetCU = null;
+ try {
+ targetCU = ASTResolving.findCompilationUnitForBinding(cu, compilationUnit, declaringTypeDecl);
+ } catch (JavaModelException e) { /* can't do better */ }
+ if (targetCU != null) {
+ return ASTResolving.createQuickFixAST(targetCU, null);
+ }
+ }
+ return null;
+ }
+ return compilationUnit;
+ }
+
+ /** The relevant declaring node of a return statement is the enclosing method. */
+ static ASTNode getDeclaringNode(ASTNode selectedNode) {
+ return ASTNodes.getParent(selectedNode, ASTNode.METHOD_DECLARATION);
+ }
+}
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickFixProcessor.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickFixProcessor.java
index 4e798af..635ea8f 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickFixProcessor.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/text/correction/QuickFixProcessor.java
@@ -31,6 +31,7 @@ import org.eclipse.jdt.ui.text.java.IProblemLocation;
import org.eclipse.jdt.ui.text.java.IQuickFixProcessor;
import org.eclipse.jdt.ui.text.java.correction.ICommandAccess;
+import org.eclipse.jdt.internal.ui.fix.NullQuickFixes;
import org.eclipse.jdt.internal.ui.text.correction.proposals.ReplaceCorrectionProposal;
import org.eclipse.jdt.internal.ui.text.correction.proposals.TaskMarkerProposal;
@@ -235,6 +236,16 @@ public class QuickFixProcessor implements IQuickFixProcessor {
case IProblem.UnsafeGenericArrayForVarargs:
case IProblem.SafeVarargsOnFixedArityMethod :
case IProblem.SafeVarargsOnNonFinalInstanceMethod:
+ case IProblem.RequiredNonNullButProvidedNull:
+ case IProblem.RequiredNonNullButProvidedPotentialNull:
+ case IProblem.RequiredNonNullButProvidedUnknown:
+ case IProblem.IllegalReturnNullityRedefinition:
+ case IProblem.IllegalRedefinitionToNonNullParameter:
+ case IProblem.IllegalDefinitionToNonNullParameter:
+ case IProblem.ParameterLackingNonNullAnnotation:
+ case IProblem.ParameterLackingNullableAnnotation:
+ case IProblem.NonNullLocalVariableComparisonYieldsFalse:
+ case IProblem.RedundantNullCheckOnNonNullLocalVariable:
return true;
default:
return SuppressWarningsSubProcessor.hasSuppressWarningsProposal(cu.getJavaProject(), problemId);
@@ -663,6 +674,21 @@ public class QuickFixProcessor implements IQuickFixProcessor {
case IProblem.SafeVarargsOnNonFinalInstanceMethod:
VarargsWarningsSubProcessor.addRemoveSafeVarargsProposals(context, problem, proposals);
break;
+ case IProblem.IllegalReturnNullityRedefinition:
+ case IProblem.IllegalDefinitionToNonNullParameter:
+ case IProblem.IllegalRedefinitionToNonNullParameter:
+ NullQuickFixes.addNullAnnotationInSignatureProposal(context, problem, proposals, false);
+ NullQuickFixes.addNullAnnotationInSignatureProposal(context, problem, proposals, true);
+ break;
+ case IProblem.RequiredNonNullButProvidedNull:
+ case IProblem.RequiredNonNullButProvidedPotentialNull:
+ case IProblem.RequiredNonNullButProvidedUnknown:
+ case IProblem.ParameterLackingNonNullAnnotation:
+ case IProblem.ParameterLackingNullableAnnotation:
+ case IProblem.NonNullLocalVariableComparisonYieldsFalse:
+ case IProblem.RedundantNullCheckOnNonNullLocalVariable:
+ NullQuickFixes.addReturnAndArgumentTypeProposal(context, problem, proposals);
+ break;
default:
}
if (JavaModelUtil.is50OrHigher(context.getCompilationUnit().getJavaProject())) {