Added
Link Here
|
1 |
/******************************************************************************* |
2 |
* Copyright (c) 2011 GK Software AG and others. |
3 |
* All rights reserved. This program and the accompanying materials |
4 |
* are made available under the terms of the Eclipse Public License v1.0 |
5 |
* which accompanies this distribution, and is available at |
6 |
* http://www.eclipse.org/legal/epl-v10.html |
7 |
* |
8 |
* Contributors: |
9 |
* Stephan Herrmann - initial API and implementation |
10 |
*******************************************************************************/ |
11 |
package org.eclipse.jdt.internal.ui.fix; |
12 |
|
13 |
import java.util.List; |
14 |
import java.util.Set; |
15 |
|
16 |
import org.eclipse.core.runtime.CoreException; |
17 |
import org.eclipse.jdt.core.ICompilationUnit; |
18 |
import org.eclipse.jdt.core.JavaModelException; |
19 |
import org.eclipse.jdt.core.compiler.IProblem; |
20 |
import org.eclipse.jdt.core.dom.AST; |
21 |
import org.eclipse.jdt.core.dom.ASTNode; |
22 |
import org.eclipse.jdt.core.dom.Annotation; |
23 |
import org.eclipse.jdt.core.dom.BodyDeclaration; |
24 |
import org.eclipse.jdt.core.dom.CompilationUnit; |
25 |
import org.eclipse.jdt.core.dom.IBinding; |
26 |
import org.eclipse.jdt.core.dom.IExtendedModifier; |
27 |
import org.eclipse.jdt.core.dom.IMethodBinding; |
28 |
import org.eclipse.jdt.core.dom.ITypeBinding; |
29 |
import org.eclipse.jdt.core.dom.IVariableBinding; |
30 |
import org.eclipse.jdt.core.dom.MarkerAnnotation; |
31 |
import org.eclipse.jdt.core.dom.MethodDeclaration; |
32 |
import org.eclipse.jdt.core.dom.MethodInvocation; |
33 |
import org.eclipse.jdt.core.dom.Name; |
34 |
import org.eclipse.jdt.core.dom.SimpleName; |
35 |
import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
36 |
import org.eclipse.jdt.core.dom.VariableDeclaration; |
37 |
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; |
38 |
import org.eclipse.jdt.core.dom.rewrite.ListRewrite; |
39 |
import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
40 |
import org.eclipse.jdt.internal.corext.dom.Bindings; |
41 |
import org.eclipse.jdt.internal.corext.fix.CompilationUnitRewriteOperationsFix.CompilationUnitRewriteOperation; |
42 |
import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel; |
43 |
import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; |
44 |
import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
45 |
import org.eclipse.jdt.internal.corext.util.Messages; |
46 |
import org.eclipse.jdt.internal.ui.text.correction.ASTResolving; |
47 |
import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels; |
48 |
import org.eclipse.jdt.ui.text.java.IProblemLocation; |
49 |
import org.eclipse.text.edits.TextEditGroup; |
50 |
|
51 |
public class NullRewriteOperations { |
52 |
|
53 |
static abstract class SignatureAnnotationRewriteOperation extends CompilationUnitRewriteOperation { |
54 |
String fAnnotationToAdd; |
55 |
String fAnnotationToRemove; |
56 |
boolean fAllowRemove; |
57 |
CompilationUnit fUnit; |
58 |
|
59 |
protected String fKey; |
60 |
protected String fMessage; |
61 |
|
62 |
/** A globally unique key that identifies the position being annotated (for avoiding double annotations). */ |
63 |
public String getKey() { return this.fKey; } |
64 |
|
65 |
public CompilationUnit getCompilationUnit() { |
66 |
return fUnit; |
67 |
} |
68 |
|
69 |
|
70 |
boolean checkExisting(@SuppressWarnings("rawtypes") List existingModifiers, |
71 |
ListRewrite listRewrite, |
72 |
TextEditGroup editGroup) |
73 |
{ |
74 |
for (Object mod : existingModifiers) { |
75 |
if (mod instanceof MarkerAnnotation) { |
76 |
MarkerAnnotation annotation = (MarkerAnnotation) mod; |
77 |
String existingName = annotation.getTypeName().getFullyQualifiedName(); |
78 |
int lastDot = fAnnotationToRemove.lastIndexOf('.'); |
79 |
if ( existingName.equals(fAnnotationToRemove) |
80 |
|| (lastDot != -1 && fAnnotationToRemove.substring(lastDot+1).equals(existingName))) |
81 |
{ |
82 |
if (!fAllowRemove) |
83 |
return false; // veto this change |
84 |
listRewrite.remove(annotation, editGroup); |
85 |
return true; |
86 |
} |
87 |
// paranoia: check if by accident the annotation is already present (shouldn't happen): |
88 |
lastDot = fAnnotationToAdd.lastIndexOf('.'); |
89 |
if ( existingName.equals(fAnnotationToAdd) |
90 |
|| (lastDot != -1 && fAnnotationToAdd.substring(lastDot+1).equals(existingName))) |
91 |
{ |
92 |
return false; // already present |
93 |
} |
94 |
} |
95 |
} |
96 |
return true; |
97 |
} |
98 |
|
99 |
public String getMessage() { |
100 |
return fMessage; |
101 |
} |
102 |
} |
103 |
|
104 |
/** |
105 |
* Rewrite operation that inserts an annotation into a method signature. |
106 |
* |
107 |
* Crafted after the lead of Java50Fix.AnnotationRewriteOperation |
108 |
* @author stephan |
109 |
*/ |
110 |
static class ReturnAnnotationRewriteOperation extends SignatureAnnotationRewriteOperation { |
111 |
|
112 |
private final BodyDeclaration fBodyDeclaration; |
113 |
|
114 |
ReturnAnnotationRewriteOperation(CompilationUnit unit, |
115 |
MethodDeclaration method, |
116 |
String annotationToAdd, |
117 |
String annotationToRemove, |
118 |
boolean allowRemove, |
119 |
String message) |
120 |
{ |
121 |
fUnit = unit; |
122 |
fKey= method.resolveBinding().getKey()+"<return>"; //$NON-NLS-1$ |
123 |
fBodyDeclaration= method; |
124 |
fAnnotationToAdd= annotationToAdd; |
125 |
fAnnotationToRemove= annotationToRemove; |
126 |
fAllowRemove= allowRemove; |
127 |
fMessage = message; |
128 |
} |
129 |
|
130 |
@Override |
131 |
public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException { |
132 |
AST ast= cuRewrite.getRoot().getAST(); |
133 |
ListRewrite listRewrite= cuRewrite.getASTRewrite().getListRewrite(fBodyDeclaration, fBodyDeclaration.getModifiersProperty()); |
134 |
TextEditGroup group= createTextEditGroup(fMessage, cuRewrite); |
135 |
if (!checkExisting(fBodyDeclaration.modifiers(), listRewrite, group)) |
136 |
return; |
137 |
Annotation newAnnotation= ast.newMarkerAnnotation(); |
138 |
ImportRewrite importRewrite = cuRewrite.getImportRewrite(); |
139 |
String resolvableName = importRewrite.addImport(fAnnotationToAdd); |
140 |
newAnnotation.setTypeName(ast.newName(resolvableName)); |
141 |
listRewrite.insertLast(newAnnotation, group); // null annotation is last modifier, directly preceding the return type |
142 |
} |
143 |
} |
144 |
|
145 |
static class ParameterAnnotationRewriteOperation extends SignatureAnnotationRewriteOperation { |
146 |
|
147 |
private SingleVariableDeclaration fArgument; |
148 |
|
149 |
ParameterAnnotationRewriteOperation(CompilationUnit unit, |
150 |
MethodDeclaration method, |
151 |
String annotationToAdd, |
152 |
String annotationToRemove, |
153 |
String paramName, |
154 |
boolean allowRemove, |
155 |
String message) |
156 |
{ |
157 |
fUnit= unit; |
158 |
fKey= method.resolveBinding().getKey(); |
159 |
fAnnotationToAdd= annotationToAdd; |
160 |
fAnnotationToRemove= annotationToRemove; |
161 |
fAllowRemove= allowRemove; |
162 |
fMessage = message; |
163 |
for (Object param : method.parameters()) { |
164 |
SingleVariableDeclaration argument = (SingleVariableDeclaration) param; |
165 |
if (argument.getName().getIdentifier().equals(paramName)) { |
166 |
fArgument= argument; |
167 |
fKey += argument.getName().getIdentifier(); |
168 |
return; |
169 |
} |
170 |
} |
171 |
// shouldn't happen, we've checked that paramName indeed denotes a parameter. |
172 |
throw new RuntimeException("Argument "+paramName+" not found in method "+method.getName().getIdentifier()); //$NON-NLS-1$ //$NON-NLS-2$ |
173 |
} |
174 |
|
175 |
ParameterAnnotationRewriteOperation(CompilationUnit unit, |
176 |
MethodDeclaration method, |
177 |
String annotationToAdd, |
178 |
String annotationToRemove, |
179 |
int paramIdx, |
180 |
boolean allowRemove, |
181 |
String message) |
182 |
{ |
183 |
fUnit= unit; |
184 |
fKey= method.resolveBinding().getKey(); |
185 |
fAnnotationToAdd= annotationToAdd; |
186 |
fAnnotationToRemove= annotationToRemove; |
187 |
fAllowRemove= allowRemove; |
188 |
fArgument = (SingleVariableDeclaration) method.parameters().get(paramIdx); |
189 |
fKey += fArgument.getName().getIdentifier(); |
190 |
fMessage = message; |
191 |
} |
192 |
|
193 |
@Override |
194 |
public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel linkedModel) throws CoreException { |
195 |
AST ast= cuRewrite.getRoot().getAST(); |
196 |
ListRewrite listRewrite= cuRewrite.getASTRewrite().getListRewrite(fArgument, SingleVariableDeclaration.MODIFIERS2_PROPERTY); |
197 |
TextEditGroup group= createTextEditGroup(fMessage, cuRewrite); |
198 |
if (!checkExisting(fArgument.modifiers(), listRewrite, group)) |
199 |
return; |
200 |
Annotation newAnnotation= ast.newMarkerAnnotation(); |
201 |
ImportRewrite importRewrite = cuRewrite.getImportRewrite(); |
202 |
String resolvableName = importRewrite.addImport(fAnnotationToAdd); |
203 |
newAnnotation.setTypeName(ast.newName(resolvableName)); |
204 |
listRewrite.insertLast(newAnnotation, group); // null annotation is last modifier, directly preceding the type |
205 |
} |
206 |
} |
207 |
|
208 |
// Entry for QuickFixes: |
209 |
public static SignatureAnnotationRewriteOperation createAddAnnotationOperation(CompilationUnit compilationUnit, |
210 |
IProblemLocation problem, |
211 |
String annotationToAdd, |
212 |
String annotationToRemove, |
213 |
Set<String> handledPositions, |
214 |
boolean thisUnitOnly, |
215 |
boolean allowRemove, |
216 |
boolean modifyOverridden) |
217 |
{ |
218 |
SignatureAnnotationRewriteOperation result = modifyOverridden |
219 |
? createAddAnnotationToOverriddenOperation(compilationUnit, problem, annotationToAdd, annotationToRemove, |
220 |
handledPositions, thisUnitOnly, allowRemove) |
221 |
: createAddAnnotationOperation(compilationUnit, problem, annotationToAdd, annotationToRemove, |
222 |
handledPositions, thisUnitOnly, allowRemove); |
223 |
if (handledPositions != null && result != null) { |
224 |
if (handledPositions.contains(result.getKey())) |
225 |
return null; |
226 |
handledPositions.add(result.getKey()); |
227 |
} |
228 |
return result; |
229 |
} |
230 |
static SignatureAnnotationRewriteOperation createAddAnnotationOperation(CompilationUnit compilationUnit, |
231 |
IProblemLocation problem, |
232 |
String annotationToAdd, |
233 |
String annotationToRemove, |
234 |
Set<String> handledPositions, |
235 |
boolean thisUnitOnly, |
236 |
boolean allowRemove) |
237 |
{ |
238 |
ICompilationUnit cu= (ICompilationUnit)compilationUnit.getJavaElement(); |
239 |
if (!JavaModelUtil.is50OrHigher(cu.getJavaProject())) |
240 |
return null; |
241 |
|
242 |
ASTNode selectedNode= problem.getCoveringNode(compilationUnit); |
243 |
if (selectedNode == null) |
244 |
return null; |
245 |
|
246 |
ASTNode declaringNode= getDeclaringNode(selectedNode); |
247 |
|
248 |
switch (problem.getProblemId()) { |
249 |
case IProblem.IllegalDefinitionToNonNullParameter: |
250 |
// case IllegalRedefinitionToNonNullParameter: |
251 |
// these affect another method |
252 |
break; |
253 |
case IProblem.IllegalReturnNullityRedefinition: |
254 |
if (declaringNode == null) |
255 |
declaringNode = selectedNode; |
256 |
break; // do propose changes even if we already have an annotation |
257 |
default: |
258 |
// if this method has annotations, don't change'em |
259 |
if (NullQuickFixes.hasExplicitNullAnnotation(cu, problem.getOffset())) |
260 |
return null; |
261 |
} |
262 |
|
263 |
SignatureAnnotationRewriteOperation result = null; |
264 |
String message = null; |
265 |
String annotationNameLabel = annotationToAdd; |
266 |
int lastDot = annotationToAdd.lastIndexOf('.'); |
267 |
if (lastDot != -1) |
268 |
annotationNameLabel = annotationToAdd.substring(lastDot+1); |
269 |
annotationNameLabel = BasicElementLabels.getJavaElementName(annotationNameLabel); |
270 |
|
271 |
if (selectedNode.getParent() instanceof MethodInvocation) { |
272 |
// DefiniteNullToNonNullParameter || PotentialNullToNonNullParameter |
273 |
MethodInvocation methodInvocation = (MethodInvocation)selectedNode.getParent(); |
274 |
int paramIdx = methodInvocation.arguments().indexOf(selectedNode); |
275 |
IMethodBinding methodBinding = methodInvocation.resolveMethodBinding(); |
276 |
compilationUnit = findCUForMethod(compilationUnit, cu, methodBinding); |
277 |
if (compilationUnit == null) |
278 |
return null; |
279 |
if (thisUnitOnly && !compilationUnit.getJavaElement().equals(cu)) |
280 |
return null; |
281 |
ASTNode methodDecl = compilationUnit.findDeclaringNode(methodBinding.getKey()); |
282 |
if (methodDecl == null) |
283 |
return null; |
284 |
message = Messages.format(NullFixMessages.QuickFixes_declare_method_parameter_nullness, annotationNameLabel); |
285 |
result = new ParameterAnnotationRewriteOperation(compilationUnit, |
286 |
(MethodDeclaration) methodDecl, |
287 |
annotationToAdd, |
288 |
annotationToRemove, |
289 |
paramIdx, |
290 |
allowRemove, |
291 |
message); |
292 |
} else if (declaringNode instanceof MethodDeclaration) { |
293 |
|
294 |
// complaint is in signature of this method |
295 |
|
296 |
MethodDeclaration declaration= (MethodDeclaration) declaringNode; |
297 |
|
298 |
switch (problem.getProblemId()) { |
299 |
case IProblem.ParameterLackingNonNullAnnotation: |
300 |
case IProblem.ParameterLackingNullableAnnotation: |
301 |
case IProblem.IllegalDefinitionToNonNullParameter: |
302 |
case IProblem.IllegalRedefinitionToNonNullParameter: |
303 |
case IProblem.NonNullLocalVariableComparisonYieldsFalse: |
304 |
case IProblem.RedundantNullCheckOnNonNullLocalVariable: |
305 |
// statements suggest changing parameters: |
306 |
if (declaration.getNodeType() == ASTNode.METHOD_DECLARATION) { |
307 |
String paramName = findAffectedParameterName(selectedNode); |
308 |
if (paramName != null) { |
309 |
message = Messages.format(NullFixMessages.QuickFixes_declare_method_parameter_nullness, annotationNameLabel); |
310 |
result = new ParameterAnnotationRewriteOperation(compilationUnit, |
311 |
declaration, |
312 |
annotationToAdd, |
313 |
annotationToRemove, |
314 |
paramName, |
315 |
allowRemove, |
316 |
message); |
317 |
} |
318 |
} |
319 |
break; |
320 |
case IProblem.IllegalReturnNullityRedefinition: |
321 |
case IProblem.RequiredNonNullButProvidedNull: |
322 |
case IProblem.RequiredNonNullButProvidedPotentialNull: |
323 |
case IProblem.RequiredNonNullButProvidedUnknown: |
324 |
message = Messages.format(NullFixMessages.QuickFixes_declare_method_return_nullness, annotationNameLabel); |
325 |
result = new ReturnAnnotationRewriteOperation(compilationUnit, |
326 |
declaration, |
327 |
annotationToAdd, |
328 |
annotationToRemove, |
329 |
allowRemove, |
330 |
message); |
331 |
break; |
332 |
} |
333 |
|
334 |
} |
335 |
return result; |
336 |
} |
337 |
static SignatureAnnotationRewriteOperation createAddAnnotationToOverriddenOperation(CompilationUnit compilationUnit, |
338 |
IProblemLocation problem, |
339 |
String annotationToAdd, |
340 |
String annotationToRemove, |
341 |
Set<String> handledPositions, |
342 |
boolean thisUnitOnly, |
343 |
boolean allowRemove) |
344 |
{ |
345 |
ICompilationUnit cu = (ICompilationUnit) compilationUnit.getJavaElement(); |
346 |
if (!JavaModelUtil.is50OrHigher(cu.getJavaProject())) |
347 |
return null; |
348 |
|
349 |
ASTNode selectedNode = problem.getCoveringNode(compilationUnit); |
350 |
if (selectedNode == null) |
351 |
return null; |
352 |
|
353 |
ASTNode declaringNode = getDeclaringNode(selectedNode); |
354 |
|
355 |
switch (problem.getProblemId()) { |
356 |
case IProblem.IllegalDefinitionToNonNullParameter: |
357 |
case IProblem.IllegalRedefinitionToNonNullParameter: |
358 |
break; |
359 |
case IProblem.IllegalReturnNullityRedefinition: |
360 |
if (declaringNode == null) |
361 |
declaringNode = selectedNode; |
362 |
break; |
363 |
default: |
364 |
return null; |
365 |
} |
366 |
|
367 |
String annotationNameLabel = annotationToAdd; |
368 |
int lastDot = annotationToAdd.lastIndexOf('.'); |
369 |
if (lastDot != -1) |
370 |
annotationNameLabel = annotationToAdd.substring(lastDot + 1); |
371 |
annotationNameLabel = BasicElementLabels.getJavaElementName(annotationNameLabel); |
372 |
|
373 |
if (declaringNode instanceof MethodDeclaration) { |
374 |
|
375 |
// complaint is in signature of this method |
376 |
|
377 |
MethodDeclaration declaration = (MethodDeclaration) declaringNode; |
378 |
|
379 |
switch (problem.getProblemId()) { |
380 |
case IProblem.IllegalDefinitionToNonNullParameter: |
381 |
case IProblem.IllegalRedefinitionToNonNullParameter: |
382 |
return createChangeOverriddenParameterOperation(compilationUnit, cu, declaration, selectedNode, |
383 |
allowRemove, annotationToAdd, annotationToRemove, annotationNameLabel); |
384 |
case IProblem.IllegalReturnNullityRedefinition: |
385 |
if (hasNullAnnotation(declaration)) { // don't adjust super if local has no explicit annotation (?) |
386 |
return createChangeOverriddenReturnOperation(compilationUnit, cu, declaration, allowRemove, |
387 |
annotationToAdd, annotationToRemove, annotationNameLabel); |
388 |
} |
389 |
} |
390 |
|
391 |
} |
392 |
return null; |
393 |
} |
394 |
|
395 |
static SignatureAnnotationRewriteOperation createChangeOverriddenParameterOperation(CompilationUnit compilationUnit, |
396 |
ICompilationUnit cu, |
397 |
MethodDeclaration declaration, |
398 |
ASTNode selectedNode, |
399 |
boolean allowRemove, |
400 |
String annotationToAdd, |
401 |
String annotationToRemove, |
402 |
String annotationNameLabel) |
403 |
{ |
404 |
SignatureAnnotationRewriteOperation result; |
405 |
String message; |
406 |
IMethodBinding methodDeclBinding= declaration.resolveBinding(); |
407 |
if (methodDeclBinding == null) |
408 |
return null; |
409 |
|
410 |
IMethodBinding overridden= Bindings.findOverriddenMethod(methodDeclBinding, false); |
411 |
if (overridden == null) |
412 |
return null; |
413 |
compilationUnit = findCUForMethod(compilationUnit, cu, overridden); |
414 |
if (compilationUnit == null) |
415 |
return null; |
416 |
ASTNode methodDecl = compilationUnit.findDeclaringNode(overridden.getKey()); |
417 |
if (methodDecl == null) |
418 |
return null; |
419 |
declaration = (MethodDeclaration) methodDecl; |
420 |
message = Messages.format(NullFixMessages.QuickFixes_declare_overridden_parameter_as_nonnull, |
421 |
new String[] { |
422 |
annotationNameLabel, |
423 |
BasicElementLabels.getJavaElementName(overridden.getDeclaringClass().getName()) |
424 |
}); |
425 |
String paramName = findAffectedParameterName(selectedNode); |
426 |
result = new ParameterAnnotationRewriteOperation(compilationUnit, |
427 |
declaration, |
428 |
annotationToAdd, |
429 |
annotationToRemove, |
430 |
paramName, |
431 |
allowRemove, |
432 |
message); |
433 |
return result; |
434 |
} |
435 |
|
436 |
static String findAffectedParameterName(ASTNode selectedNode) { |
437 |
VariableDeclaration argDecl = selectedNode instanceof VariableDeclaration |
438 |
? (VariableDeclaration) selectedNode |
439 |
: (VariableDeclaration) ASTNodes.getParent(selectedNode, VariableDeclaration.class); |
440 |
if (argDecl != null) |
441 |
return argDecl.getName().getIdentifier(); |
442 |
if (selectedNode.getNodeType() == ASTNode.SIMPLE_NAME) { |
443 |
IBinding binding = ((SimpleName)selectedNode).resolveBinding(); |
444 |
if (binding.getKind() == IBinding.VARIABLE && ((IVariableBinding)binding).isParameter()) |
445 |
return ((SimpleName)selectedNode).getIdentifier(); |
446 |
} |
447 |
return null; |
448 |
} |
449 |
|
450 |
static boolean hasNullAnnotation(MethodDeclaration decl) { |
451 |
List<IExtendedModifier> modifiers = decl.modifiers(); |
452 |
String nonnull = NullQuickFixes.getNonNullAnnotationName(decl.resolveBinding().getJavaElement(), false); |
453 |
String nullable = NullQuickFixes.getNullableAnnotationName(decl.resolveBinding().getJavaElement(), false); |
454 |
for (Object mod : modifiers) { |
455 |
if (mod instanceof Annotation) { |
456 |
Name annotationName = ((Annotation) mod).getTypeName(); |
457 |
String fullyQualifiedName = annotationName.getFullyQualifiedName(); |
458 |
if (annotationName.isSimpleName() |
459 |
? nonnull.endsWith(fullyQualifiedName) |
460 |
: fullyQualifiedName.equals(nonnull)) |
461 |
return true; |
462 |
if (annotationName.isSimpleName() |
463 |
? nullable.endsWith(fullyQualifiedName) |
464 |
: fullyQualifiedName.equals(nullable)) |
465 |
return true; |
466 |
} |
467 |
} |
468 |
return false; |
469 |
} |
470 |
|
471 |
static SignatureAnnotationRewriteOperation createChangeOverriddenReturnOperation(CompilationUnit compilationUnit, |
472 |
ICompilationUnit cu, |
473 |
MethodDeclaration declaration, |
474 |
boolean allowRemove, |
475 |
String annotationToAdd, |
476 |
String annotationToRemove, |
477 |
String annotationNameLabel) |
478 |
{ |
479 |
SignatureAnnotationRewriteOperation result; |
480 |
String message; |
481 |
IMethodBinding methodDeclBinding= declaration.resolveBinding(); |
482 |
if (methodDeclBinding == null) |
483 |
return null; |
484 |
|
485 |
IMethodBinding overridden= Bindings.findOverriddenMethod(methodDeclBinding, false); |
486 |
if (overridden == null) |
487 |
return null; |
488 |
compilationUnit = findCUForMethod(compilationUnit, cu, overridden); |
489 |
if (compilationUnit == null) |
490 |
return null; |
491 |
ASTNode methodDecl = compilationUnit.findDeclaringNode(overridden.getKey()); |
492 |
if (methodDecl == null) |
493 |
return null; |
494 |
declaration = (MethodDeclaration) methodDecl; |
495 |
// TODO(SH): decide whether we want to propose overwriting existing annotations in super |
496 |
// if (hasNullAnnotation(declaration)) // if overridden has explicit declaration don't propose to change it |
497 |
// return null; |
498 |
message = Messages.format(NullFixMessages.QuickFixes_declare_overridden_return_as_nullable, |
499 |
new String[] { |
500 |
annotationNameLabel, |
501 |
BasicElementLabels.getJavaElementName(overridden.getDeclaringClass().getName()) |
502 |
}); |
503 |
result = new ReturnAnnotationRewriteOperation(compilationUnit, |
504 |
declaration, |
505 |
annotationToAdd, |
506 |
annotationToRemove, |
507 |
allowRemove, |
508 |
message); |
509 |
return result; |
510 |
} |
511 |
|
512 |
static CompilationUnit findCUForMethod(CompilationUnit compilationUnit, ICompilationUnit cu, IMethodBinding methodBinding) |
513 |
{ |
514 |
ASTNode methodDecl= compilationUnit.findDeclaringNode(methodBinding.getMethodDeclaration()); |
515 |
if (methodDecl == null) { |
516 |
// is methodDecl defined in another CU? |
517 |
ITypeBinding declaringTypeDecl= methodBinding.getDeclaringClass().getTypeDeclaration(); |
518 |
if (declaringTypeDecl.isFromSource()) { |
519 |
ICompilationUnit targetCU = null; |
520 |
try { |
521 |
targetCU = ASTResolving.findCompilationUnitForBinding(cu, compilationUnit, declaringTypeDecl); |
522 |
} catch (JavaModelException e) { /* can't do better */ } |
523 |
if (targetCU != null) { |
524 |
return ASTResolving.createQuickFixAST(targetCU, null); |
525 |
} |
526 |
} |
527 |
return null; |
528 |
} |
529 |
return compilationUnit; |
530 |
} |
531 |
|
532 |
/** The relevant declaring node of a return statement is the enclosing method. */ |
533 |
static ASTNode getDeclaringNode(ASTNode selectedNode) { |
534 |
return ASTNodes.getParent(selectedNode, ASTNode.METHOD_DECLARATION); |
535 |
} |
536 |
} |