1 14 package org.eclipse.jdt.internal.corext.refactoring.code; 15 16 import java.util.ArrayList ; 17 import java.util.HashMap ; 18 import java.util.List ; 19 import java.util.Map ; 20 import java.util.Set ; 21 import java.util.Stack ; 22 23 import org.eclipse.core.runtime.Assert; 24 import org.eclipse.core.runtime.IProgressMonitor; 25 import org.eclipse.core.runtime.SubProgressMonitor; 26 27 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 28 29 import org.eclipse.jdt.core.ICompilationUnit; 30 import org.eclipse.jdt.core.IJavaElement; 31 import org.eclipse.jdt.core.IMethod; 32 import org.eclipse.jdt.core.IType; 33 import org.eclipse.jdt.core.JavaModelException; 34 import org.eclipse.jdt.core.dom.AST; 35 import org.eclipse.jdt.core.dom.ASTNode; 36 import org.eclipse.jdt.core.dom.ASTVisitor; 37 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 38 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; 39 import org.eclipse.jdt.core.dom.BodyDeclaration; 40 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 41 import org.eclipse.jdt.core.dom.ConstructorInvocation; 42 import org.eclipse.jdt.core.dom.EnumDeclaration; 43 import org.eclipse.jdt.core.dom.FieldDeclaration; 44 import org.eclipse.jdt.core.dom.IBinding; 45 import org.eclipse.jdt.core.dom.IMethodBinding; 46 import org.eclipse.jdt.core.dom.ITypeBinding; 47 import org.eclipse.jdt.core.dom.Initializer; 48 import org.eclipse.jdt.core.dom.MethodDeclaration; 49 import org.eclipse.jdt.core.dom.MethodInvocation; 50 import org.eclipse.jdt.core.dom.SuperMethodInvocation; 51 import org.eclipse.jdt.core.dom.TypeDeclaration; 52 import org.eclipse.jdt.core.search.IJavaSearchConstants; 53 import org.eclipse.jdt.core.search.SearchMatch; 54 import org.eclipse.jdt.core.search.SearchPattern; 55 56 import org.eclipse.jdt.internal.corext.SourceRange; 57 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 58 import org.eclipse.jdt.internal.corext.refactoring.IRefactoringSearchRequestor; 59 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 60 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; 61 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2; 62 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; 63 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 64 import org.eclipse.jdt.internal.corext.util.SearchUtils; 65 66 69 abstract class TargetProvider { 70 71 public static final boolean BUG_CORE_130317= true; 73 protected SourceProvider fSourceProvider; 74 75 public void setSourceProvider(SourceProvider sourceProvider) { 77 Assert.isNotNull(sourceProvider); 78 fSourceProvider= sourceProvider; 79 } 80 81 public abstract void initialize(); 82 83 public abstract ICompilationUnit[] getAffectedCompilationUnits(RefactoringStatus status, IProgressMonitor pm) throws JavaModelException; 84 85 public abstract BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm); 86 87 public abstract ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm); 89 90 public abstract RefactoringStatus checkActivation() throws JavaModelException; 91 92 public abstract int getStatusSeverity(); 93 94 public boolean isSingle() { 95 return false; 96 } 97 98 public static TargetProvider create(ICompilationUnit cu, MethodInvocation invocation) { 99 return new SingleCallTargetProvider(cu, invocation); 100 } 101 102 public static TargetProvider create(ICompilationUnit cu, SuperMethodInvocation invocation) { 103 return new SingleCallTargetProvider(cu, invocation); 104 } 105 106 public static TargetProvider create(ICompilationUnit cu, ConstructorInvocation invocation) { 107 return new SingleCallTargetProvider(cu, invocation); 108 } 109 110 public static TargetProvider create(MethodDeclaration declaration) { 111 IMethodBinding method= declaration.resolveBinding(); 112 if (method == null) 113 return new ErrorTargetProvider(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.TargetProvider_method_declaration_not_unique)); 114 ITypeBinding type= method.getDeclaringClass(); 115 if (type.isLocal()) { 116 if (((IType) type.getJavaElement()).isBinary()) { 117 return new ErrorTargetProvider(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.TargetProvider_cannot_local_method_in_binary)); 118 } else { 119 IType declaringClassOfLocal= (IType) type.getDeclaringClass().getJavaElement(); 120 return new LocalTypeTargetProvider(declaringClassOfLocal.getCompilationUnit(), declaration); 121 } 122 } else { 123 return new MemberTypeTargetProvider(declaration.resolveBinding()); 124 } 125 } 126 127 public static TargetProvider create(IMethodBinding methodBinding) { 128 return new MemberTypeTargetProvider(methodBinding); 129 } 130 131 static void fastDone(IProgressMonitor pm) { 132 if (pm == null) 133 return; 134 pm.beginTask("", 1); pm.worked(1); 136 pm.done(); 137 } 138 139 static class ErrorTargetProvider extends TargetProvider { 140 private RefactoringStatus fErrorStatus; 141 public ErrorTargetProvider(RefactoringStatus status) { 142 fErrorStatus= status; 143 } 144 public RefactoringStatus checkActivation() throws JavaModelException { 145 return fErrorStatus; 146 } 147 public void initialize() { 148 } 149 public ICompilationUnit[] getAffectedCompilationUnits(RefactoringStatus status, IProgressMonitor pm) throws JavaModelException { 150 return null; 151 } 152 public BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm) { 153 return null; 154 } 155 public ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm) { 156 return null; 157 } 158 public int getStatusSeverity() { 159 return 0; 160 } 161 } 162 163 static class SingleCallTargetProvider extends TargetProvider { 164 private ICompilationUnit fCUnit; 165 private ASTNode fInvocation; 166 private boolean fIterated; 167 public SingleCallTargetProvider(ICompilationUnit cu, ASTNode invocation) { 168 Assert.isNotNull(cu); 169 Assert.isNotNull(invocation); 170 Assert.isTrue(Invocations.isInvocation(invocation)); 171 fCUnit= cu; 172 fInvocation= invocation; 173 } 174 public void initialize() { 175 fIterated= false; 176 } 177 public ICompilationUnit[] getAffectedCompilationUnits(RefactoringStatus status, IProgressMonitor pm) { 178 return new ICompilationUnit[] { fCUnit }; 179 } 180 public BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm) { 181 Assert.isTrue(unit == fCUnit); 182 if (fIterated) 183 return new BodyDeclaration[0]; 184 fastDone(pm); 185 return new BodyDeclaration[] { 186 (BodyDeclaration)ASTNodes.getParent(fInvocation, BodyDeclaration.class) 187 }; 188 } 189 190 public ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm) { 191 fastDone(pm); 192 if (fIterated) 193 return null; 194 fIterated= true; 195 return new ASTNode[] { fInvocation }; 196 } 197 public RefactoringStatus checkActivation() throws JavaModelException { 198 return new RefactoringStatus(); 199 } 200 public int getStatusSeverity() { 201 return RefactoringStatus.FATAL; 202 } 203 public boolean isSingle() { 204 return true; 205 } 206 } 207 208 private static class BodyData { 209 public BodyDeclaration fBody; 210 private List fInvocations; 211 public BodyData(BodyDeclaration declaration) { 212 fBody= declaration; 213 } 214 public void addInvocation(ASTNode node) { 215 if (fInvocations == null) 216 fInvocations= new ArrayList (2); 217 fInvocations.add(node); 218 } 219 public ASTNode[] getInvocations() { 220 return (ASTNode[])fInvocations.toArray(new ASTNode[fInvocations.size()]); 221 } 222 public boolean hasInvocations() { 223 return fInvocations != null && !fInvocations.isEmpty(); 224 } 225 public BodyDeclaration getDeclaration() { 226 return fBody; 227 } 228 } 229 230 private static class InvocationFinder extends ASTVisitor { 231 Map result= new HashMap (2); 232 Stack fBodies= new Stack (); 233 BodyData fCurrent; 234 private IMethodBinding fBinding; 235 public InvocationFinder(IMethodBinding binding) { 236 Assert.isNotNull(binding); 237 fBinding= binding.getMethodDeclaration(); 238 Assert.isNotNull(fBinding); 239 } 240 public boolean visit(MethodInvocation node) { 241 if (matches(node.getName().resolveBinding()) && fCurrent != null) { 242 fCurrent.addInvocation(node); 243 } 244 return true; 245 } 246 public boolean visit(SuperMethodInvocation node) { 247 if (matches(node.getName().resolveBinding()) && fCurrent != null) { 248 fCurrent.addInvocation(node); 249 } 250 return true; 251 } 252 public boolean visit(ConstructorInvocation node) { 253 if (matches(node.resolveConstructorBinding()) && fCurrent != null) { 254 fCurrent.addInvocation(node); 255 } 256 return true; 257 } 258 public boolean visit(ClassInstanceCreation node) { 259 if (matches(node.resolveConstructorBinding()) && fCurrent != null) { 260 fCurrent.addInvocation(node); 261 } 262 return true; 263 } 264 public boolean visit(TypeDeclaration node) { 265 return visitType(); 266 } 267 public void endVisit(TypeDeclaration node) { 268 endVisitType(); 269 } 270 public boolean visit(EnumDeclaration node) { 271 return visitType(); 272 } 273 public void endVisit(EnumDeclaration node) { 274 endVisitType(); 275 } 276 public boolean visit(AnnotationTypeDeclaration node) { 277 return visitType(); 278 } 279 public void endVisit(AnnotationTypeDeclaration node) { 280 endVisitType(); 281 } 282 private boolean visitType() { 283 fBodies.add(fCurrent); 284 fCurrent= null; 285 return true; 286 } 287 private void endVisitType() { 288 fCurrent= (BodyData)fBodies.remove(fBodies.size() - 1); 289 } 290 public boolean visit(FieldDeclaration node) { 291 fBodies.add(fCurrent); 292 fCurrent= new BodyData(node); 293 return true; 294 } 295 public void endVisit(FieldDeclaration node) { 296 if (fCurrent.hasInvocations()) { 297 result.put(node, fCurrent); 298 } 299 endVisitType(); 300 } 301 public boolean visit(MethodDeclaration node) { 302 fBodies.add(fCurrent); 303 fCurrent= new BodyData(node); 304 return true; 305 } 306 public void endVisit(MethodDeclaration node) { 307 if (fCurrent.hasInvocations()) { 308 result.put(node, fCurrent); 309 } 310 endVisitType(); 311 312 } 313 public boolean visit(Initializer node) { 314 fBodies.add(fCurrent); 315 fCurrent= new BodyData(node); 316 return true; 317 } 318 public void endVisit(Initializer node) { 319 if (fCurrent.hasInvocations()) { 320 result.put(node, fCurrent); 321 } 322 endVisitType(); 323 } 324 private boolean matches(IBinding binding) { 325 if (!(binding instanceof IMethodBinding)) 326 return false; 327 if (BUG_CORE_130317) 328 return fBinding.getKey().equals(((IMethodBinding)binding).getMethodDeclaration().getKey()); 329 else 330 return fBinding.isEqualTo(((IMethodBinding)binding).getMethodDeclaration()); 331 } 332 } 333 334 private static class LocalTypeTargetProvider extends TargetProvider { 335 private ICompilationUnit fCUnit; 336 private MethodDeclaration fDeclaration; 337 private Map fBodies; 338 public LocalTypeTargetProvider(ICompilationUnit unit, MethodDeclaration declaration) { 339 Assert.isNotNull(unit); 340 Assert.isNotNull(declaration); 341 fCUnit= unit; 342 fDeclaration= declaration; 343 } 344 public void initialize() { 345 InvocationFinder finder= new InvocationFinder(fDeclaration.resolveBinding()); 346 ASTNode type= ASTNodes.getParent(fDeclaration, AbstractTypeDeclaration.class); 347 type.accept(finder); 348 fBodies= finder.result; 349 } 350 public ICompilationUnit[] getAffectedCompilationUnits(RefactoringStatus status, IProgressMonitor pm) { 351 fastDone(pm); 352 return new ICompilationUnit[] { fCUnit }; 353 } 354 355 public BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm) { 356 Assert.isTrue(unit == fCUnit); 357 Set result= fBodies.keySet(); 358 fastDone(pm); 359 return (BodyDeclaration[])result.toArray(new BodyDeclaration[result.size()]); 360 } 361 362 public ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm) { 363 BodyData data= (BodyData)fBodies.get(declaration); 364 Assert.isNotNull(data); 365 fastDone(pm); 366 return data.getInvocations(); 367 } 368 369 public RefactoringStatus checkActivation() throws JavaModelException { 370 return new RefactoringStatus(); 371 } 372 373 public int getStatusSeverity() { 374 return RefactoringStatus.ERROR; 375 } 376 } 377 378 private static class MemberTypeTargetProvider extends TargetProvider { 379 private final IMethodBinding fMethodBinding; 380 private Map fCurrentBodies; 381 public MemberTypeTargetProvider(IMethodBinding methodBinding) { 382 Assert.isNotNull(methodBinding); 383 fMethodBinding= methodBinding; 384 } 385 public void initialize() { 386 } 388 389 public ICompilationUnit[] getAffectedCompilationUnits(final RefactoringStatus status, IProgressMonitor pm) throws JavaModelException { 390 IMethod method= (IMethod)fMethodBinding.getJavaElement(); 391 Assert.isTrue(method != null); 392 final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(method, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE)); 393 engine.setGranularity(RefactoringSearchEngine2.GRANULARITY_COMPILATION_UNIT); 394 engine.setFiltering(true, true); 395 engine.setScope(RefactoringScopeFactory.create(method)); 396 engine.setRequestor(new IRefactoringSearchRequestor() { 397 public SearchMatch acceptSearchMatch(SearchMatch match) { 398 if (match.isInsideDocComment()) 399 return null; 400 if (match.getAccuracy() == SearchMatch.A_INACCURATE) { 401 Object element= match.getElement(); 402 if (element instanceof IJavaElement) { 403 IJavaElement jElement= (IJavaElement)element; 404 ICompilationUnit unit= (ICompilationUnit)jElement.getAncestor(IJavaElement.COMPILATION_UNIT); 405 if (unit != null) { 406 status.addError(RefactoringCoreMessages.TargetProvider_inaccurate_match, 407 JavaStatusContext.create(unit, new SourceRange(match.getOffset(), match.getLength()))); 408 return null; 409 } 410 } 411 status.addError(RefactoringCoreMessages.TargetProvider_inaccurate_match); 412 return null; 413 } else { 414 return match; 415 } 416 } 417 }); 418 engine.searchPattern(new SubProgressMonitor(pm, 1)); 419 return engine.getAffectedCompilationUnits(); 420 } 421 422 public BodyDeclaration[] getAffectedBodyDeclarations(ICompilationUnit unit, IProgressMonitor pm) { 423 ASTNode root= new RefactoringASTParser(AST.JLS3).parse(unit, true); 424 InvocationFinder finder= new InvocationFinder(fMethodBinding); 425 root.accept(finder); 426 fCurrentBodies= finder.result; 427 Set result= fCurrentBodies.keySet(); 428 fastDone(pm); 429 return (BodyDeclaration[])result.toArray(new BodyDeclaration[result.size()]); 430 } 431 432 public ASTNode[] getInvocations(BodyDeclaration declaration, IProgressMonitor pm) { 433 BodyData data= (BodyData)fCurrentBodies.get(declaration); 434 Assert.isNotNull(data); 435 fastDone(pm); 436 return data.getInvocations(); 437 } 438 439 public RefactoringStatus checkActivation() throws JavaModelException { 440 return new RefactoringStatus(); 441 } 442 443 public int getStatusSeverity() { 444 return RefactoringStatus.ERROR; 445 } 446 } 447 } 448 | Popular Tags |