]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-before/core extension/org/eclipse/jdt/internal/corext/fix/CodeStyleFix.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / core extension / org / eclipse / jdt / internal / corext / fix / CodeStyleFix.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2011 IBM Corporation 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 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11package org.eclipse.jdt.internal.corext.fix;
12
13import java.util.ArrayList;
14import java.util.HashMap;
15import java.util.List;
16
17import org.eclipse.core.runtime.CoreException;
18
19import org.eclipse.text.edits.TextEditGroup;
20
21import org.eclipse.jdt.core.IJavaElement;
22import org.eclipse.jdt.core.IType;
23import org.eclipse.jdt.core.compiler.IProblem;
24import org.eclipse.jdt.core.dom.AST;
25import org.eclipse.jdt.core.dom.ASTNode;
26import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
27import org.eclipse.jdt.core.dom.Assignment;
28import org.eclipse.jdt.core.dom.Block;
29import org.eclipse.jdt.core.dom.ClassInstanceCreation;
30import org.eclipse.jdt.core.dom.CompilationUnit;
31import org.eclipse.jdt.core.dom.ConstructorInvocation;
32import org.eclipse.jdt.core.dom.Expression;
33import org.eclipse.jdt.core.dom.ExpressionStatement;
34import org.eclipse.jdt.core.dom.FieldAccess;
35import org.eclipse.jdt.core.dom.IBinding;
36import org.eclipse.jdt.core.dom.IMethodBinding;
37import org.eclipse.jdt.core.dom.ITypeBinding;
38import org.eclipse.jdt.core.dom.IVariableBinding;
39import org.eclipse.jdt.core.dom.Initializer;
40import org.eclipse.jdt.core.dom.MethodInvocation;
41import org.eclipse.jdt.core.dom.Modifier;
42import org.eclipse.jdt.core.dom.Name;
43import org.eclipse.jdt.core.dom.QualifiedName;
44import org.eclipse.jdt.core.dom.SimpleName;
45import org.eclipse.jdt.core.dom.Statement;
46import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
47import org.eclipse.jdt.core.dom.SuperFieldAccess;
48import org.eclipse.jdt.core.dom.SwitchCase;
49import org.eclipse.jdt.core.dom.ThisExpression;
50import org.eclipse.jdt.core.dom.Type;
51import org.eclipse.jdt.core.dom.TypeDeclaration;
52import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
53import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
54import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
55import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
56
57import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
58import org.eclipse.jdt.internal.corext.dom.ASTNodes;
59import org.eclipse.jdt.internal.corext.dom.Bindings;
60import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
61import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
62import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
63import org.eclipse.jdt.internal.corext.util.Messages;
64
65import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
66import org.eclipse.jdt.ui.text.java.IProblemLocation;
67
68import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
69import org.eclipse.jdt.internal.ui.text.correction.ProblemLocation;
70import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
71
72/**
73 * A fix which fixes code style issues.
74 */
75public class CodeStyleFix extends CompilationUnitRewriteOperationsFix {
76
77 private final static class CodeStyleVisitor extends GenericVisitor {
78
79 private final List<CompilationUnitRewriteOperation> fResult;
80 private final ImportRewrite fImportRewrite;
81 private final boolean fFindUnqualifiedAccesses;
82 private final boolean fFindUnqualifiedStaticAccesses;
83 private final boolean fFindUnqualifiedMethodAccesses;
84 private final boolean fFindUnqualifiedStaticMethodAccesses;
85
86 public CodeStyleVisitor(CompilationUnit compilationUnit,
87 boolean findUnqualifiedAccesses,
88 boolean findUnqualifiedStaticAccesses,
89 boolean findUnqualifiedMethodAccesses,
90 boolean findUnqualifiedStaticMethodAccesses,
91 List<CompilationUnitRewriteOperation> resultingCollection) {
92
93 fFindUnqualifiedAccesses= findUnqualifiedAccesses;
94 fFindUnqualifiedStaticAccesses= findUnqualifiedStaticAccesses;
95 fFindUnqualifiedMethodAccesses= findUnqualifiedMethodAccesses;
96 fFindUnqualifiedStaticMethodAccesses= findUnqualifiedStaticMethodAccesses;
97 fImportRewrite= StubUtility.createImportRewrite(compilationUnit, true);
98 fResult= resultingCollection;
99 }
100
101 /**
102 * {@inheritDoc}
103 */
104 @Override
105 public boolean visit(TypeDeclaration node) {
106 if (!fFindUnqualifiedStaticAccesses && !fFindUnqualifiedStaticMethodAccesses && node.isInterface())
107 return false;
108
109 return super.visit(node);
110 }
111
112 @Override
113 public boolean visit(QualifiedName node) {
114 if (fFindUnqualifiedAccesses || fFindUnqualifiedStaticAccesses) {
115 ASTNode simpleName= node;
116 while (simpleName instanceof QualifiedName) {
117 simpleName= ((QualifiedName) simpleName).getQualifier();
118 }
119 if (simpleName instanceof SimpleName) {
120 handleSimpleName((SimpleName)simpleName);
121 }
122 }
123 return false;
124 }
125
126 @Override
127 public boolean visit(SimpleName node) {
128 if (fFindUnqualifiedAccesses || fFindUnqualifiedStaticAccesses) {
129 handleSimpleName(node);
130 }
131 return false;
132 }
133
134 /**
135 * {@inheritDoc}
136 */
137 @Override
138 public boolean visit(MethodInvocation node) {
139 if (!fFindUnqualifiedMethodAccesses && !fFindUnqualifiedStaticMethodAccesses)
140 return true;
141
142 if (node.getExpression() != null)
143 return true;
144
145 IBinding binding= node.getName().resolveBinding();
146 if (!(binding instanceof IMethodBinding))
147 return true;
148
149 handleMethod(node.getName(), (IMethodBinding)binding);
150 return true;
151 }
152
153 private void handleSimpleName(SimpleName node) {
154 ASTNode firstExpression= node.getParent();
155 if (firstExpression instanceof FieldAccess) {
156 while (firstExpression instanceof FieldAccess) {
157 firstExpression= ((FieldAccess)firstExpression).getExpression();
158 }
159 if (!(firstExpression instanceof SimpleName))
160 return;
161
162 node= (SimpleName)firstExpression;
163 } else if (firstExpression instanceof SuperFieldAccess)
164 return;
165
166 StructuralPropertyDescriptor parentDescription= node.getLocationInParent();
167 if (parentDescription == VariableDeclarationFragment.NAME_PROPERTY || parentDescription == SwitchCase.EXPRESSION_PROPERTY)
168 return;
169
170 IBinding binding= node.resolveBinding();
171 if (!(binding instanceof IVariableBinding))
172 return;
173
174 handleVariable(node, (IVariableBinding) binding);
175 }
176
177 private void handleVariable(SimpleName node, IVariableBinding varbinding) {
178 if (!varbinding.isField())
179 return;
180
181 if (varbinding.isEnumConstant())
182 return;
183
184 ITypeBinding declaringClass= varbinding.getDeclaringClass();
185 if (Modifier.isStatic(varbinding.getModifiers())) {
186 if (fFindUnqualifiedStaticAccesses) {
187 Initializer initializer= (Initializer) ASTNodes.getParent(node, Initializer.class);
188 //Do not qualify assignments to static final fields in static initializers (would result in compile error)
189 StructuralPropertyDescriptor parentDescription= node.getLocationInParent();
190 if (initializer != null && Modifier.isStatic(initializer.getModifiers())
191 && Modifier.isFinal(varbinding.getModifiers()) && parentDescription == Assignment.LEFT_HAND_SIDE_PROPERTY)
192 return;
193
194 //Do not qualify static fields if defined inside an anonymous class
195 if (declaringClass.isAnonymous())
196 return;
197
198 fResult.add(new AddStaticQualifierOperation(declaringClass, node));
199 }
200 } else if (fFindUnqualifiedAccesses){
201 String qualifier= getThisExpressionQualifier(declaringClass, fImportRewrite, node);
202 if (qualifier == null)
203 return;
204
205 if (qualifier.length() == 0)
206 qualifier= null;
207
208 fResult.add(new AddThisQualifierOperation(qualifier, node));
209 }
210 }
211
212 private void handleMethod(SimpleName node, IMethodBinding binding) {
213 ITypeBinding declaringClass= binding.getDeclaringClass();
214 if (Modifier.isStatic(binding.getModifiers())) {
215 if (fFindUnqualifiedStaticMethodAccesses) {
216 //Do not qualify static fields if defined inside an anonymous class
217 if (declaringClass.isAnonymous())
218 return;
219
220 fResult.add(new AddStaticQualifierOperation(declaringClass, node));
221 }
222 } else {
223 if (fFindUnqualifiedMethodAccesses) {
224 String qualifier= getThisExpressionQualifier(declaringClass, fImportRewrite, node);
225 if (qualifier == null)
226 return;
227
228 if (qualifier.length() == 0)
229 qualifier= null;
230
231 fResult.add(new AddThisQualifierOperation(qualifier, node));
232 }
233 }
234 }
235 }
236
237 private static class ThisQualifierVisitor extends GenericVisitor {
238
239 private final CompilationUnit fCompilationUnit;
240 private final List<CompilationUnitRewriteOperation> fOperations;
241 private final boolean fRemoveFieldQualifiers;
242 private final boolean fRemoveMethodQualifiers;
243
244 public ThisQualifierVisitor(boolean removeFieldQualifiers,
245 boolean removeMethodQualifiers,
246 CompilationUnit compilationUnit,
247 List<CompilationUnitRewriteOperation> result) {
248 fRemoveFieldQualifiers= removeFieldQualifiers;
249 fRemoveMethodQualifiers= removeMethodQualifiers;
250 fCompilationUnit= compilationUnit;
251 fOperations= result;
252 }
253
254 /**
255 * {@inheritDoc}
256 */
257 @Override
258 public boolean visit(final FieldAccess node) {
259 if (!fRemoveFieldQualifiers)
260 return true;
261
262 Expression expression= node.getExpression();
263 if (!(expression instanceof ThisExpression))
264 return true;
265
266 final SimpleName name= node.getName();
267 if (hasConflict(expression.getStartPosition(), name, ScopeAnalyzer.VARIABLES | ScopeAnalyzer.CHECK_VISIBILITY))
268 return true;
269
270 Name qualifier= ((ThisExpression) expression).getQualifier();
271 if (qualifier != null) {
272 ITypeBinding outerClass= (ITypeBinding) qualifier.resolveBinding();
273 if (outerClass == null)
274 return true;
275
276 IVariableBinding nameBinding= (IVariableBinding) name.resolveBinding();
277 if (nameBinding == null)
278 return true;
279
280 ITypeBinding variablesDeclaringClass= nameBinding.getDeclaringClass();
281 if (outerClass != variablesDeclaringClass)
282 //be conservative: We have a reference to a field of an outer type, and this type inherited
283 //the field. It's possible that the inner type inherits the same field. We must not remove
284 //the qualifier in this case.
285 return true;
286
287 ITypeBinding enclosingTypeBinding= Bindings.getBindingOfParentType(node);
288 if (enclosingTypeBinding == null || Bindings.isSuperType(variablesDeclaringClass, enclosingTypeBinding))
289 //We have a reference to a field of an outer type, and this type inherited
290 //the field. The inner type inherits the same field. We must not remove
291 //the qualifier in this case.
292 return true;
293 }
294
295 fOperations.add(new CompilationUnitRewriteOperation() {
296 @Override
297 public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
298 ASTRewrite rewrite= cuRewrite.getASTRewrite();
299 TextEditGroup group= createTextEditGroup(FixMessages.CodeStyleFix_removeThis_groupDescription, cuRewrite);
300 rewrite.replace(node, rewrite.createCopyTarget(name), group);
301 }
302 });
303 return super.visit(node);
304 }
305
306 /**
307 * {@inheritDoc}
308 */
309 @Override
310 public boolean visit(final MethodInvocation node) {
311 if (!fRemoveMethodQualifiers)
312 return true;
313
314 Expression expression= node.getExpression();
315 if (!(expression instanceof ThisExpression))
316 return true;
317
318 final SimpleName name= node.getName();
319 if (name.resolveBinding() == null)
320 return true;
321
322 if (hasConflict(expression.getStartPosition(), name, ScopeAnalyzer.METHODS | ScopeAnalyzer.CHECK_VISIBILITY))
323 return true;
324
325 Name qualifier= ((ThisExpression)expression).getQualifier();
326 if (qualifier != null) {
327 ITypeBinding declaringClass= ((IMethodBinding)name.resolveBinding()).getDeclaringClass();
328 if (declaringClass == null)
329 return true;
330
331 ITypeBinding caller= getDeclaringType(node);
332 if (caller == null)
333 return true;
334
335 ITypeBinding callee= (ITypeBinding)qualifier.resolveBinding();
336 if (callee == null)
337 return true;
338
339 if (callee.isAssignmentCompatible(declaringClass) && caller.isAssignmentCompatible(declaringClass))
340 return true;
341 }
342
343 fOperations.add(new CompilationUnitRewriteOperation() {
344 @Override
345 public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
346 ASTRewrite rewrite= cuRewrite.getASTRewrite();
347 TextEditGroup group= createTextEditGroup(FixMessages.CodeStyleFix_removeThis_groupDescription, cuRewrite);
348 rewrite.remove(node.getExpression(), group);
349 }
350 });
351 return super.visit(node);
352 }
353
354 private ITypeBinding getDeclaringType(MethodInvocation node) {
355 ASTNode p= node;
356 while (p != null) {
357 p= p.getParent();
358 if (p instanceof AbstractTypeDeclaration) {
359 return ((AbstractTypeDeclaration)p).resolveBinding();
360 }
361 }
362 return null;
363 }
364
365 private boolean hasConflict(int startPosition, SimpleName name, int flag) {
366 ScopeAnalyzer analyzer= new ScopeAnalyzer(fCompilationUnit);
367 IBinding[] declarationsInScope= analyzer.getDeclarationsInScope(startPosition, flag);
368 for (int i= 0; i < declarationsInScope.length; i++) {
369 IBinding decl= declarationsInScope[i];
370 if (decl.getName().equals(name.getIdentifier()) && name.resolveBinding() != decl)
371 return true;
372 }
373 return false;
374 }
375 }
376
377 private final static class AddThisQualifierOperation extends CompilationUnitRewriteOperation {
378
379 private final String fQualifier;
380 private final SimpleName fName;
381
382 public AddThisQualifierOperation(String qualifier, SimpleName name) {
383 fQualifier= qualifier;
384 fName= name;
385 }
386
387 public String getDescription() {
388 String nameLabel= BasicElementLabels.getJavaElementName(fName.getIdentifier());
389 String qualifierLabel;
390 if (fQualifier == null) {
391 qualifierLabel= "this"; //$NON-NLS-1$
392 } else {
393 qualifierLabel= BasicElementLabels.getJavaElementName(fQualifier + ".this"); //$NON-NLS-1$
394 }
395
396 return Messages.format(FixMessages.CodeStyleFix_QualifyWithThis_description, new Object[] {nameLabel, qualifierLabel});
397 }
398
399 /**
400 * {@inheritDoc}
401 */
402 @Override
403 public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
404 ASTRewrite rewrite= cuRewrite.getASTRewrite();
405 TextEditGroup group= createTextEditGroup(getDescription(), cuRewrite);
406 AST ast= rewrite.getAST();
407
408 FieldAccess fieldAccess= ast.newFieldAccess();
409
410 ThisExpression thisExpression= ast.newThisExpression();
411 if (fQualifier != null)
412 thisExpression.setQualifier(ast.newName(fQualifier));
413
414 fieldAccess.setExpression(thisExpression);
415 fieldAccess.setName((SimpleName) rewrite.createMoveTarget(fName));
416
417 rewrite.replace(fName, fieldAccess, group);
418 }
419 }
420
421 private final static class AddStaticQualifierOperation extends CompilationUnitRewriteOperation {
422
423 private final SimpleName fName;
424 private final ITypeBinding fDeclaringClass;
425
426 public AddStaticQualifierOperation(ITypeBinding declaringClass, SimpleName name) {
427 super();
428 fDeclaringClass= declaringClass;
429 fName= name;
430 }
431
432 /**
433 * {@inheritDoc}
434 */
435 @Override
436 public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
437 ASTRewrite rewrite= cuRewrite.getASTRewrite();
438 CompilationUnit compilationUnit= cuRewrite.getRoot();
439 importType(fDeclaringClass, fName, cuRewrite.getImportRewrite(), compilationUnit);
440 TextEditGroup group;
441 if (fName.resolveBinding() instanceof IMethodBinding) {
442 group= createTextEditGroup(FixMessages.CodeStyleFix_QualifyMethodWithDeclClass_description, cuRewrite);
443 } else {
444 group= createTextEditGroup(FixMessages.CodeStyleFix_QualifyFieldWithDeclClass_description, cuRewrite);
445 }
446 IJavaElement javaElement= fDeclaringClass.getJavaElement();
447 if (javaElement instanceof IType) {
448 Name qualifierName= compilationUnit.getAST().newName(((IType)javaElement).getElementName());
449 SimpleName simpleName= (SimpleName)rewrite.createMoveTarget(fName);
450 QualifiedName qualifiedName= compilationUnit.getAST().newQualifiedName(qualifierName, simpleName);
451 rewrite.replace(fName, qualifiedName, group);
452 }
453 }
454
455 }
456
457 private final static class ToStaticAccessOperation extends CompilationUnitRewriteOperation {
458
459 private final ITypeBinding fDeclaringTypeBinding;
460 private final Expression fQualifier;
461 private final HashMap<ASTNode, Block> fCreatedBlocks;
462
463 public ToStaticAccessOperation(ITypeBinding declaringTypeBinding, Expression qualifier, HashMap<ASTNode, Block> createdBlocks) {
464 fDeclaringTypeBinding= declaringTypeBinding;
465 fQualifier= qualifier;
466 fCreatedBlocks= createdBlocks;
467 }
468
469 public String getAccessorName() {
470 return fDeclaringTypeBinding.getName();
471 }
472
473 /**
474 * {@inheritDoc}
475 */
476 @Override
477 public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
478 TextEditGroup group= createTextEditGroup(FixMessages.CodeStyleFix_ChangeAccessUsingDeclaring_description, cuRewrite);
479
480 if (fQualifier instanceof MethodInvocation || fQualifier instanceof ClassInstanceCreation)
481 extractQualifier(fQualifier, cuRewrite, group);
482
483 Type type= importType(fDeclaringTypeBinding, fQualifier, cuRewrite.getImportRewrite(), cuRewrite.getRoot());
484 cuRewrite.getASTRewrite().replace(fQualifier, type, group);
485 }
486
487 private void extractQualifier(Expression qualifier, CompilationUnitRewrite cuRewrite, TextEditGroup group) {
488 Statement statement= ASTResolving.findParentStatement(qualifier);
489 if (statement == null)
490 return;
491
492 ASTRewrite astRewrite= cuRewrite.getASTRewrite();
493 AST ast= cuRewrite.getAST();
494
495 Expression expression= (Expression) astRewrite.createMoveTarget(qualifier);
496 ExpressionStatement newStatement= ast.newExpressionStatement(expression);
497
498 if (statement.getParent() instanceof Block) {
499 Block block= (Block) statement.getParent();
500 ListRewrite listRewrite= astRewrite.getListRewrite(block, Block.STATEMENTS_PROPERTY);
501
502 listRewrite.insertBefore(newStatement, statement, group);
503 } else {
504 Block block;
505 if (fCreatedBlocks.containsKey(statement.getParent())) {
506 block= fCreatedBlocks.get(statement.getParent());
507 } else {
508 block= ast.newBlock();
509 }
510
511 ListRewrite listRewrite= astRewrite.getListRewrite(block, Block.STATEMENTS_PROPERTY);
512
513 ASTNode lastStatement;
514 if (!fCreatedBlocks.containsKey(statement.getParent())) {
515 fCreatedBlocks.put(statement.getParent(), block);
516
517 lastStatement= astRewrite.createMoveTarget(statement);
518 listRewrite.insertLast(lastStatement, group);
519
520 ASTNode parent= statement.getParent();
521 astRewrite.set(parent, statement.getLocationInParent(), block, group);
522 } else {
523 List<?> rewrittenList= listRewrite.getRewrittenList();
524 lastStatement= (ASTNode) rewrittenList.get(rewrittenList.size() - 1);
525 }
526
527 listRewrite.insertBefore(newStatement, lastStatement, group);
528 }
529 }
530 }
531
532 public static CompilationUnitRewriteOperationsFix[] createNonStaticAccessFixes(CompilationUnit compilationUnit, IProblemLocation problem) {
533 if (!isNonStaticAccess(problem))
534 return null;
535
536 ToStaticAccessOperation operations[]= createToStaticAccessOperations(compilationUnit, new HashMap<ASTNode, Block>(), problem, false);
537 if (operations == null)
538 return null;
539
540 String label1= Messages.format(FixMessages.CodeStyleFix_ChangeAccessToStatic_description, operations[0].getAccessorName());
541 CompilationUnitRewriteOperationsFix fix1= new CompilationUnitRewriteOperationsFix(label1, compilationUnit, operations[0]);
542
543 if (operations.length > 1) {
544 String label2= Messages.format(FixMessages.CodeStyleFix_ChangeAccessToStaticUsingInstanceType_description, operations[1].getAccessorName());
545 CompilationUnitRewriteOperationsFix fix2= new CompilationUnitRewriteOperationsFix(label2, compilationUnit, operations[1]);
546 return new CompilationUnitRewriteOperationsFix[] {fix1, fix2};
547 }
548 return new CompilationUnitRewriteOperationsFix[] {fix1};
549 }
550
551 public static CompilationUnitRewriteOperationsFix createAddFieldQualifierFix(CompilationUnit compilationUnit, IProblemLocation problem) {
552 if (IProblem.UnqualifiedFieldAccess != problem.getProblemId())
553 return null;
554
555 AddThisQualifierOperation operation= getUnqualifiedFieldAccessResolveOperation(compilationUnit, problem);
556 if (operation == null)
557 return null;
558
559 String groupName= operation.getDescription();
560 return new CodeStyleFix(groupName, compilationUnit, new CompilationUnitRewriteOperation[] {operation});
561 }
562
563 public static CompilationUnitRewriteOperationsFix createIndirectAccessToStaticFix(CompilationUnit compilationUnit, IProblemLocation problem) {
564 if (!isIndirectStaticAccess(problem))
565 return null;
566
567 ToStaticAccessOperation operations[]= createToStaticAccessOperations(compilationUnit, new HashMap<ASTNode, Block>(), problem, false);
568 if (operations == null)
569 return null;
570
571 String label= Messages.format(FixMessages.CodeStyleFix_ChangeStaticAccess_description, operations[0].getAccessorName());
572 return new CodeStyleFix(label, compilationUnit, new CompilationUnitRewriteOperation[] {operations[0]});
573 }
574
575 public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit,
576 boolean addThisQualifier,
577 boolean changeNonStaticAccessToStatic,
578 boolean qualifyStaticFieldAccess,
579 boolean changeIndirectStaticAccessToDirect,
580 boolean qualifyMethodAccess,
581 boolean qualifyStaticMethodAccess,
582 boolean removeFieldQualifier,
583 boolean removeMethodQualifier) {
584
585 if (!addThisQualifier && !changeNonStaticAccessToStatic && !qualifyStaticFieldAccess && !changeIndirectStaticAccessToDirect && !qualifyMethodAccess && !qualifyStaticMethodAccess && !removeFieldQualifier && !removeMethodQualifier)
586 return null;
587
588 List<CompilationUnitRewriteOperation> operations= new ArrayList<CompilationUnitRewriteOperation>();
589 if (addThisQualifier || qualifyStaticFieldAccess || qualifyMethodAccess || qualifyStaticMethodAccess) {
590 CodeStyleVisitor codeStyleVisitor= new CodeStyleVisitor(compilationUnit, addThisQualifier, qualifyStaticFieldAccess, qualifyMethodAccess, qualifyStaticMethodAccess, operations);
591 compilationUnit.accept(codeStyleVisitor);
592 }
593
594 IProblem[] problems= compilationUnit.getProblems();
595 IProblemLocation[] locations= new IProblemLocation[problems.length];
596 for (int i= 0; i < problems.length; i++) {
597 locations[i]= new ProblemLocation(problems[i]);
598 }
599 addToStaticAccessOperations(compilationUnit, locations, changeNonStaticAccessToStatic, changeIndirectStaticAccessToDirect, operations);
600
601 if (removeFieldQualifier || removeMethodQualifier) {
602 ThisQualifierVisitor visitor= new ThisQualifierVisitor(removeFieldQualifier, removeMethodQualifier, compilationUnit, operations);
603 compilationUnit.accept(visitor);
604 }
605
606 if (operations.isEmpty())
607 return null;
608
609 CompilationUnitRewriteOperation[] operationsArray= operations.toArray(new CompilationUnitRewriteOperation[operations.size()]);
610 return new CodeStyleFix(FixMessages.CodeStyleFix_change_name, compilationUnit, operationsArray);
611 }
612
613 public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit, IProblemLocation[] problems,
614 boolean addThisQualifier,
615 boolean changeNonStaticAccessToStatic,
616 boolean changeIndirectStaticAccessToDirect) {
617
618 if (!addThisQualifier && !changeNonStaticAccessToStatic && !changeIndirectStaticAccessToDirect)
619 return null;
620
621 List<CompilationUnitRewriteOperation> operations= new ArrayList<CompilationUnitRewriteOperation>();
622 if (addThisQualifier) {
623 for (int i= 0; i < problems.length; i++) {
624 IProblemLocation problem= problems[i];
625 if (problem.getProblemId() == IProblem.UnqualifiedFieldAccess) {
626 AddThisQualifierOperation operation= getUnqualifiedFieldAccessResolveOperation(compilationUnit, problem);
627 if (operation != null)
628 operations.add(operation);
629 }
630 }
631 }
632
633 addToStaticAccessOperations(compilationUnit, problems, changeNonStaticAccessToStatic, changeIndirectStaticAccessToDirect, operations);
634
635 if (operations.isEmpty())
636 return null;
637
638 CompilationUnitRewriteOperation[] operationsArray= operations.toArray(new CompilationUnitRewriteOperation[operations.size()]);
639 return new CodeStyleFix(FixMessages.CodeStyleFix_change_name, compilationUnit, operationsArray);
640 }
641
642 private static void addToStaticAccessOperations(CompilationUnit compilationUnit, IProblemLocation[] problems, boolean changeNonStaticAccessToStatic, boolean changeIndirectStaticAccessToDirect, List<CompilationUnitRewriteOperation> result) {
643 if (!changeNonStaticAccessToStatic && !changeIndirectStaticAccessToDirect)
644 return;
645
646 HashMap<ASTNode, Block> createdBlocks= new HashMap<ASTNode, Block>();
647 for (int i= 0; i < problems.length; i++) {
648 IProblemLocation problem= problems[i];
649 boolean isNonStaticAccess= changeNonStaticAccessToStatic && isNonStaticAccess(problem);
650 boolean isIndirectStaticAccess= changeIndirectStaticAccessToDirect && isIndirectStaticAccess(problem);
651 if (isNonStaticAccess || isIndirectStaticAccess) {
652 ToStaticAccessOperation[] nonStaticAccessInformation= createToStaticAccessOperations(compilationUnit, createdBlocks, problem, true);
653 if (nonStaticAccessInformation != null) {
654 ToStaticAccessOperation op= nonStaticAccessInformation[0];
655
656 Expression qualifier= op.fQualifier;
657 if (!(qualifier instanceof MethodInvocation) || !isMethodArgument(qualifier)) {
658 result.add(op);
659 }
660 }
661 }
662 }
663 }
664
665 private static boolean isMethodArgument(Expression expression) {
666 ASTNode parent= expression;
667 while (parent instanceof Expression) {
668
669 if (parent.getLocationInParent() == MethodInvocation.ARGUMENTS_PROPERTY)
670 return true;
671
672 if (parent.getLocationInParent() == ConstructorInvocation.ARGUMENTS_PROPERTY)
673 return true;
674
675 parent= ((Expression) parent).getParent();
676 }
677
678 return false;
679 }
680
681 public static boolean isIndirectStaticAccess(IProblemLocation problem) {
682 return (problem.getProblemId() == IProblem.IndirectAccessToStaticField
683 || problem.getProblemId() == IProblem.IndirectAccessToStaticMethod);
684 }
685
686 public static boolean isNonStaticAccess(IProblemLocation problem) {
687 return (problem.getProblemId() == IProblem.NonStaticAccessToStaticField
688 || problem.getProblemId() == IProblem.NonStaticAccessToStaticMethod);
689 }
690
691 private static ToStaticAccessOperation[] createToStaticAccessOperations(CompilationUnit astRoot, HashMap<ASTNode, Block> createdBlocks, IProblemLocation problem, boolean conservative) {
692 ASTNode selectedNode= problem.getCoveringNode(astRoot);
693 if (selectedNode == null) {
694 return null;
695 }
696
697 Expression qualifier= null;
698 IBinding accessBinding= null;
699
700 if (selectedNode instanceof QualifiedName) {
701 QualifiedName name= (QualifiedName) selectedNode;
702 qualifier= name.getQualifier();
703 accessBinding= name.resolveBinding();
704 } else if (selectedNode instanceof SimpleName) {
705 ASTNode parent= selectedNode.getParent();
706 if (parent instanceof FieldAccess) {
707 FieldAccess fieldAccess= (FieldAccess) parent;
708 qualifier= fieldAccess.getExpression();
709 accessBinding= fieldAccess.getName().resolveBinding();
710 } else if (parent instanceof QualifiedName) {
711 QualifiedName qualifiedName= (QualifiedName) parent;
712 qualifier= qualifiedName.getQualifier();
713 accessBinding= qualifiedName.getName().resolveBinding();
714 }
715 } else if (selectedNode instanceof MethodInvocation) {
716 MethodInvocation methodInvocation= (MethodInvocation) selectedNode;
717 qualifier= methodInvocation.getExpression();
718 accessBinding= methodInvocation.getName().resolveBinding();
719 } else if (selectedNode instanceof FieldAccess) {
720 FieldAccess fieldAccess= (FieldAccess) selectedNode;
721 qualifier= fieldAccess.getExpression();
722 accessBinding= fieldAccess.getName().resolveBinding();
723 }
724
725 if (accessBinding != null && qualifier != null) {
726 if (conservative && ASTResolving.findParentStatement(qualifier) == null)
727 return null;
728
729 ToStaticAccessOperation declaring= null;
730 ITypeBinding declaringTypeBinding= getDeclaringTypeBinding(accessBinding);
731 if (declaringTypeBinding != null) {
732 declaringTypeBinding= declaringTypeBinding.getTypeDeclaration(); // use generic to avoid any type arguments
733
734 declaring= new ToStaticAccessOperation(declaringTypeBinding, qualifier, createdBlocks);
735 }
736 ToStaticAccessOperation instance= null;
737 ITypeBinding instanceTypeBinding= Bindings.normalizeTypeBinding(qualifier.resolveTypeBinding());
738 if (instanceTypeBinding != null) {
739 instanceTypeBinding= instanceTypeBinding.getTypeDeclaration(); // use generic to avoid any type arguments
740 if (instanceTypeBinding.getTypeDeclaration() != declaringTypeBinding) {
741 instance= new ToStaticAccessOperation(instanceTypeBinding, qualifier, createdBlocks);
742 }
743 }
744 if (declaring != null && instance != null) {
745 return new ToStaticAccessOperation[] {declaring, instance};
746 } else {
747 return new ToStaticAccessOperation[] {declaring};
748 }
749 }
750 return null;
751 }
752
753 private static ITypeBinding getDeclaringTypeBinding(IBinding accessBinding) {
754 if (accessBinding instanceof IMethodBinding) {
755 return ((IMethodBinding) accessBinding).getDeclaringClass();
756 } else if (accessBinding instanceof IVariableBinding) {
757 return ((IVariableBinding) accessBinding).getDeclaringClass();
758 }
759 return null;
760 }
761
762 private static AddThisQualifierOperation getUnqualifiedFieldAccessResolveOperation(CompilationUnit compilationUnit, IProblemLocation problem) {
763 SimpleName name= getName(compilationUnit, problem);
764 if (name == null)
765 return null;
766
767 IBinding binding= name.resolveBinding();
768 if (binding == null || binding.getKind() != IBinding.VARIABLE)
769 return null;
770
771 ImportRewrite imports= StubUtility.createImportRewrite(compilationUnit, true);
772
773 String replacement= getThisExpressionQualifier(((IVariableBinding) binding).getDeclaringClass(), imports, name);
774 if (replacement == null)
775 return null;
776
777 if (replacement.length() == 0)
778 replacement= null;
779
780 return new AddThisQualifierOperation(replacement, name);
781 }
782
783 private static String getThisExpressionQualifier(ITypeBinding declaringClass, ImportRewrite imports, SimpleName name) {
784 ITypeBinding parentType= Bindings.getBindingOfParentType(name);
785 ITypeBinding currType= parentType;
786 while (currType != null && !Bindings.isSuperType(declaringClass, currType)) {
787 currType= currType.getDeclaringClass();
788 }
789 if (currType == null) {
790 declaringClass= declaringClass.getTypeDeclaration();
791 currType= parentType;
792 while (currType != null && !Bindings.isSuperType(declaringClass, currType)) {
793 currType= currType.getDeclaringClass();
794 }
795 }
796 if (currType != parentType) {
797 if (currType == null)
798 return null;
799
800 if (currType.isAnonymous())
801 //If we access a field of a super class of an anonymous class
802 //then we can only qualify with 'this' but not with outer.this
803 //see bug 115277
804 return null;
805
806 return imports.addImport(currType);
807 } else {
808 return ""; //$NON-NLS-1$
809 }
810 }
811
812 private static SimpleName getName(CompilationUnit compilationUnit, IProblemLocation problem) {
813 ASTNode selectedNode= problem.getCoveringNode(compilationUnit);
814
815 while (selectedNode instanceof QualifiedName) {
816 selectedNode= ((QualifiedName) selectedNode).getQualifier();
817 }
818 if (!(selectedNode instanceof SimpleName)) {
819 return null;
820 }
821 return (SimpleName) selectedNode;
822 }
823
824 private CodeStyleFix(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation[] operations) {
825 super(name, compilationUnit, operations);
826 }
827
828}