1 16 package org.eclipse.jdt.internal.corext.refactoring.code; 17 18 import java.util.ArrayList ; 19 import java.util.Collection ; 20 import java.util.HashMap ; 21 import java.util.Iterator ; 22 import java.util.List ; 23 import java.util.Map ; 24 25 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 26 27 import org.eclipse.jdt.core.ITypeRoot; 28 import org.eclipse.jdt.core.JavaModelException; 29 import org.eclipse.jdt.core.compiler.IProblem; 30 import org.eclipse.jdt.core.dom.ASTNode; 31 import org.eclipse.jdt.core.dom.ASTVisitor; 32 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 33 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; 34 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; 35 import org.eclipse.jdt.core.dom.ArrayAccess; 36 import org.eclipse.jdt.core.dom.Block; 37 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 38 import org.eclipse.jdt.core.dom.EnumDeclaration; 39 import org.eclipse.jdt.core.dom.Expression; 40 import org.eclipse.jdt.core.dom.FieldAccess; 41 import org.eclipse.jdt.core.dom.IBinding; 42 import org.eclipse.jdt.core.dom.IMethodBinding; 43 import org.eclipse.jdt.core.dom.ITypeBinding; 44 import org.eclipse.jdt.core.dom.IVariableBinding; 45 import org.eclipse.jdt.core.dom.MethodDeclaration; 46 import org.eclipse.jdt.core.dom.MethodInvocation; 47 import org.eclipse.jdt.core.dom.Modifier; 48 import org.eclipse.jdt.core.dom.Name; 49 import org.eclipse.jdt.core.dom.ReturnStatement; 50 import org.eclipse.jdt.core.dom.SimpleName; 51 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 52 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; 53 import org.eclipse.jdt.core.dom.SuperConstructorInvocation; 54 import org.eclipse.jdt.core.dom.SuperMethodInvocation; 55 import org.eclipse.jdt.core.dom.ThisExpression; 56 import org.eclipse.jdt.core.dom.TypeDeclaration; 57 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 58 59 import org.eclipse.jdt.internal.corext.codemanipulation.ImportReferencesCollector; 60 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 61 import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex; 62 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 63 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; 64 import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext; 65 import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo; 66 import org.eclipse.jdt.internal.corext.refactoring.code.flow.InOutFlowAnalyzer; 67 68 class SourceAnalyzer { 69 70 public static class NameData { 71 private String fName; 72 private List fReferences; 73 public NameData(String n) { 74 fName= n; 75 fReferences= new ArrayList (2); 76 } 77 public String getName() { 78 return fName; 79 } 80 public void addReference(SimpleName ref) { 81 fReferences.add(ref); 82 } 83 public List references() { 84 return fReferences; 85 } 86 } 87 88 private class ActivationAnalyzer extends ASTVisitor { 89 public RefactoringStatus status= new RefactoringStatus(); 90 private ASTNode fLastNode= getLastNode(); 91 private IMethodBinding fBinding= getBinding(); 92 public boolean visit(ReturnStatement node) { 93 if (node != fLastNode) { 94 fInterruptedExecutionFlow= true; 95 } 96 return true; 97 } 98 public boolean visit(EnumDeclaration node) { 99 return false; 100 } 101 public boolean visit(AnnotationTypeDeclaration node) { 102 return false; 103 } 104 public boolean visit(TypeDeclaration node) { 105 return false; 106 } 107 public boolean visit(AnonymousClassDeclaration node) { 108 return false; 109 } 110 public boolean visit(MethodInvocation node) { 111 IMethodBinding methodBinding= node.resolveMethodBinding(); 112 if (methodBinding != null) 113 methodBinding.getMethodDeclaration(); 114 if (fBinding != null && methodBinding != null && fBinding.isEqualTo(methodBinding) && !status.hasFatalError()) { 115 status.addFatalError(RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_recursive_call); 116 return false; 117 } 118 return true; 119 } 120 public boolean visit(SimpleName node) { 121 IBinding binding= node.resolveBinding(); 122 if (binding == null && !status.hasFatalError()) { 123 if (!ASTNodes.isLabel(node)) { 125 status.addFatalError( 126 RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_declaration_has_errors, 127 JavaStatusContext.create(fTypeRoot, fDeclaration)); 128 return false; 129 } 130 } 131 return true; 132 } 133 public boolean visit(ThisExpression node) { 134 if (node.getQualifier() != null) { 135 status.addFatalError( 136 RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_qualified_this_expressions, 137 JavaStatusContext.create(fTypeRoot, node)); 138 return false; 139 } 140 return true; 141 } 142 private ASTNode getLastNode() { 143 List statements= fDeclaration.getBody().statements(); 144 if (statements.size() == 0) 145 return null; 146 return (ASTNode)statements.get(statements.size() - 1); 147 } 148 private IMethodBinding getBinding() { 149 IMethodBinding result= fDeclaration.resolveBinding(); 150 if (result != null) 151 return result.getMethodDeclaration(); 152 return result; 153 } 154 } 155 156 private class UpdateCollector extends ASTVisitor { 157 private int fTypeCounter; 158 public boolean visit(TypeDeclaration node) { 159 return visitType(node); 160 } 161 public void endVisit(TypeDeclaration node) { 162 fTypeCounter--; 163 } 164 public boolean visit(EnumDeclaration node) { 165 return visitType(node); 166 } 167 public void endVisit(EnumDeclaration node) { 168 fTypeCounter--; 169 } 170 public boolean visit(AnnotationTypeDeclaration node) { 171 return visitType(node); 172 } 173 public void endVisit(AnnotationTypeDeclaration node) { 174 fTypeCounter--; 175 } 176 private boolean visitType(AbstractTypeDeclaration node) { 177 if (fTypeCounter++ == 0) { 178 addNameReference(node.getName()); 179 } 180 return true; 181 } 182 public boolean visit(AnonymousClassDeclaration node) { 183 fTypeCounter++; 184 return true; 185 } 186 public void endVisit(AnonymousClassDeclaration node) { 187 fTypeCounter--; 188 } 189 public boolean visit(FieldAccess node) { 190 node.getExpression().accept(this); 192 addReferencesToName(node.getName()); 193 return false; 194 } 195 public boolean visit(MethodDeclaration node) { 196 if (node.isConstructor()) { 197 AbstractTypeDeclaration decl= (AbstractTypeDeclaration) ASTNodes.getParent(node, AbstractTypeDeclaration.class); 198 NameData name= (NameData)fNames.get(decl.getName().resolveBinding()); 199 if (name != null) { 200 name.addReference(node.getName()); 201 } 202 } 203 return true; 204 } 205 public boolean visit(MethodInvocation node) { 206 if (fTypeCounter == 0) { 207 Expression receiver= node.getExpression(); 208 if (receiver == null && !isStaticallyImported(node.getName())) { 209 fImplicitReceivers.add(node); 210 } 211 } 212 return true; 213 } 214 public boolean visit(SuperMethodInvocation node) { 215 if (fTypeCounter == 0) { 216 fHasSuperMethodInvocation= true; 217 } 218 return true; 219 } 220 public boolean visist(SuperConstructorInvocation node) { 221 if (fTypeCounter == 0) { 222 fHasSuperMethodInvocation= true; 223 } 224 return true; 225 } 226 public boolean visit(ClassInstanceCreation node) { 227 if (fTypeCounter == 0) { 228 Expression receiver= node.getExpression(); 229 if (receiver == null) { 230 if (node.resolveTypeBinding().isLocal()) 231 fImplicitReceivers.add(node); 232 } 233 } 234 return true; 235 } 236 public boolean visit(SingleVariableDeclaration node) { 237 if (fTypeCounter == 0) 238 addNameReference(node.getName()); 239 return true; 240 } 241 public boolean visit(VariableDeclarationFragment node) { 242 if (fTypeCounter == 0) 243 addNameReference(node.getName()); 244 return true; 245 } 246 public boolean visit(SimpleName node) { 247 addReferencesToName(node); 248 IBinding binding= node.resolveBinding(); 249 if (binding instanceof ITypeBinding) { 250 ITypeBinding type= (ITypeBinding)binding; 251 if (type.isTypeVariable()) { 252 addTypeVariableReference(type, node); 253 } 254 } else if (binding instanceof IVariableBinding) { 255 IVariableBinding vb= (IVariableBinding)binding; 256 if (vb.isField() && ! isStaticallyImported(node)) { 257 Name topName= ASTNodes.getTopMostName(node); 258 if (node == topName || node == ASTNodes.getLeftMostSimpleName(topName)) { 259 StructuralPropertyDescriptor location= node.getLocationInParent(); 260 if (location != SingleVariableDeclaration.NAME_PROPERTY 261 && location != VariableDeclarationFragment.NAME_PROPERTY) { 262 fImplicitReceivers.add(node); 263 } 264 } 265 } else if (!vb.isField()) { 266 ParameterData data= (ParameterData)fParameters.get(binding); 268 if (data != null) { 269 ASTNode parent= node.getParent(); 270 if (parent instanceof Expression) { 271 int precedence= OperatorPrecedence.getValue((Expression)parent); 272 if (precedence != -1) { 273 data.setOperatorPrecedence(node, precedence); 274 } 275 } 276 } 277 } 278 } 279 return true; 280 } 281 public boolean visit(ThisExpression node) { 282 if (fTypeCounter == 0) { 283 fImplicitReceivers.add(node); 284 } 285 return true; 286 } 287 private void addReferencesToName(SimpleName node) { 288 IBinding binding= node.resolveBinding(); 289 ParameterData data= (ParameterData)fParameters.get(binding); 290 if (data != null) 291 data.addReference(node); 292 293 NameData name= (NameData)fNames.get(binding); 294 if (name != null) 295 name.addReference(node); 296 } 297 private void addNameReference(SimpleName name) { 298 fNames.put(name.resolveBinding(), new NameData(name.getIdentifier())); 299 } 300 private void addTypeVariableReference(ITypeBinding variable, SimpleName name) { 301 NameData data= (NameData)fTypeParameterMapping.get(variable); 302 if (data == null) { 303 data= (NameData)fMethodTypeParameterMapping.get(variable); 304 } 305 data.addReference(name); 306 } 307 private boolean isStaticallyImported(Name name) { 308 return fStaticsToImport.contains(name); 309 } 310 } 311 312 private class VarargAnalyzer extends ASTVisitor { 313 private IBinding fParameter; 314 public VarargAnalyzer(IBinding parameter) { 315 fParameter= parameter; 316 } 317 public boolean visit(ArrayAccess node) { 318 Expression array= node.getArray(); 319 if (array instanceof SimpleName && fParameter.isEqualTo(((SimpleName)array).resolveBinding())) { 320 fArrayAccess= true; 321 } 322 return true; 323 } 324 } 325 326 private ITypeRoot fTypeRoot; 327 private MethodDeclaration fDeclaration; 328 private Map fParameters; 329 private Map fNames; 330 private List fImplicitReceivers; 331 332 private boolean fArrayAccess; 333 private boolean fHasSuperMethodInvocation; 334 335 private List fTypesToImport; 336 private List fStaticsToImport; 337 338 private List fTypeParameterReferences; 339 private Map fTypeParameterMapping; 340 341 private List fMethodTypeParameterReferences; 342 private Map fMethodTypeParameterMapping; 343 344 private boolean fInterruptedExecutionFlow; 345 346 public SourceAnalyzer(ITypeRoot typeRoot, MethodDeclaration declaration) { 347 super(); 348 fTypeRoot= typeRoot; 349 fDeclaration= declaration; 350 } 351 352 public boolean isExecutionFlowInterrupted() { 353 return fInterruptedExecutionFlow; 354 } 355 356 public RefactoringStatus checkActivation() throws JavaModelException { 357 RefactoringStatus result= new RefactoringStatus(); 358 if (!fTypeRoot.isStructureKnown()) { 359 result.addFatalError( 360 RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_syntax_errors, 361 JavaStatusContext.create(fTypeRoot)); 362 return result; 363 } 364 IProblem[] problems= ASTNodes.getProblems(fDeclaration, ASTNodes.NODE_ONLY, ASTNodes.ERROR); 365 if (problems.length > 0) { 366 result.addFatalError( 367 RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_declaration_has_errors, 368 JavaStatusContext.create(fTypeRoot, fDeclaration)); 369 return result; 370 } 371 final IMethodBinding declarationBinding= fDeclaration.resolveBinding(); 372 if (declarationBinding != null) { 373 final int modifiers= declarationBinding.getModifiers(); 374 if (Modifier.isAbstract(modifiers)) { 375 result.addFatalError(RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_abstract_methods, JavaStatusContext.create(fTypeRoot, fDeclaration)); 376 return result; 377 } else if (Modifier.isNative(modifiers)) { 378 result.addFatalError(RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_native_methods, JavaStatusContext.create(fTypeRoot, fDeclaration)); 379 return result; 380 } 381 } else { 382 result.addFatalError(RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_methoddeclaration_has_errors, JavaStatusContext.create(fTypeRoot)); 383 return result; 384 } 385 ActivationAnalyzer analyzer= new ActivationAnalyzer(); 386 fDeclaration.accept(analyzer); 387 result.merge(analyzer.status); 388 if (!result.hasFatalError()) { 389 List parameters= fDeclaration.parameters(); 390 fParameters= new HashMap (parameters.size() * 2); 391 for (Iterator iter= parameters.iterator(); iter.hasNext();) { 392 SingleVariableDeclaration element= (SingleVariableDeclaration) iter.next(); 393 IVariableBinding binding= element.resolveBinding(); 394 if (binding == null) { 395 result.addFatalError( 396 RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_declaration_has_errors, 397 JavaStatusContext.create(fTypeRoot, fDeclaration)); 398 return result; 399 } 400 fParameters.put(binding, element.getProperty(ParameterData.PROPERTY)); 401 } 402 fNames= new HashMap (); 403 fImplicitReceivers= new ArrayList (2); 404 405 fTypeParameterReferences= new ArrayList (0); 406 fTypeParameterMapping= new HashMap (); 407 ITypeBinding declaringType= declarationBinding.getDeclaringClass(); 408 if (declaringType == null) { 409 result.addFatalError( 410 RefactoringCoreMessages.InlineMethodRefactoring_SourceAnalyzer_typedeclaration_has_errors, 411 JavaStatusContext.create(fTypeRoot)); 412 return result; 413 } 414 ITypeBinding[] typeParameters= declaringType.getTypeParameters(); 415 for (int i= 0; i < typeParameters.length; i++) { 416 NameData data= new NameData(typeParameters[i].getName()); 417 fTypeParameterReferences.add(data); 418 fTypeParameterMapping.put(typeParameters[i], data); 419 } 420 421 fMethodTypeParameterReferences= new ArrayList (0); 422 fMethodTypeParameterMapping= new HashMap (); 423 IMethodBinding method= declarationBinding; 424 typeParameters= method.getTypeParameters(); 425 for (int i= 0; i < typeParameters.length; i++) { 426 NameData data= new NameData(typeParameters[i].getName()); 427 fMethodTypeParameterReferences.add(data); 428 fMethodTypeParameterMapping.put(typeParameters[i], data); 429 } 430 431 } 432 if (fDeclaration.isVarargs()) { 433 List parameters= fDeclaration.parameters(); 434 VarargAnalyzer vAnalyzer= new VarargAnalyzer( 435 ((SingleVariableDeclaration)parameters.get(parameters.size() - 1)).getName().resolveBinding()); 436 fDeclaration.getBody().accept(vAnalyzer); 437 } 438 return result; 439 } 440 441 public void initialize() { 442 Block body= fDeclaration.getBody(); 443 fTypesToImport= new ArrayList (); 446 fStaticsToImport= new ArrayList (); 447 ImportReferencesCollector collector= new ImportReferencesCollector( 448 fTypeRoot.getJavaProject(), null, fTypesToImport, fStaticsToImport); 449 body.accept(collector); 450 451 body.accept(new UpdateCollector()); 453 454 int numberOfLocals= LocalVariableIndex.perform(fDeclaration); 455 FlowContext context= new FlowContext(0, numberOfLocals + 1); 456 context.setConsiderAccessMode(true); 457 context.setComputeMode(FlowContext.MERGE); 458 InOutFlowAnalyzer flowAnalyzer= new InOutFlowAnalyzer(context); 459 FlowInfo info= flowAnalyzer.perform(getStatements()); 460 461 for (Iterator iter= fDeclaration.parameters().iterator(); iter.hasNext();) { 462 SingleVariableDeclaration element= (SingleVariableDeclaration) iter.next(); 463 IVariableBinding binding= element.resolveBinding(); 464 ParameterData data= (ParameterData)element.getProperty(ParameterData.PROPERTY); 465 data.setAccessMode(info.getAccessMode(context, binding)); 466 } 467 } 468 469 public Collection getUsedNames() { 470 return fNames.values(); 471 } 472 473 public List getImplicitReceivers() { 474 return fImplicitReceivers; 475 } 476 477 public List getTypesToImport() { 478 return fTypesToImport; 479 } 480 481 public List getStaticsToImport() { 482 return fStaticsToImport; 483 } 484 485 public List getTypeParameterReferences() { 486 return fTypeParameterReferences; 487 } 488 489 public List getMethodTypeParameterReferences() { 490 return fMethodTypeParameterReferences; 491 } 492 493 public boolean hasArrayAccess() { 494 return fArrayAccess; 495 } 496 497 public boolean hasSuperMethodInvocation() { 498 return fHasSuperMethodInvocation; 499 } 500 501 private ASTNode[] getStatements() { 502 List statements= fDeclaration.getBody().statements(); 503 return (ASTNode[]) statements.toArray(new ASTNode[statements.size()]); 504 } 505 506 } 507 | Popular Tags |