diff options
Diffstat (limited to 'org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java')
-rw-r--r-- | org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java | 137 |
1 files changed, 103 insertions, 34 deletions
diff --git a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java index adb1fe7b63..f0074bf92a 100644 --- a/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java +++ b/org.eclipse.jdt.ui/core extension/org/eclipse/jdt/internal/corext/fix/NullAnnotationsRewriteOperations.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2011, 2012 GK Software AG and others. + * Copyright (c) 2011, 2013 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 @@ -25,11 +25,11 @@ 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.IAnnotationBinding; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IExtendedModifier; +import org.eclipse.jdt.core.dom.IMemberValuePairBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; @@ -58,10 +58,19 @@ import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels; public class NullAnnotationsRewriteOperations { + public enum ChangeKind { + LOCAL, // do the normal thing locally in the current method + INVERSE, // insert the inverse annotation in the local method + OVERRIDDEN, // change the overridden method + TARGET // change the target method of a method call + } + static abstract class SignatureAnnotationRewriteOperation extends CompilationUnitRewriteOperation { String fAnnotationToAdd; String fAnnotationToRemove; boolean fAllowRemove; + boolean fRemoveIfNonNullByDefault; + String fNonNullByDefaultName; CompilationUnit fUnit; protected String fKey; protected String fMessage; @@ -97,6 +106,37 @@ public class NullAnnotationsRewriteOperations { return true; } + /* Is the given element affected by a @NonNullByDefault. */ + boolean hasNonNullDefault(IBinding enclosingElement) { + if (!fRemoveIfNonNullByDefault) return false; + IAnnotationBinding[] annotations = enclosingElement.getAnnotations(); + for (int i= 0; i < annotations.length; i++) { + IAnnotationBinding annot = annotations[i]; + if (annot.getAnnotationType().getQualifiedName().equals(fNonNullByDefaultName)) { + IMemberValuePairBinding[] pairs= annot.getDeclaredMemberValuePairs(); + if (pairs.length > 0) { + // is default cancelled by "false" or "value=false" ? + for (int j= 0; j < pairs.length; j++) + if (pairs[j].getKey() == null || pairs[j].getKey().equals("value")) //$NON-NLS-1$ + return (pairs[j].getValue() != Boolean.FALSE); + } + return true; + } + } + if (enclosingElement instanceof IMethodBinding) { + return hasNonNullDefault(((IMethodBinding)enclosingElement).getDeclaringClass()); + } else if (enclosingElement instanceof ITypeBinding) { + ITypeBinding typeBinding= (ITypeBinding)enclosingElement; + if (typeBinding.isLocal()) + return hasNonNullDefault(typeBinding.getDeclaringMethod()); + else if (typeBinding.isMember()) + return hasNonNullDefault(typeBinding.getDeclaringClass()); + else + return hasNonNullDefault(typeBinding.getPackage()); + } + return false; + } + public String getMessage() { return fMessage; } @@ -109,7 +149,7 @@ public class NullAnnotationsRewriteOperations { */ static class ReturnAnnotationRewriteOperation extends SignatureAnnotationRewriteOperation { - private final BodyDeclaration fBodyDeclaration; + private final MethodDeclaration fBodyDeclaration; ReturnAnnotationRewriteOperation(CompilationUnit unit, MethodDeclaration method, String annotationToAdd, String annotationToRemove, boolean allowRemove, String message) { fUnit= unit; @@ -128,6 +168,8 @@ public class NullAnnotationsRewriteOperations { TextEditGroup group= createTextEditGroup(fMessage, cuRewrite); if (!checkExisting(fBodyDeclaration.modifiers(), listRewrite, group)) return; + if (hasNonNullDefault(fBodyDeclaration.resolveBinding())) + return; // should be safe, as in this case checkExisting() should've already produced a change (remove existing annotation). Annotation newAnnotation= ast.newMarkerAnnotation(); ImportRewrite importRewrite= cuRewrite.getImportRewrite(); String resolvableName= importRewrite.addImport(fAnnotationToAdd); @@ -241,9 +283,15 @@ public class NullAnnotationsRewriteOperations { // 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); + Set<String> handledPositions, boolean thisUnitOnly, boolean allowRemove, boolean isArgumentProblem, ChangeKind changeKind) { + // precondition: + // thisUnitOnly => changeKind == LOCAL + SignatureAnnotationRewriteOperation result; + if (changeKind == ChangeKind.OVERRIDDEN) + result= createAddAnnotationToOverriddenOperation(compilationUnit, problem, annotationToAdd, annotationToRemove, allowRemove); + else + result= createAddAnnotationOperation(compilationUnit, problem, annotationToAdd, annotationToRemove, changeKind == ChangeKind.TARGET, + thisUnitOnly, allowRemove, isArgumentProblem); if (handledPositions != null && result != null) { if (handledPositions.contains(result.getKey())) return null; @@ -253,7 +301,7 @@ public class NullAnnotationsRewriteOperations { } private static SignatureAnnotationRewriteOperation createAddAnnotationOperation(CompilationUnit compilationUnit, IProblemLocation problem, String annotationToAdd, String annotationToRemove, - Set<String> handledPositions, boolean thisUnitOnly, boolean allowRemove) { + boolean changeTargetMethod, boolean thisUnitOnly, boolean allowRemove, boolean isArgumentProblem) { ICompilationUnit cu= (ICompilationUnit) compilationUnit.getJavaElement(); if (!JavaModelUtil.is50OrHigher(cu.getJavaProject())) return null; @@ -274,7 +322,7 @@ public class NullAnnotationsRewriteOperations { break; // do propose changes even if we already have an annotation default: // if this method has annotations, don't change'em - if (NullAnnotationsFix.hasExplicitNullAnnotation(cu, problem.getOffset())) + if (!allowRemove && NullAnnotationsFix.hasExplicitNullAnnotation(cu, problem.getOffset())) return null; } @@ -284,21 +332,38 @@ public class NullAnnotationsRewriteOperations { 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; - String message= Messages.format(FixMessages.NullAnnotationsRewriteOperations_change_method_parameter_nullness, annotationNameLabel); - return new ParameterAnnotationRewriteOperation(compilationUnit, (MethodDeclaration) methodDecl, annotationToAdd, annotationToRemove, paramIdx, allowRemove, message); + if (changeTargetMethod) { + MethodInvocation methodInvocation= null; + if (isArgumentProblem) { + if (selectedNode.getParent() instanceof MethodInvocation) + methodInvocation= (MethodInvocation) selectedNode.getParent(); + } else { + if (selectedNode instanceof MethodInvocation) + methodInvocation= (MethodInvocation) selectedNode; + } + if (methodInvocation != null) { + // DefiniteNullToNonNullParameter || PotentialNullToNonNullParameter + 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; + if (isArgumentProblem) { + String message= Messages.format(FixMessages.NullAnnotationsRewriteOperations_change_target_method_parameter_nullness, + new Object[] {methodInvocation.getName(), annotationNameLabel}); + return new ParameterAnnotationRewriteOperation(compilationUnit, (MethodDeclaration) methodDecl, annotationToAdd, annotationToRemove, paramIdx, allowRemove, message); + } else { + MethodDeclaration declaration = (MethodDeclaration) methodDecl; + String message= Messages.format(FixMessages.NullAnnotationsRewriteOperations_change_method_return_nullness, + new String[] { declaration.getName().getIdentifier(), annotationNameLabel }); + return new ReturnAnnotationRewriteOperation(compilationUnit, declaration, annotationToAdd, annotationToRemove, allowRemove, message); + } + } } else if (declaringNode instanceof MethodDeclaration) { // complaint is in signature of this method MethodDeclaration declaration= (MethodDeclaration) declaringNode; @@ -307,13 +372,14 @@ public class NullAnnotationsRewriteOperations { case IProblem.ParameterLackingNullableAnnotation: case IProblem.IllegalDefinitionToNonNullParameter: case IProblem.IllegalRedefinitionToNonNullParameter: - case IProblem.NonNullLocalVariableComparisonYieldsFalse: - case IProblem.RedundantNullCheckOnNonNullLocalVariable: - // statements suggest changing parameters: + case IProblem.SpecdNonNullLocalVariableComparisonYieldsFalse: + case IProblem.RedundantNullCheckOnSpecdNonNullLocalVariable: + // problems regarding the argument declaration: if (declaration.getNodeType() == ASTNode.METHOD_DECLARATION) { String paramName= findAffectedParameterName(selectedNode); if (paramName != null) { - String message= Messages.format(FixMessages.NullAnnotationsRewriteOperations_change_method_parameter_nullness, annotationNameLabel); + String message= Messages.format(FixMessages.NullAnnotationsRewriteOperations_change_method_parameter_nullness, + new Object[] {paramName, annotationNameLabel}); return new ParameterAnnotationRewriteOperation(compilationUnit, declaration, annotationToAdd, annotationToRemove, paramName, allowRemove, message); } } @@ -322,13 +388,16 @@ public class NullAnnotationsRewriteOperations { case IProblem.RequiredNonNullButProvidedPotentialNull: case IProblem.RequiredNonNullButProvidedSpecdNullable: case IProblem.RequiredNonNullButProvidedUnknown: - if (NullAnnotationsFix.isComplainingAboutArgument(selectedNode)) { - //TODO: duplication - // statements suggest changing parameters: - if (declaration.getNodeType() == ASTNode.METHOD_DECLARATION) { - String paramName= findAffectedParameterName(selectedNode); + case IProblem.ConflictingNullAnnotations: + case IProblem.ConflictingInheritedNullAnnotations: + if (isArgumentProblem) { + // statement suggests changing parameters: + if (declaration.getNodeType() == ASTNode.METHOD_DECLARATION && selectedNode instanceof SimpleName) { + // don't call findAffectedParameterName(), in this branch we're not interested in any target method + String paramName= ((SimpleName) selectedNode).getIdentifier(); if (paramName != null) { - String message= Messages.format(FixMessages.NullAnnotationsRewriteOperations_change_method_parameter_nullness, annotationNameLabel); + String message= Messages.format(FixMessages.NullAnnotationsRewriteOperations_change_method_parameter_nullness, + new Object[] { paramName, annotationNameLabel }); return new ParameterAnnotationRewriteOperation(compilationUnit, declaration, annotationToAdd, annotationToRemove, paramName, allowRemove, message); } } @@ -344,7 +413,7 @@ public class NullAnnotationsRewriteOperations { } private static SignatureAnnotationRewriteOperation createAddAnnotationToOverriddenOperation(CompilationUnit compilationUnit, IProblemLocation problem, String annotationToAdd, - String annotationToRemove, Set<String> handledPositions, boolean thisUnitOnly, boolean allowRemove) { + String annotationToRemove, boolean allowRemove) { ICompilationUnit cu= (ICompilationUnit) compilationUnit.getJavaElement(); if (!JavaModelUtil.is50OrHigher(cu.getJavaProject())) return null; |