1 11 12 package org.eclipse.jdt.internal.corext.refactoring; 13 14 import java.util.ArrayList ; 15 import java.util.Collections ; 16 import java.util.HashMap ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.Map ; 20 21 import org.eclipse.core.runtime.Assert; 22 import org.eclipse.core.runtime.CoreException; 23 import org.eclipse.core.runtime.IProgressMonitor; 24 import org.eclipse.core.runtime.NullProgressMonitor; 25 26 import org.eclipse.jface.text.BadLocationException; 27 import org.eclipse.jface.text.IDocument; 28 29 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 30 31 import org.eclipse.jdt.core.Flags; 32 import org.eclipse.jdt.core.ICompilationUnit; 33 import org.eclipse.jdt.core.IJavaProject; 34 import org.eclipse.jdt.core.IMethod; 35 import org.eclipse.jdt.core.IPackageFragment; 36 import org.eclipse.jdt.core.ISourceRange; 37 import org.eclipse.jdt.core.IType; 38 import org.eclipse.jdt.core.ITypeParameter; 39 import org.eclipse.jdt.core.JavaModelException; 40 import org.eclipse.jdt.core.WorkingCopyOwner; 41 import org.eclipse.jdt.core.compiler.IProblem; 42 import org.eclipse.jdt.core.dom.AST; 43 import org.eclipse.jdt.core.dom.ASTNode; 44 import org.eclipse.jdt.core.dom.ASTParser; 45 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 46 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; 47 import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; 48 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; 49 import org.eclipse.jdt.core.dom.ArrayType; 50 import org.eclipse.jdt.core.dom.Block; 51 import org.eclipse.jdt.core.dom.BodyDeclaration; 52 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 53 import org.eclipse.jdt.core.dom.CompilationUnit; 54 import org.eclipse.jdt.core.dom.EnumDeclaration; 55 import org.eclipse.jdt.core.dom.IExtendedModifier; 56 import org.eclipse.jdt.core.dom.ITypeBinding; 57 import org.eclipse.jdt.core.dom.ImportDeclaration; 58 import org.eclipse.jdt.core.dom.MethodDeclaration; 59 import org.eclipse.jdt.core.dom.Modifier; 60 import org.eclipse.jdt.core.dom.Name; 61 import org.eclipse.jdt.core.dom.PackageDeclaration; 62 import org.eclipse.jdt.core.dom.PrimitiveType; 63 import org.eclipse.jdt.core.dom.QualifiedName; 64 import org.eclipse.jdt.core.dom.QualifiedType; 65 import org.eclipse.jdt.core.dom.SimpleName; 66 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 67 import org.eclipse.jdt.core.dom.Type; 68 import org.eclipse.jdt.core.dom.TypeDeclaration; 69 import org.eclipse.jdt.core.dom.TypeParameter; 70 import org.eclipse.jdt.core.search.IJavaSearchConstants; 71 import org.eclipse.jdt.core.search.IJavaSearchScope; 72 import org.eclipse.jdt.core.search.SearchEngine; 73 import org.eclipse.jdt.core.search.SearchPattern; 74 import org.eclipse.jdt.core.search.TypeNameMatch; 75 76 import org.eclipse.jdt.internal.corext.dom.ASTFlattener; 77 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 78 import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor; 79 import org.eclipse.jdt.internal.corext.dom.NodeFinder; 80 import org.eclipse.jdt.internal.corext.dom.Selection; 81 import org.eclipse.jdt.internal.corext.dom.SelectionAnalyzer; 82 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 83 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringFileBuffers; 84 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 85 import org.eclipse.jdt.internal.corext.util.Messages; 86 import org.eclipse.jdt.internal.corext.util.TypeNameMatchCollector; 87 88 import org.eclipse.jdt.internal.ui.JavaPlugin; 89 import org.eclipse.jdt.internal.ui.refactoring.contentassist.JavaTypeCompletionProcessor; 90 91 public class TypeContextChecker { 92 93 public interface IProblemVerifier { 94 95 boolean isError(IProblem problem, ASTNode node); 96 97 } 98 99 private static class MethodTypesChecker { 100 101 private static final String METHOD_NAME= "__$$__"; 103 private final IMethod fMethod; 104 private final StubTypeContext fStubTypeContext; 105 private final List fParameterInfos; 106 private final ReturnTypeInfo fReturnTypeInfo; 107 108 private final IProblemVerifier fProblemVerifier; 109 110 public MethodTypesChecker(IMethod method, StubTypeContext stubTypeContext, List parameterInfos, ReturnTypeInfo returnTypeInfo, IProblemVerifier problemVerifier) { 111 fMethod= method; 112 fStubTypeContext= stubTypeContext; 113 fParameterInfos= parameterInfos; 114 fReturnTypeInfo= returnTypeInfo; 115 fProblemVerifier= problemVerifier; 116 } 117 118 public RefactoringStatus[] checkAndResolveMethodTypes() throws CoreException { 119 RefactoringStatus[] results= new MethodTypesSyntaxChecker(fMethod, fParameterInfos, fReturnTypeInfo).checkSyntax(); 120 for (int i= 0; i < results.length; i++) 121 if (results[i] != null && results[i].hasFatalError()) 122 return results; 123 124 int parameterCount= fParameterInfos.size(); 125 String [] types= new String [parameterCount + 1]; 126 for (int i= 0; i < parameterCount; i++) 127 types[i]= ParameterInfo.stripEllipsis(((ParameterInfo) fParameterInfos.get(i)).getNewTypeName()); 128 types[parameterCount]= fReturnTypeInfo.getNewTypeName(); 129 RefactoringStatus[] semanticsResults= new RefactoringStatus[parameterCount + 1]; 130 ITypeBinding[] typeBindings= resolveBindings(types, semanticsResults, true); 131 132 boolean needsSecondPass= false; 133 for (int i= 0; i < types.length; i++) 134 if (typeBindings[i] == null || ! semanticsResults[i].isOK()) 135 needsSecondPass= true; 136 137 RefactoringStatus[] semanticsResults2= new RefactoringStatus[parameterCount + 1]; 138 if (needsSecondPass) 139 typeBindings= resolveBindings(types, semanticsResults2, false); 140 141 for (int i= 0; i < fParameterInfos.size(); i++) { 142 ParameterInfo parameterInfo= (ParameterInfo) fParameterInfos.get(i); 143 if (parameterInfo.getOldTypeBinding() != null && ! parameterInfo.isTypeNameChanged()) { 144 parameterInfo.setNewTypeBinding(parameterInfo.getOldTypeBinding()); 145 } else { 146 parameterInfo.setNewTypeBinding(typeBindings[i]); 147 if (typeBindings[i] == null || (needsSecondPass && ! semanticsResults2[i].isOK())) { 148 if (results[i] == null) 149 results[i]= semanticsResults2[i]; 150 else 151 results[i].merge(semanticsResults2[i]); 152 } 153 } 154 } 155 fReturnTypeInfo.setNewTypeBinding(typeBindings[fParameterInfos.size()]); 156 if (typeBindings[parameterCount] == null || (needsSecondPass && ! semanticsResults2[parameterCount].isOK())) { 157 if (results[parameterCount] == null) 158 results[parameterCount]= semanticsResults2[parameterCount]; 159 else 160 results[parameterCount].merge(semanticsResults2[parameterCount]); 161 } 162 163 return results; 164 } 165 166 private ITypeBinding[] resolveBindings(String [] types, RefactoringStatus[] results, boolean firstPass) throws CoreException { 167 int parameterCount= types.length - 1; 169 ITypeBinding[] typeBindings= new ITypeBinding[types.length]; 170 171 StringBuffer cuString= new StringBuffer (); 172 cuString.append(fStubTypeContext.getBeforeString()); 173 int offsetBeforeMethodName= appendMethodDeclaration(cuString, types, parameterCount); 174 cuString.append(fStubTypeContext.getAfterString()); 175 176 ICompilationUnit wc= fMethod.getCompilationUnit().getWorkingCopy(new WorkingCopyOwner() {}, new NullProgressMonitor()); 178 try { 179 wc.getBuffer().setContents(cuString.toString()); 180 CompilationUnit compilationUnit= new RefactoringASTParser(AST.JLS3).parse(wc, true); 181 ASTNode method= NodeFinder.perform(compilationUnit, offsetBeforeMethodName, METHOD_NAME.length()).getParent(); 182 Type[] typeNodes= new Type[types.length]; 183 if (method instanceof MethodDeclaration) { 184 MethodDeclaration methodDeclaration= (MethodDeclaration) method; 185 typeNodes[parameterCount]= methodDeclaration.getReturnType2(); 186 List parameters= methodDeclaration.parameters(); 187 for (int i= 0; i < parameterCount; i++) 188 typeNodes[i]= ((SingleVariableDeclaration) parameters.get(i)).getType(); 189 190 } else if (method instanceof AnnotationTypeMemberDeclaration) { 191 typeNodes[0]= ((AnnotationTypeMemberDeclaration) method).getType(); 192 } 193 194 for (int i= 0; i < types.length; i++) { 195 Type type= typeNodes[i]; 196 if (type == null) { 197 String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_couldNotResolveType, types[i]); 198 results[i]= RefactoringStatus.createErrorStatus(msg); 199 continue; 200 } 201 results[i]= new RefactoringStatus(); 202 IProblem[] problems= ASTNodes.getProblems(type, ASTNodes.NODE_ONLY, ASTNodes.PROBLEMS); 203 if (problems.length > 0) { 204 for (int p= 0; p < problems.length; p++) 205 if (isError(problems[p], type)) 206 results[i].addError(problems[p].getMessage()); 207 } 208 typeBindings[i]= type.resolveBinding(); 209 typeBindings[i]= handleBug84585(typeBindings[i]); 210 if (firstPass && typeBindings[i] == null) 211 types[i]= qualifyTypes(type, results[i]); 212 } 213 return typeBindings; 214 } finally { 215 wc.discardWorkingCopy(); 216 } 217 } 218 219 private boolean isError(IProblem problem, Type type) { 220 if (fProblemVerifier != null) 221 return fProblemVerifier.isError(problem, type); 222 return true; 223 } 224 225 private int appendMethodDeclaration(StringBuffer cuString, String [] types, int parameterCount) throws JavaModelException { 226 if (Flags.isStatic(fMethod.getFlags())) 227 cuString.append("static "); 229 ITypeParameter[] methodTypeParameters= fMethod.getTypeParameters(); 230 if (methodTypeParameters.length != 0) { 231 cuString.append('<'); 232 for (int i= 0; i < methodTypeParameters.length; i++) { 233 ITypeParameter typeParameter= methodTypeParameters[i]; 234 if (i > 0) 235 cuString.append(','); 236 cuString.append(typeParameter.getElementName()); 237 } 238 cuString.append("> "); } 240 241 cuString.append(types[parameterCount]).append(' '); 242 int offsetBeforeMethodName= cuString.length(); 243 cuString.append(METHOD_NAME).append('('); 244 for (int i= 0; i < parameterCount; i++) { 245 if (i > 0) 246 cuString.append(','); 247 cuString.append(types[i]).append(" p").append(i); } 249 cuString.append(");"); 251 return offsetBeforeMethodName; 252 } 253 254 private String qualifyTypes(Type type, final RefactoringStatus result) throws CoreException { 255 class NestedException extends RuntimeException { 256 private static final long serialVersionUID= 1L; 257 NestedException(CoreException e) { 258 super(e); 259 } 260 } 261 ASTFlattener flattener= new ASTFlattener() { 262 public boolean visit(SimpleName node) { 263 appendResolved(node.getIdentifier()); 264 return false; 265 } 266 public boolean visit(QualifiedName node) { 267 appendResolved(node.getFullyQualifiedName()); 268 return false; 269 } 270 public boolean visit(QualifiedType node) { 271 appendResolved(ASTNodes.asString(node)); 272 return false; 273 } 274 private void appendResolved(String typeName) { 275 String resolvedType; 276 try { 277 resolvedType= resolveType(typeName, result, fMethod.getDeclaringType(), null); 278 } catch (CoreException e) { 279 throw new NestedException(e); 280 } 281 this.fBuffer.append(resolvedType); 282 } 283 }; 284 try { 285 type.accept(flattener); 286 } catch (NestedException e) { 287 throw ((CoreException) e.getCause()); 288 } 289 return flattener.getResult(); 290 } 291 292 private static String resolveType(String elementTypeName, RefactoringStatus status, IType declaringType, IProgressMonitor pm) throws CoreException { 293 String [][] fqns= declaringType.resolveType(elementTypeName); 294 if (fqns != null) { 295 if (fqns.length == 1) { 296 return JavaModelUtil.concatenateName(fqns[0][0], fqns[0][1]); 297 } else if (fqns.length > 1){ 298 String [] keys= {elementTypeName, String.valueOf(fqns.length)}; 299 String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_ambiguous, keys); 300 status.addError(msg); 301 return elementTypeName; 302 } 303 } 304 305 List typeRefsFound= findTypeInfos(elementTypeName, declaringType, pm); 306 if (typeRefsFound.size() == 0){ 307 String [] keys= {elementTypeName}; 308 String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_not_unique, keys); 309 status.addError(msg); 310 return elementTypeName; 311 } else if (typeRefsFound.size() == 1){ 312 TypeNameMatch typeInfo= (TypeNameMatch) typeRefsFound.get(0); 313 return typeInfo.getFullyQualifiedName(); 314 } else { 315 Assert.isTrue(typeRefsFound.size() > 1); 316 String [] keys= {elementTypeName, String.valueOf(typeRefsFound.size())}; 317 String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_ambiguous, keys); 318 status.addError(msg); 319 return elementTypeName; 320 } 321 } 322 323 private static List findTypeInfos(String typeName, IType contextType, IProgressMonitor pm) throws JavaModelException { 324 IJavaSearchScope scope= SearchEngine.createJavaSearchScope(new IJavaProject[]{contextType.getJavaProject()}, true); 325 IPackageFragment currPackage= contextType.getPackageFragment(); 326 ArrayList collectedInfos= new ArrayList (); 327 TypeNameMatchCollector requestor= new TypeNameMatchCollector(collectedInfos); 328 int matchMode= SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE; 329 new SearchEngine().searchAllTypeNames(null, matchMode, typeName.toCharArray(), matchMode, IJavaSearchConstants.TYPE, scope, requestor, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, pm); 330 331 List result= new ArrayList (); 332 for (Iterator iter= collectedInfos.iterator(); iter.hasNext();) { 333 TypeNameMatch curr= (TypeNameMatch) iter.next(); 334 IType type= curr.getType(); 335 if (type != null) { 336 boolean visible=true; 337 try { 338 visible= JavaModelUtil.isVisible(type, currPackage); 339 } catch (JavaModelException e) { 340 } 342 if (visible) { 343 result.add(curr); 344 } 345 } 346 } 347 return result; 348 } 349 350 } 351 352 private static class MethodTypesSyntaxChecker { 353 354 private final IMethod fMethod; 355 private final List fParameterInfos; 356 private final ReturnTypeInfo fReturnTypeInfo; 357 358 public MethodTypesSyntaxChecker(IMethod method, List parameterInfos, ReturnTypeInfo returnTypeInfo) { 359 fMethod= method; 360 fParameterInfos= parameterInfos; 361 fReturnTypeInfo= returnTypeInfo; 362 } 363 364 public RefactoringStatus[] checkSyntax() { 365 int parameterCount= fParameterInfos.size(); 366 RefactoringStatus[] results= new RefactoringStatus[parameterCount + 1]; 367 results[parameterCount]= checkReturnTypeSyntax(); 368 for (int i= 0; i < parameterCount; i++) { 369 ParameterInfo info= (ParameterInfo) fParameterInfos.get(i); 370 results[i]= checkParameterTypeSyntax(info); 371 } 372 return results; 373 } 374 375 private RefactoringStatus checkParameterTypeSyntax(ParameterInfo info) { 376 if (! info.isAdded() && ! info.isTypeNameChanged()) 377 return null; 378 return TypeContextChecker.checkParameterTypeSyntax(info.getNewTypeName(), fMethod.getJavaProject()); 379 } 380 381 private RefactoringStatus checkReturnTypeSyntax() { 382 String newTypeName= fReturnTypeInfo.getNewTypeName(); 383 if ("".equals(newTypeName.trim())) { String msg= RefactoringCoreMessages.TypeContextChecker_return_type_not_empty; 385 return RefactoringStatus.createFatalErrorStatus(msg); 386 } 387 List problemsCollector= new ArrayList (0); 388 Type parsedType= parseType(newTypeName, fMethod.getJavaProject(), problemsCollector); 389 if (parsedType == null) { 390 String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_invalid_return_type, new String []{newTypeName}); 391 return RefactoringStatus.createFatalErrorStatus(msg); 392 } 393 if (problemsCollector.size() == 0) 394 return null; 395 396 RefactoringStatus result= new RefactoringStatus(); 397 for (Iterator iter= problemsCollector.iterator(); iter.hasNext();) { 398 String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_invalid_return_type_syntax, new String []{newTypeName, (String ) iter.next()}); 399 result.addError(msg); 400 } 401 return result; 402 } 403 404 private static boolean isVoidArrayType(Type type){ 405 if (! type.isArrayType()) 406 return false; 407 408 ArrayType arrayType= (ArrayType)type; 409 if (! arrayType.getComponentType().isPrimitiveType()) 410 return false; 411 PrimitiveType primitiveType= (PrimitiveType)arrayType.getComponentType(); 412 return (primitiveType.getPrimitiveTypeCode() == PrimitiveType.VOID); 413 } 414 415 } 416 417 private static Type parseType(String typeString, IJavaProject javaProject, List problemsCollector) { 418 if ("".equals(typeString.trim())) return null; 420 if (! typeString.trim().equals(typeString)) 421 return null; 422 423 StringBuffer cuBuff= new StringBuffer (); 424 cuBuff.append("interface A{"); int offset= cuBuff.length(); 426 cuBuff.append(typeString).append(" m();}"); 428 ASTParser p= ASTParser.newParser(AST.JLS3); 429 p.setSource(cuBuff.toString().toCharArray()); 430 p.setProject(javaProject); 431 CompilationUnit cu= (CompilationUnit) p.createAST(null); 432 Selection selection= Selection.createFromStartLength(offset, typeString.length()); 433 SelectionAnalyzer analyzer= new SelectionAnalyzer(selection, false); 434 cu.accept(analyzer); 435 ASTNode selected= analyzer.getFirstSelectedNode(); 436 if (!(selected instanceof Type)) 437 return null; 438 Type type= (Type)selected; 439 if (MethodTypesSyntaxChecker.isVoidArrayType(type)) 440 return null; 441 IProblem[] problems= ASTNodes.getProblems(type, ASTNodes.NODE_ONLY, ASTNodes.PROBLEMS); 442 if (problems.length > 0) { 443 for (int i= 0; i < problems.length; i++) 444 problemsCollector.add(problems[i].getMessage()); 445 } 446 447 String typeNodeRange= cuBuff.substring(type.getStartPosition(), ASTNodes.getExclusiveEnd(type)); 448 if (typeString.equals(typeNodeRange)) 449 return type; 450 else 451 return null; 452 } 453 454 private static ITypeBinding handleBug84585(ITypeBinding typeBinding) { 455 if (typeBinding == null) 456 return null; 457 else if (typeBinding.isGenericType() && ! typeBinding.isRawType() && ! typeBinding.isParameterizedType()) 458 return null; else 460 return typeBinding; 461 } 462 463 public static RefactoringStatus[] checkAndResolveMethodTypes(IMethod method, StubTypeContext stubTypeContext, List parameterInfos, ReturnTypeInfo returnTypeInfo, IProblemVerifier problemVerifier) throws CoreException { 464 MethodTypesChecker checker= new MethodTypesChecker(method, stubTypeContext, parameterInfos, returnTypeInfo, problemVerifier); 465 return checker.checkAndResolveMethodTypes(); 466 } 467 468 public static RefactoringStatus[] checkMethodTypesSyntax(IMethod method, List parameterInfos, ReturnTypeInfo returnTypeInfo) { 469 MethodTypesSyntaxChecker checker= new MethodTypesSyntaxChecker(method, parameterInfos, returnTypeInfo); 470 return checker.checkSyntax(); 471 } 472 473 public static RefactoringStatus checkParameterTypeSyntax(String type, IJavaProject project) { 474 String newTypeName= ParameterInfo.stripEllipsis(type.trim()).trim(); 475 476 if ("".equals(newTypeName.trim())){ String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_parameter_type, new String []{type}); 478 return RefactoringStatus.createFatalErrorStatus(msg); 479 } 480 481 if (ParameterInfo.isVarargs(type) && ! JavaModelUtil.is50OrHigher(project)) { 482 String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_no_vararg_below_50, new String []{type}); 483 return RefactoringStatus.createFatalErrorStatus(msg); 484 } 485 486 List problemsCollector= new ArrayList (0); 487 Type parsedType= parseType(newTypeName, project, problemsCollector); 488 boolean valid= parsedType != null; 489 if (valid && parsedType instanceof PrimitiveType) 490 valid= ! PrimitiveType.VOID.equals(((PrimitiveType) parsedType).getPrimitiveTypeCode()); 491 if (! valid) { 492 String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_invalid_type_name, new String []{newTypeName}); 493 return RefactoringStatus.createFatalErrorStatus(msg); 494 } 495 if (problemsCollector.size() == 0) 496 return null; 497 498 RefactoringStatus result= new RefactoringStatus(); 499 for (Iterator iter= problemsCollector.iterator(); iter.hasNext();) { 500 String msg= Messages.format(RefactoringCoreMessages.TypeContextChecker_invalid_type_syntax, new String []{newTypeName, (String ) iter.next()}); 501 result.addError(msg); 502 } 503 return result; 504 } 505 506 public static StubTypeContext createStubTypeContext(ICompilationUnit cu, CompilationUnit root, int focalPosition) throws CoreException { 507 IDocument document= RefactoringFileBuffers.acquire(cu).getDocument(); 508 try { 509 StringBuffer bufBefore= new StringBuffer (); 510 StringBuffer bufAfter= new StringBuffer (); 511 512 int introEnd= 0; 513 PackageDeclaration pack= root.getPackage(); 514 if (pack != null) 515 introEnd= pack.getStartPosition() + pack.getLength(); 516 List imports= root.imports(); 517 if (imports.size() > 0) { 518 ImportDeclaration lastImport= (ImportDeclaration) imports.get(imports.size() - 1); 519 introEnd= lastImport.getStartPosition() + lastImport.getLength(); 520 } 521 try { 522 bufBefore.append(document.get(0, introEnd)); 523 } catch (BadLocationException e) { 524 throw new RuntimeException (e); } 526 527 fillWithTypeStubs(bufBefore, bufAfter, focalPosition, root.types()); 528 bufBefore.append(' '); 529 bufAfter.insert(0, ' '); 530 return new StubTypeContext(cu, bufBefore.toString(), bufAfter.toString()); 531 532 } finally { 533 RefactoringFileBuffers.release(cu); 534 } 535 } 536 537 private static void fillWithTypeStubs(final StringBuffer bufBefore, final StringBuffer bufAfter, final int focalPosition, List types) { 538 StringBuffer buf; 539 for (Iterator iter= types.iterator(); iter.hasNext();) { 540 BodyDeclaration bodyDeclaration= (BodyDeclaration) iter.next(); 541 if (! (bodyDeclaration instanceof AbstractTypeDeclaration)) { 542 if (! (bodyDeclaration instanceof MethodDeclaration)) 544 continue; 545 int bodyStart= bodyDeclaration.getStartPosition(); 546 int bodyEnd= bodyDeclaration.getStartPosition() + bodyDeclaration.getLength(); 547 if (! (bodyStart < focalPosition && focalPosition < bodyEnd)) 548 continue; 549 MethodDeclaration methodDeclaration= (MethodDeclaration) bodyDeclaration; 550 buf= bufBefore; 551 appendModifiers(buf, methodDeclaration.modifiers()); 552 appendTypeParameters(buf, methodDeclaration.typeParameters()); 553 buf.append(" void "); buf.append(methodDeclaration.getName().getIdentifier()); 555 buf.append("(){\n"); Block body= methodDeclaration.getBody(); 557 body.accept(new HierarchicalASTVisitor() { 558 public boolean visit(AbstractTypeDeclaration node) { 559 fillWithTypeStubs(bufBefore, bufAfter, focalPosition, Collections.singletonList(node)); 560 return false; 561 } 562 public boolean visit(ClassInstanceCreation node) { 563 AnonymousClassDeclaration anonDecl= node.getAnonymousClassDeclaration(); 564 if (anonDecl == null) 565 return false; 566 int anonStart= anonDecl.getStartPosition(); 567 int anonEnd= anonDecl.getStartPosition() + anonDecl.getLength(); 568 if (! (anonStart < focalPosition && focalPosition < anonEnd)) 569 return false; 570 bufBefore.append(" new "); bufBefore.append(node.getType().toString()); 572 bufBefore.append("(){\n"); fillWithTypeStubs(bufBefore, bufAfter, focalPosition, anonDecl.bodyDeclarations()); 574 bufAfter.insert(0, "};\n"); return false; 576 } 577 }); 578 buf= bufAfter; 579 buf.append("}\n"); continue; 581 } 582 583 AbstractTypeDeclaration decl= (AbstractTypeDeclaration) bodyDeclaration; 584 buf= decl.getStartPosition() < focalPosition ? bufBefore : bufAfter; 585 appendModifiers(buf, decl.modifiers()); 586 587 if (decl instanceof TypeDeclaration) { 588 TypeDeclaration type= (TypeDeclaration) decl; 589 buf.append(type.isInterface() ? "interface " : "class "); buf.append(type.getName().getIdentifier()); 591 appendTypeParameters(buf, type.typeParameters()); 592 if (type.getSuperclassType() != null) { 593 buf.append(" extends "); buf.append(ASTNodes.asString(type.getSuperclassType())); 595 } 596 List superInterfaces= type.superInterfaceTypes(); 597 appendSuperInterfaces(buf, superInterfaces); 598 599 } else if (decl instanceof AnnotationTypeDeclaration) { 600 AnnotationTypeDeclaration annotation= (AnnotationTypeDeclaration) decl; 601 buf.append("@interface "); buf.append(annotation.getName().getIdentifier()); 603 604 } else if (decl instanceof EnumDeclaration) { 605 EnumDeclaration enumDecl= (EnumDeclaration) decl; 606 buf.append("enum "); buf.append(enumDecl.getName().getIdentifier()); 608 List superInterfaces= enumDecl.superInterfaceTypes(); 609 appendSuperInterfaces(buf, superInterfaces); 610 } 611 612 buf.append("{\n"); if (decl instanceof EnumDeclaration) 614 buf.append(";\n"); fillWithTypeStubs(bufBefore, bufAfter, focalPosition, decl.bodyDeclarations()); 616 buf= decl.getStartPosition() + decl.getLength() < focalPosition ? bufBefore : bufAfter; 617 buf.append("}\n"); } 619 } 620 621 private static void appendTypeParameters(StringBuffer buf, List typeParameters) { 622 int typeParametersCount= typeParameters.size(); 623 if (typeParametersCount > 0) { 624 buf.append('<'); 625 for (int i= 0; i < typeParametersCount; i++) { 626 TypeParameter typeParameter= (TypeParameter) typeParameters.get(i); 627 buf.append(ASTNodes.asString(typeParameter)); 628 if (i < typeParametersCount - 1) 629 buf.append(','); 630 } 631 } 632 } 633 634 private static void appendModifiers(StringBuffer buf, List modifiers) { 635 for (Iterator iterator= modifiers.iterator(); iterator.hasNext();) { 636 IExtendedModifier extendedModifier= (IExtendedModifier) iterator.next(); 637 if (extendedModifier.isModifier()) { 638 Modifier modifier= (Modifier) extendedModifier; 639 buf.append(modifier.getKeyword().toString()).append(' '); 640 } 641 } 642 } 643 644 private static void appendSuperInterfaces(StringBuffer buf, List superInterfaces) { 645 int superInterfaceCount= superInterfaces.size(); 646 if (superInterfaceCount > 0) { 647 buf.append(" implements "); for (int i= 0; i < superInterfaceCount; i++) { 649 Type superInterface= (Type) superInterfaces.get(i); 650 buf.append(ASTNodes.asString(superInterface)); 651 if (i < superInterfaceCount - 1) 652 buf.append(','); 653 } 654 } 655 } 656 657 public static StubTypeContext createSuperInterfaceStubTypeContext(String typeName, IType enclosingType, IPackageFragment packageFragment) { 658 return createSupertypeStubTypeContext(typeName, true, enclosingType, packageFragment); 659 } 660 661 public static StubTypeContext createSuperClassStubTypeContext(String typeName, IType enclosingType, IPackageFragment packageFragment) { 662 return createSupertypeStubTypeContext(typeName, false, enclosingType, packageFragment); 663 } 664 665 private static StubTypeContext createSupertypeStubTypeContext(String typeName, boolean isInterface, IType enclosingType, IPackageFragment packageFragment) { 666 StubTypeContext stubTypeContext; 667 String prolog= "class " + typeName + (isInterface ? " implements " : " extends "); String epilog= " {} "; if (enclosingType != null) { 670 try { 671 ICompilationUnit cu= enclosingType.getCompilationUnit(); 672 ISourceRange typeSourceRange= enclosingType.getSourceRange(); 673 int focalPosition= typeSourceRange.getOffset() + typeSourceRange.getLength() - 1; 675 ASTParser parser= ASTParser.newParser(AST.JLS3); 676 parser.setSource(cu); 677 parser.setFocalPosition(focalPosition); 678 CompilationUnit compilationUnit= (CompilationUnit) parser.createAST(null); 679 680 stubTypeContext= createStubTypeContext(cu, compilationUnit, focalPosition); 681 stubTypeContext= new StubTypeContext(stubTypeContext.getCuHandle(), 682 stubTypeContext.getBeforeString() + prolog, 683 epilog + stubTypeContext.getAfterString()); 684 } catch (CoreException e) { 685 JavaPlugin.log(e); 686 stubTypeContext= new StubTypeContext(null, null, null); 687 } 688 689 } else if (packageFragment != null) { 690 ICompilationUnit cu= packageFragment.getCompilationUnit(JavaTypeCompletionProcessor.DUMMY_CU_NAME); 691 stubTypeContext= new StubTypeContext(cu, "package " + packageFragment.getElementName() + ";" + prolog, epilog); 693 } else { 694 stubTypeContext= new StubTypeContext(null, null, null); 695 } 696 return stubTypeContext; 697 } 698 699 public static Type parseSuperClass(String superClass) { 700 return parseSuperType(superClass, false); 701 } 702 703 public static Type parseSuperInterface(String superInterface) { 704 return parseSuperType(superInterface, true); 705 } 706 707 private static Type parseSuperType(String superType, boolean isInterface) { 708 if (! superType.trim().equals(superType)) { 709 return null; 710 } 711 712 StringBuffer cuBuff= new StringBuffer (); 713 if (isInterface) 714 cuBuff.append("class __X__ implements "); else 716 cuBuff.append("class __X__ extends "); int offset= cuBuff.length(); 718 cuBuff.append(superType).append(" {}"); 720 ASTParser p= ASTParser.newParser(AST.JLS3); 721 p.setSource(cuBuff.toString().toCharArray()); 722 Map options= new HashMap (); 723 JavaModelUtil.set50CompilanceOptions(options); 724 p.setCompilerOptions(options); 725 CompilationUnit cu= (CompilationUnit) p.createAST(null); 726 ASTNode selected= NodeFinder.perform(cu, offset, superType.length()); 727 if (selected instanceof Name) 728 selected= selected.getParent(); 729 if (selected.getStartPosition() != offset 730 || selected.getLength() != superType.length() 731 || ! (selected instanceof Type) 732 || selected instanceof PrimitiveType) { 733 return null; 734 } 735 Type type= (Type) selected; 736 737 String typeNodeRange= cuBuff.substring(type.getStartPosition(), ASTNodes.getExclusiveEnd(type)); 738 if (! superType.equals(typeNodeRange)){ 739 return null; 740 } 741 return type; 742 } 743 744 public static ITypeBinding resolveSuperClass(String superclass, IType typeHandle, StubTypeContext superClassContext) { 745 StringBuffer cuString= new StringBuffer (); 746 cuString.append(superClassContext.getBeforeString()); 747 cuString.append(superclass); 748 cuString.append(superClassContext.getAfterString()); 749 750 try { 751 ICompilationUnit wc= typeHandle.getCompilationUnit().getWorkingCopy(new WorkingCopyOwner() {}, new NullProgressMonitor()); 752 try { 753 wc.getBuffer().setContents(cuString.toString()); 754 CompilationUnit compilationUnit= new RefactoringASTParser(AST.JLS3).parse(wc, true); 755 ASTNode type= NodeFinder.perform(compilationUnit, superClassContext.getBeforeString().length(), 756 superclass.length()); 757 if (type instanceof Type) { 758 return handleBug84585(((Type) type).resolveBinding()); 759 } else if (type instanceof Name) { 760 ASTNode parent= type.getParent(); 761 if (parent instanceof Type) 762 return handleBug84585(((Type) parent).resolveBinding()); 763 } 764 throw new IllegalStateException (); 765 } finally { 766 wc.discardWorkingCopy(); 767 } 768 } catch (JavaModelException e) { 769 return null; 770 } 771 } 772 773 public static ITypeBinding[] resolveSuperInterfaces(String [] interfaces, IType typeHandle, StubTypeContext superInterfaceContext) { 774 ITypeBinding[] result= new ITypeBinding[interfaces.length]; 775 776 int[] interfaceOffsets= new int[interfaces.length]; 777 StringBuffer cuString= new StringBuffer (); 778 cuString.append(superInterfaceContext.getBeforeString()); 779 int last= interfaces.length - 1; 780 for (int i= 0; i <= last; i++) { 781 interfaceOffsets[i]= cuString.length(); 782 cuString.append(interfaces[i]); 783 if (i != last) 784 cuString.append(", "); } 786 cuString.append(superInterfaceContext.getAfterString()); 787 788 try { 789 ICompilationUnit wc= typeHandle.getCompilationUnit().getWorkingCopy(new WorkingCopyOwner() {}, new NullProgressMonitor()); 790 try { 791 wc.getBuffer().setContents(cuString.toString()); 792 CompilationUnit compilationUnit= new RefactoringASTParser(AST.JLS3).parse(wc, true); 793 for (int i= 0; i <= last; i++) { 794 ASTNode type= NodeFinder.perform(compilationUnit, interfaceOffsets[i], interfaces[i].length()); 795 if (type instanceof Type) { 796 result[i]= handleBug84585(((Type) type).resolveBinding()); 797 } else if (type instanceof Name) { 798 ASTNode parent= type.getParent(); 799 if (parent instanceof Type) { 800 result[i]= handleBug84585(((Type) parent).resolveBinding()); 801 } else { 802 throw new IllegalStateException (); 803 } 804 } else { 805 throw new IllegalStateException (); 806 } 807 } 808 } finally { 809 wc.discardWorkingCopy(); 810 } 811 } catch (JavaModelException e) { 812 } 814 return result; 815 } 816 } 817 | Popular Tags |