New quickfixes for adjusting annotations of overridden methods
Refactor to better accommodate the growing amount of code
diff --git a/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/FixMessages.java b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/FixMessages.java
index f055c61..a110b52 100644
--- a/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/FixMessages.java
+++ b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/FixMessages.java
@@ -24,6 +24,12 @@
public static String QuickFixes_declare_method_return_nullable;
+
+ 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, FixMessages.class);
diff --git a/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/FixMessages.properties b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/FixMessages.properties
index 985ec90..1493f08 100644
--- a/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/FixMessages.properties
+++ b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/FixMessages.properties
@@ -2,3 +2,5 @@
QuickFixes_add_annotation_change_name=Add Annotations
QuickFixes_declare_method_parameter_nullable=Declare method parameter as @{0}
QuickFixes_declare_method_return_nullable=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/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/NullAnnotationsCleanUp.java b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/NullAnnotationsCleanUp.java
index ddb34ce..e20c632 100644
--- a/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/NullAnnotationsCleanUp.java
+++ b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/NullAnnotationsCleanUp.java
@@ -144,7 +144,7 @@
public boolean canFix(ICompilationUnit compilationUnit, IProblemLocation problem) {
int id= problem.getProblemId();
- if (QuickFixes.isMissingNullableAnnotationProblem(id)) {
+ if (QuickFixes.isMissingNullAnnotationProblem(id)) {
if ( isEnabled(CleanUpConstants.ADD_MISSING_ANNOTATIONS)
&& ( ((id == DefiniteNullFromNonNullMethod) && isEnabled(CleanUpConstants.ADD_DEFINITELY_MISSING_RETURN_ANNOTATION_NULLABLE))
|| ((id == PotentialNullFromNonNullMethod) && isEnabled(CleanUpConstants.ADD_POTENTIALLY_MISSING_RETURN_ANNOTATION_NULLABLE))
@@ -178,7 +178,7 @@
if ( (addDefinitelyMissingReturnNullable && id == DefiniteNullFromNonNullMethod)
|| (addPotentiallyMissingReturnNullable && id == PotentialNullFromNonNullMethod)
|| (addDefinitelyMissingParamNullable && QuickFixes.mayIndicateParameterNullcheck(id)))
- if (!QuickFixes.hasExplicitNullnessAnnotation((ICompilationUnit) compilationUnit.getJavaElement(), problems[i].getSourceStart()))
+ if (!QuickFixes.hasExplicitNullAnnotation((ICompilationUnit) compilationUnit.getJavaElement(), problems[i].getSourceStart()))
result++;
}
return result;
diff --git a/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/QuickFixes.java b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/QuickFixes.java
index d6e21a3..af11492 100644
--- a/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/QuickFixes.java
+++ b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/QuickFixes.java
@@ -29,20 +29,13 @@
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.IMethodBinding;
-import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.IVariableBinding;
-import org.eclipse.jdt.core.dom.MethodDeclaration;
-import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.SimpleName;
-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.fix.IProposableFix;
import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
-import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.internal.ui.JavaPluginImages;
-import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
import org.eclipse.jdt.internal.ui.text.correction.proposals.FixCorrectionProposal;
import org.eclipse.jdt.ui.cleanup.CleanUpOptions;
@@ -74,6 +67,7 @@
case PotentialNullFromNonNullMethod:
case DefiniteNullToNonNullParameter:
case PotentialNullToNonNullParameter:
+ case IllegalRedefinitionToNullableReturn:
case IProblem.NonNullLocalVariableComparisonYieldsFalse:
case IProblem.RedundantNullCheckOnNonNullLocalVariable:
return true;
@@ -97,33 +91,46 @@
case PotentialNullFromNonNullMethod:
case DefiniteNullToNonNullParameter:
case PotentialNullToNonNullParameter:
- addNullableAnnotationInSignatureProposal(context, problem, proposals);
+ case IllegalRedefinitionToNullableReturn:
+ case IllegalDefinitionToNonNullParameter:
+ case IllegalRedefinitionToNonNullParameter:
+ addNullAnnotationInSignatureProposal(context, problem, proposals);
break;
case IProblem.NonNullLocalVariableComparisonYieldsFalse:
case IProblem.RedundantNullCheckOnNonNullLocalVariable:
if (isComplainingAboutArgument(context, problem))
- addNullableAnnotationInSignatureProposal(context, problem, proposals);
+ addNullAnnotationInSignatureProposal(context, problem, proposals);
break;
}
}
}
@SuppressWarnings("unchecked")
- void addNullableAnnotationInSignatureProposal(IInvocationContext context, IProblemLocation problem, @SuppressWarnings("rawtypes") Collection proposals) {
- IProposableFix fix= createNullableInSignatureFix(context.getASTRoot(), problem);
+ void addNullAnnotationInSignatureProposal(IInvocationContext context, IProblemLocation problem, @SuppressWarnings("rawtypes") Collection proposals)
+ {
+ IProposableFix fix= createNullAnnotationInSignatureFix(context.getASTRoot(), problem);
if (fix != null) {
Image image= JavaPluginImages.get(JavaPluginImages.IMG_CORRECTION_CHANGE);
Map<String, String> options= new Hashtable<String, String>();
options.put(CleanUpConstants.ADD_MISSING_ANNOTATIONS, CleanUpOptions.TRUE);
- if (problem.getProblemId() == DefiniteNullFromNonNullMethod)
+ switch (problem.getProblemId()) {
+ case DefiniteNullFromNonNullMethod:
+ case IllegalRedefinitionToNullableReturn:
options.put(CleanUpConstants.ADD_DEFINITELY_MISSING_RETURN_ANNOTATION_NULLABLE, CleanUpOptions.TRUE);
- if (problem.getProblemId() == PotentialNullFromNonNullMethod)
+ break;
+ case PotentialNullFromNonNullMethod:
options.put(CleanUpConstants.ADD_POTENTIALLY_MISSING_RETURN_ANNOTATION_NULLABLE, CleanUpOptions.TRUE);
- if (mayIndicateParameterNullcheck(problem.getProblemId()))
+ break;
+ case IProblem.NonNullLocalVariableComparisonYieldsFalse:
+ case IProblem.RedundantNullCheckOnNonNullLocalVariable:
+ // may indicate a parameter null-check
+ case DefiniteNullToNonNullParameter:
+ case IllegalDefinitionToNonNullParameter:
+ case IllegalRedefinitionToNonNullParameter:
options.put(CleanUpConstants.ADD_DEFINITELY_MISSING_PARAMETER_ANNOTATION_NULLABLE, CleanUpOptions.TRUE);
- if (problem.getProblemId() == DefiniteNullToNonNullParameter)
- options.put(CleanUpConstants.ADD_DEFINITELY_MISSING_PARAMETER_ANNOTATION_NULLABLE, CleanUpOptions.TRUE);
+ break;
+ }
FixCorrectionProposal proposal= new FixCorrectionProposal(fix, new NullAnnotationsCleanUp(options, this), 15, image, context);
proposals.add(proposal);
}
@@ -144,40 +151,39 @@
return false;
}
- CompilationUnitRewriteOperationsFix createNullableInSignatureFix(CompilationUnit compilationUnit, IProblemLocation problem) {
+ CompilationUnitRewriteOperationsFix createNullAnnotationInSignatureFix(CompilationUnit compilationUnit, IProblemLocation problem)
+ {
String nullableAnnotationName = getNullableAnnotationName(compilationUnit.getJavaElement(), false);
String nonNullAnnotationName = getNonNullAnnotationName(compilationUnit.getJavaElement(), false);
- RewriteOperations.SignatureAnnotationRewriteOperation operation = createAddNullableOperation(
- compilationUnit, problem, nullableAnnotationName, nonNullAnnotationName, null, false, true);
+ String annotationToAdd = nullableAnnotationName;
+ String annotationToRemove = nonNullAnnotationName;
+
+ switch (problem.getProblemId()) {
+ case IllegalDefinitionToNonNullParameter:
+ case IllegalRedefinitionToNonNullParameter:
+ annotationToAdd = nonNullAnnotationName;
+ annotationToRemove = nullableAnnotationName;
+ break;
+ // all others propose to add @Nullable
+ }
+
+ RewriteOperations.SignatureAnnotationRewriteOperation operation =
+ RewriteOperations.createAddAnnotationOperation(
+ compilationUnit, problem, annotationToAdd, annotationToRemove, null, false/*thisUnitOnly*/, true/*allowRemove*/);
if (operation == null)
return null;
- int lastDot = nullableAnnotationName.lastIndexOf('.');
- if (lastDot != -1)
- nullableAnnotationName = nullableAnnotationName.substring(lastDot+1);
- String messageTemplate = null;
- switch (problem.getProblemId()) {
- case DefiniteNullFromNonNullMethod:
- case PotentialNullFromNonNullMethod:
- messageTemplate = FixMessages.QuickFixes_declare_method_return_nullable;
- break;
- case DefiniteNullToNonNullParameter:
- case PotentialNullToNonNullParameter:
- case IProblem.NonNullLocalVariableComparisonYieldsFalse:
- case IProblem.RedundantNullCheckOnNonNullLocalVariable:
- messageTemplate = FixMessages.QuickFixes_declare_method_parameter_nullable;
- break;
- }
- return new CompilationUnitRewriteOperationsFix(Messages.format(messageTemplate, nullableAnnotationName),
- operation.getCompilationUnit(),
- new CompilationUnitRewriteOperation[] {operation});
+ return new CompilationUnitRewriteOperationsFix(operation.getMessage(),
+ operation.getCompilationUnit(),
+ new CompilationUnitRewriteOperation[] {operation});
}
- ICleanUpFix createCleanUp(CompilationUnit compilationUnit,
- boolean addDefinitelyMissingReturnAnnotations,
- boolean addPotentiallyMissingReturnAnnotations,
- boolean addDefinitelyMissingParamAnnotations,
- IProblemLocation[] locations)
+ // Entry for NullAnnotationsCleanup:
+ public ICleanUpFix createCleanUp(CompilationUnit compilationUnit,
+ boolean addDefinitelyMissingReturnAnnotations,
+ boolean addPotentiallyMissingReturnAnnotations,
+ boolean addDefinitelyMissingParamAnnotations,
+ IProblemLocation[] locations)
{
ICompilationUnit cu= (ICompilationUnit)compilationUnit.getJavaElement();
@@ -200,7 +206,7 @@
}
}
- createAddNullableAnnotationOperations(compilationUnit, locations, operations);
+ createAddNullAnnotationOperations(compilationUnit, locations, operations);
if (operations.size() == 0)
return null;
@@ -210,115 +216,40 @@
}
@SuppressWarnings({ "rawtypes", "unchecked" })
- void createAddNullableAnnotationOperations(CompilationUnit compilationUnit, IProblemLocation[] locations, List result) {
+ void createAddNullAnnotationOperations(CompilationUnit compilationUnit, IProblemLocation[] locations, List 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()
- CompilationUnitRewriteOperation fix = createAddNullableOperation(
- compilationUnit, problem, nullableAnnotationName, nonNullAnnotationName, handledPositions, true, false);
+ String annotationToAdd = nullableAnnotationName;
+ String annotationToRemove = nonNullAnnotationName;
+ switch (problem.getProblemId()) {
+ case IllegalDefinitionToNonNullParameter:
+ case IllegalRedefinitionToNonNullParameter:
+ annotationToAdd = nonNullAnnotationName;
+ annotationToRemove = nullableAnnotationName;
+ }
+ CompilationUnitRewriteOperation fix = RewriteOperations.createAddAnnotationOperation(
+ compilationUnit, problem, annotationToAdd, annotationToRemove, handledPositions, true, false);
if (fix != null)
result.add(fix);
}
}
- RewriteOperations.SignatureAnnotationRewriteOperation createAddNullableOperation(CompilationUnit compilationUnit,
- IProblemLocation problem, String nullableAnnotationName, String nonNullAnnotationName, Set<String> handledPositions,
- boolean thisUnitOnly, boolean allowRemove)
- {
- ICompilationUnit cu= (ICompilationUnit)compilationUnit.getJavaElement();
- if (!JavaModelUtil.is50OrHigher(cu.getJavaProject()))
- return null;
-
- if (!isMissingNullableAnnotationProblem(problem.getProblemId())) // TODO is this obsolete?
- return null;
-
- if (hasExplicitNullnessAnnotation(cu, problem.getOffset()))
- return null;
-
- ASTNode selectedNode= problem.getCoveringNode(compilationUnit);
- if (selectedNode == null)
- return null;
-
- RewriteOperations.SignatureAnnotationRewriteOperation result = null;
- ASTNode declaringNode= getDeclaringNode(selectedNode);
- if (selectedNode.getParent() instanceof MethodInvocation) {
- // check problem ID!
- MethodInvocation methodInvocation = (MethodInvocation)selectedNode.getParent();
- int paramIdx = methodInvocation.arguments().indexOf(selectedNode);
- IMethodBinding methodBinding = methodInvocation.resolveMethodBinding();
- 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) {
- compilationUnit = ASTResolving.createQuickFixAST(targetCU, null);
- methodDecl= compilationUnit.findDeclaringNode(methodBinding.getKey());
- }
- }
- }
- if (methodDecl != null)
- result = new RewriteOperations.ParameterAnnotationRewriteOperation(compilationUnit,
- (MethodDeclaration) methodDecl,
- nullableAnnotationName,
- nonNullAnnotationName,
- paramIdx,
- allowRemove);
- } else if (declaringNode instanceof MethodDeclaration) {
-
- MethodDeclaration declaration= (MethodDeclaration) declaringNode;
-
- if (mayIndicateParameterNullcheck(problem.getProblemId())) {
- if (selectedNode.getNodeType() == ASTNode.SIMPLE_NAME && declaration.getNodeType() == ASTNode.METHOD_DECLARATION) {
- IBinding binding = ((SimpleName)selectedNode).resolveBinding();
- if (binding.getKind() == IBinding.VARIABLE && ((IVariableBinding)binding).isParameter())
- result = new RewriteOperations.ParameterAnnotationRewriteOperation(compilationUnit,
- declaration,
- nullableAnnotationName,
- nonNullAnnotationName,
- ((SimpleName) selectedNode).getIdentifier(),
- allowRemove);
- }
- } else {
- result = new RewriteOperations.ReturnAnnotationRewriteOperation(compilationUnit,
- declaration,
- nullableAnnotationName,
- nonNullAnnotationName,
- allowRemove);
- }
-
- }
- if (handledPositions != null && result != null) {
- if (handledPositions.contains(result.getKey()))
- return null;
- handledPositions.add(result.getKey());
- }
- return result;
- }
-
- /** The relevant declaring node of a return statement is the enclosing method. */
- ASTNode getDeclaringNode(ASTNode selectedNode) {
- return ASTNodes.getParent(selectedNode, ASTNode.METHOD_DECLARATION);
- }
-
- static boolean isMissingNullableAnnotationProblem(int id) {
+ public static boolean isMissingNullAnnotationProblem(int id) {
return id == DefiniteNullFromNonNullMethod || id == PotentialNullFromNonNullMethod
|| id == DefiniteNullToNonNullParameter || id == PotentialNullToNonNullParameter
+ || id == IllegalRedefinitionToNullableReturn
|| mayIndicateParameterNullcheck(id);
}
- static boolean mayIndicateParameterNullcheck(int problemId) {
+ public static boolean mayIndicateParameterNullcheck(int problemId) {
return problemId == IProblem.NonNullLocalVariableComparisonYieldsFalse || problemId == IProblem.RedundantNullCheckOnNonNullLocalVariable;
}
- static boolean hasExplicitNullnessAnnotation(ICompilationUnit compilationUnit, int offset) {
+ public static boolean hasExplicitNullAnnotation(ICompilationUnit compilationUnit, int offset) {
try {
IJavaElement problemElement = compilationUnit.getElementAt(offset);
if (problemElement.getElementType() == IJavaElement.METHOD) {
@@ -337,7 +268,7 @@
return false;
}
- static String getNullableAnnotationName(IJavaElement javaElement, boolean makeSimple) {
+ public static String getNullableAnnotationName(IJavaElement javaElement, boolean makeSimple) {
String qualifiedName = javaElement.getJavaProject().getOption(NullCompilerOptions.OPTION_NullableAnnotationName, true);
int lastDot;
if (makeSimple && qualifiedName != null && (lastDot = qualifiedName.lastIndexOf('.')) != -1)
@@ -345,7 +276,7 @@
return qualifiedName;
}
- static String getNonNullAnnotationName(IJavaElement javaElement, boolean makeSimple) {
+ public static String getNonNullAnnotationName(IJavaElement javaElement, boolean makeSimple) {
String qualifiedName = javaElement.getJavaProject().getOption(NullCompilerOptions.OPTION_NonNullAnnotationName, true);
int lastDot;
if (makeSimple && qualifiedName != null && (lastDot = qualifiedName.lastIndexOf('.')) != -1)
diff --git a/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/RewriteOperations.java b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/RewriteOperations.java
index 01b20e2..6f6e7fe 100644
--- a/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/RewriteOperations.java
+++ b/plugins/org.eclipse.objectteams.jdt.nullity/src/org/eclipse/objectteams/internal/jdt/nullity/quickfix/RewriteOperations.java
@@ -10,23 +10,41 @@
*******************************************************************************/
package org.eclipse.objectteams.internal.jdt.nullity.quickfix;
+import static org.eclipse.objectteams.internal.jdt.nullity.IConstants.IProblem.*;
+
import java.util.List;
+import java.util.Set;
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.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.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.SimpleName;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
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.internal.ui.text.correction.ASTResolving;
import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
+import org.eclipse.jdt.ui.text.java.IProblemLocation;
import org.eclipse.text.edits.TextEditGroup;
@SuppressWarnings("restriction")
@@ -39,6 +57,7 @@
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; }
@@ -76,6 +95,10 @@
}
return true;
}
+
+ public String getMessage() {
+ return fMessage;
+ }
}
/**
@@ -83,17 +106,17 @@
*
* Crafted after the lead of Java50Fix.AnnotationRewriteOperation
* @author stephan
- *
*/
static class ReturnAnnotationRewriteOperation extends SignatureAnnotationRewriteOperation {
private final BodyDeclaration fBodyDeclaration;
- public ReturnAnnotationRewriteOperation(CompilationUnit unit,
- MethodDeclaration method,
- String annotationToAdd,
- String annotationToRemove,
- boolean allowRemove)
+ ReturnAnnotationRewriteOperation(CompilationUnit unit,
+ MethodDeclaration method,
+ String annotationToAdd,
+ String annotationToRemove,
+ boolean allowRemove,
+ String message)
{
fUnit = unit;
fKey= method.resolveBinding().getKey()+"<return>"; //$NON-NLS-1$
@@ -101,13 +124,13 @@
fAnnotationToAdd= annotationToAdd;
fAnnotationToRemove= annotationToRemove;
fAllowRemove= allowRemove;
+ fMessage = message;
}
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(Messages.format(FixMessages.QuickFixes_declare_method_return_nullable,
- BasicElementLabels.getJavaElementName(fAnnotationToAdd)), cuRewrite);
+ TextEditGroup group= createTextEditGroup(fMessage, cuRewrite);
if (!checkExisting(fBodyDeclaration.modifiers(), listRewrite, group))
return;
Annotation newAnnotation= ast.newMarkerAnnotation();
@@ -122,18 +145,20 @@
private SingleVariableDeclaration fArgument;
- public ParameterAnnotationRewriteOperation(CompilationUnit unit,
- MethodDeclaration method,
- String annotationToAdd,
- String annotationToRemove,
- String paramName,
- boolean allowRemove)
+ 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)) {
@@ -146,12 +171,13 @@
throw new RuntimeException("Argument "+paramName+" not found in method "+method.getName().getIdentifier()); //$NON-NLS-1$ //$NON-NLS-2$
}
- public ParameterAnnotationRewriteOperation(CompilationUnit unit,
- MethodDeclaration method,
- String annotationToAdd,
- String annotationToRemove,
- int paramIdx,
- boolean allowRemove)
+ ParameterAnnotationRewriteOperation(CompilationUnit unit,
+ MethodDeclaration method,
+ String annotationToAdd,
+ String annotationToRemove,
+ int paramIdx,
+ boolean allowRemove,
+ String message)
{
fUnit= unit;
fKey= method.resolveBinding().getKey();
@@ -160,13 +186,13 @@
fAllowRemove= allowRemove;
fArgument = (SingleVariableDeclaration) method.parameters().get(paramIdx);
fKey += fArgument.getName().getIdentifier();
+ fMessage = message;
}
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(Messages.format(FixMessages.QuickFixes_declare_method_parameter_nullable,
- BasicElementLabels.getJavaElementName(fAnnotationToAdd)), cuRewrite);
+ TextEditGroup group= createTextEditGroup(fMessage, cuRewrite);
if (!checkExisting(fArgument.modifiers(), listRewrite, group))
return;
Annotation newAnnotation= ast.newMarkerAnnotation();
@@ -176,4 +202,220 @@
listRewrite.insertLast(newAnnotation, group); // null annotation is last modifier, directly preceding the return type
}
}
+
+ // Entry for QuickFixes:
+ public 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;
+
+ switch (problem.getProblemId()) {
+ case DefiniteNullToNonNullParameter:
+ case PotentialNullToNonNullParameter:
+ case IllegalRedefinitionToNullableReturn:
+ case IllegalDefinitionToNonNullParameter:
+ case IllegalRedefinitionToNonNullParameter:
+ // these affect another method
+ break;
+ default:
+ // if this method has annotations, don't change'em
+ if (QuickFixes.hasExplicitNullAnnotation(cu, problem.getOffset()))
+ return null;
+ }
+
+ ASTNode selectedNode= problem.getCoveringNode(compilationUnit);
+ if (selectedNode == null)
+ return null;
+
+ SignatureAnnotationRewriteOperation result = null;
+ ASTNode declaringNode= getDeclaringNode(selectedNode);
+ 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;
+ ASTNode methodDecl = compilationUnit.findDeclaringNode(methodBinding.getKey());
+ if (methodDecl == null)
+ return null;
+ message = Messages.format(FixMessages.QuickFixes_declare_method_parameter_nullable, 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.NonNullLocalVariableComparisonYieldsFalse:
+ case IProblem.RedundantNullCheckOnNonNullLocalVariable:
+ // statements suggest changing parameters:
+ if (selectedNode.getNodeType() == ASTNode.SIMPLE_NAME && declaration.getNodeType() == ASTNode.METHOD_DECLARATION) {
+ IBinding binding = ((SimpleName)selectedNode).resolveBinding();
+ if (binding.getKind() == IBinding.VARIABLE && ((IVariableBinding)binding).isParameter()) {
+ message = Messages.format(FixMessages.QuickFixes_declare_method_parameter_nullable, annotationNameLabel);
+ result = new ParameterAnnotationRewriteOperation(compilationUnit,
+ declaration,
+ annotationToAdd,
+ annotationToRemove,
+ ((SimpleName) selectedNode).getIdentifier(),
+ allowRemove,
+ message);
+ }
+ }
+ break;
+ case IllegalDefinitionToNonNullParameter:
+ case IllegalRedefinitionToNonNullParameter:
+ result = createChangeOverriddenParameterOperation(compilationUnit, cu, declaration, selectedNode, allowRemove,
+ annotationToAdd, annotationToRemove, annotationNameLabel);
+ break;
+ case IllegalRedefinitionToNullableReturn:
+ result = createChangeOverriddenReturnOperation(compilationUnit, cu, declaration, allowRemove,
+ annotationToAdd, annotationToRemove, annotationNameLabel);
+ break;
+ case DefiniteNullFromNonNullMethod:
+ case PotentialNullFromNonNullMethod:
+ message = Messages.format(FixMessages.QuickFixes_declare_method_parameter_nullable, annotationNameLabel);
+ result = new ReturnAnnotationRewriteOperation(compilationUnit,
+ declaration,
+ annotationToAdd,
+ annotationToRemove,
+ allowRemove,
+ message);
+ break;
+ }
+
+ }
+ if (handledPositions != null && result != null) {
+ if (handledPositions.contains(result.getKey()))
+ return null;
+ handledPositions.add(result.getKey());
+ }
+ return result;
+ }
+
+ 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(FixMessages.QuickFixes_declare_overridden_parameter_as_nonnull,
+ new String[] {
+ annotationNameLabel,
+ BasicElementLabels.getJavaElementName(overridden.getDeclaringClass().getName())
+ });
+ result = new ParameterAnnotationRewriteOperation(compilationUnit,
+ declaration,
+ annotationToAdd,
+ annotationToRemove,
+ ((SimpleName) selectedNode).getIdentifier(),
+ allowRemove,
+ message);
+ return result;
+ }
+
+ 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;
+ message = Messages.format(FixMessages.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);
+ }
}