1 11 package org.eclipse.jdt.internal.codeassist; 12 13 import java.util.ArrayList ; 14 import java.util.HashMap ; 15 import java.util.Set ; 16 17 import org.eclipse.jdt.core.compiler.CharOperation; 18 import org.eclipse.jdt.core.search.IJavaSearchConstants; 19 import org.eclipse.jdt.internal.compiler.ASTVisitor; 20 import org.eclipse.jdt.internal.compiler.ast.*; 21 import org.eclipse.jdt.internal.compiler.env.AccessRestriction; 22 import org.eclipse.jdt.internal.compiler.lookup.Binding; 23 import org.eclipse.jdt.internal.compiler.lookup.BlockScope; 24 import org.eclipse.jdt.internal.compiler.lookup.ClassScope; 25 import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; 26 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; 27 import org.eclipse.jdt.internal.compiler.lookup.Scope; 28 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; 29 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt; 30 import org.eclipse.jdt.internal.core.SearchableEnvironment; 31 32 public class MissingTypesGuesser extends ASTVisitor { 33 public static interface GuessedTypeRequestor { 34 public void accept( 35 TypeBinding guessedType, 36 Binding[] missingElements, 37 int[] missingElementsStarts, 38 int[] missingElementsEnds, 39 boolean hasProblems); 40 41 } 42 43 private static class ResolutionCleaner extends ASTVisitor { 44 private HashtableOfObjectToInt bitsMap = new HashtableOfObjectToInt(); 45 private boolean firstCall = true; 46 47 public ResolutionCleaner(){ 48 super(); 49 } 50 51 private void cleanUp(TypeReference typeReference) { 52 if (this.firstCall) { 53 this.bitsMap.put(typeReference, typeReference.bits); 54 } else { 55 typeReference.bits = this.bitsMap.get(typeReference); 56 } 57 typeReference.resolvedType = null; 58 } 59 60 private void cleanUp(ParameterizedSingleTypeReference typeReference) { 61 this.cleanUp((TypeReference)typeReference); 62 typeReference.bits &= ~ASTNode.DidResolve; 63 } 64 65 private void cleanUp(ParameterizedQualifiedTypeReference typeReference) { 66 this.cleanUp((TypeReference)typeReference); 67 typeReference.bits &= ~ASTNode.DidResolve; 68 } 69 70 public void cleanUp(TypeReference convertedType, BlockScope scope) { 71 convertedType.traverse(this, scope); 72 this.firstCall = false; 73 } 74 75 public void cleanUp(TypeReference convertedType, ClassScope scope) { 76 convertedType.traverse(this, scope); 77 this.firstCall = false; 78 } 79 80 public boolean visit(SingleTypeReference singleTypeReference, BlockScope scope) { 81 this.cleanUp(singleTypeReference); 82 return true; 83 } 84 85 public boolean visit(SingleTypeReference singleTypeReference, ClassScope scope) { 86 this.cleanUp(singleTypeReference); 87 return true; 88 } 89 90 public boolean visit(Wildcard wildcard, BlockScope scope) { 91 this.cleanUp(wildcard); 92 return true; 93 } 94 95 public boolean visit(Wildcard wildcard, ClassScope scope) { 96 this.cleanUp(wildcard); 97 return true; 98 } 99 100 public boolean visit(ArrayTypeReference arrayTypeReference, BlockScope scope) { 101 this.cleanUp(arrayTypeReference); 102 return true; 103 } 104 105 public boolean visit(ArrayTypeReference arrayTypeReference, ClassScope scope) { 106 this.cleanUp(arrayTypeReference); 107 return true; 108 } 109 110 public boolean visit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, BlockScope scope) { 111 this.cleanUp(parameterizedSingleTypeReference); 112 return true; 113 } 114 115 public boolean visit(ParameterizedSingleTypeReference parameterizedSingleTypeReference, ClassScope scope) { 116 this.cleanUp(parameterizedSingleTypeReference); 117 return true; 118 } 119 120 public boolean visit(QualifiedTypeReference qualifiedTypeReference, BlockScope scope) { 121 this.cleanUp(qualifiedTypeReference); 122 return true; 123 } 124 125 public boolean visit(QualifiedTypeReference qualifiedTypeReference, ClassScope scope) { 126 this.cleanUp(qualifiedTypeReference); 127 return true; 128 } 129 130 public boolean visit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, BlockScope scope) { 131 this.cleanUp(arrayQualifiedTypeReference); 132 return true; 133 } 134 135 public boolean visit(ArrayQualifiedTypeReference arrayQualifiedTypeReference, ClassScope scope) { 136 this.cleanUp(arrayQualifiedTypeReference); 137 return true; 138 } 139 140 public boolean visit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, BlockScope scope) { 141 this.cleanUp(parameterizedQualifiedTypeReference); 142 return true; 143 } 144 145 public boolean visit(ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference, ClassScope scope) { 146 this.cleanUp(parameterizedQualifiedTypeReference); 147 return true; 148 } 149 150 } 151 152 private CompletionEngine.CompletionProblemFactory problemFactory ; 153 private SearchableEnvironment nameEnvironment; 154 155 private HashMap substituedTypes; 156 private HashMap originalTypes; 157 private int combinationsCount; 158 159 public MissingTypesGuesser(CompletionEngine completionEngine) { 160 this.problemFactory = completionEngine.problemFactory; 161 this.nameEnvironment = completionEngine.nameEnvironment; 162 } 163 164 private boolean computeMissingElements( 165 QualifiedTypeReference[] substituedTypeNodes, 166 char[][][] originalTypeNames, 167 Binding[] missingElements, 168 int[] missingElementsStarts, 169 int[] missingElementsEnds) { 170 int length = substituedTypeNodes.length; 171 172 for (int i = 0; i < length; i++) { 173 TypeReference substituedType = substituedTypeNodes[i]; 174 if (substituedType.resolvedType == null) return false; 175 ReferenceBinding erasure = (ReferenceBinding)substituedType.resolvedType.leafComponentType().erasure(); 176 Binding missingElement; 177 int depthToRemove = originalTypeNames[i].length - 1 ; 178 if (depthToRemove == 0) { 179 missingElement = erasure; 180 } else { 181 int depth = erasure.depth() + 1; 182 183 if (depth > depthToRemove) { 184 missingElement = erasure.enclosingTypeAt(depthToRemove); 185 } else { 186 return false; 187 } 198 } 199 200 missingElements[i] = missingElement; 201 missingElementsStarts[i] = substituedType.sourceStart; 202 missingElementsEnds[i] = substituedType.sourceEnd + 1; 203 204 } 205 206 return true; 207 } 208 209 private TypeReference convert(ArrayQualifiedTypeReference typeRef) { 210 if (typeRef.resolvedType != null) { 211 if (typeRef.resolvedType.isValidBinding()) { 212 ArrayQualifiedTypeReference convertedType = 213 new ArrayQualifiedTypeReference( 214 typeRef.tokens, 215 typeRef.dimensions(), 216 typeRef.sourcePositions); 217 convertedType.sourceStart = typeRef.sourceStart; 218 convertedType.sourceEnd = typeRef.sourceEnd; 219 return convertedType; 220 } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) { 221 if(((ReferenceBinding)typeRef.resolvedType.leafComponentType()).compoundName.length != 1) return null; 223 224 char[][] typeName = typeRef.getTypeName(); 225 char[][][] typeNames = findTypeNames(typeName); 226 if(typeNames == null || typeNames.length == 0) return null; 227 ArrayQualifiedTypeReference convertedType = 228 new ArrayQualifiedTypeReference( 229 typeNames[0], 230 typeRef.dimensions(), 231 new long[typeNames[0].length]); 232 convertedType.sourceStart = typeRef.sourceStart; 233 convertedType.sourceEnd = (int)(typeRef.sourcePositions[0] & 0x00000000FFFFFFFFL); 234 this.substituedTypes.put(convertedType, typeNames); 235 this.originalTypes.put(convertedType, typeName); 236 this.combinationsCount *= typeNames.length; 237 return convertedType; 238 } 239 } 240 return null; 241 } 242 243 private TypeReference convert(ArrayTypeReference typeRef) { 244 if (typeRef.resolvedType != null) { 245 if (typeRef.resolvedType.isValidBinding()) { 246 ArrayTypeReference convertedType = 247 new ArrayTypeReference( 248 typeRef.token, 249 typeRef.dimensions, 250 0); 251 convertedType.sourceStart = typeRef.sourceStart; 252 convertedType.sourceEnd = typeRef.originalSourceEnd; 253 return convertedType; 254 } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) { 255 char[][] typeName = typeRef.getTypeName(); 256 char[][][] typeNames = findTypeNames(typeName); 257 if(typeNames == null || typeNames.length == 0) return null; 258 ArrayQualifiedTypeReference convertedType = 259 new ArrayQualifiedTypeReference( 260 typeNames[0], 261 typeRef.dimensions, 262 new long[typeNames[0].length]); 263 convertedType.sourceStart = typeRef.sourceStart; 264 convertedType.sourceEnd = typeRef.originalSourceEnd; 265 this.substituedTypes.put(convertedType, typeNames); 266 this.originalTypes.put(convertedType, typeName); 267 this.combinationsCount *= typeNames.length; 268 return convertedType; 269 } 270 } 271 return null; 272 } 273 274 private TypeReference convert(ParameterizedQualifiedTypeReference typeRef) { 275 if (typeRef.resolvedType != null) { 276 TypeReference[][] typeArguments = typeRef.typeArguments; 277 int length = typeArguments.length; 278 TypeReference[][] convertedTypeArguments = new TypeReference[length][]; 279 next : for (int i = 0; i < length; i++) { 280 if (typeArguments[i] == null) continue next; 281 int length2 = typeArguments[i].length; 282 convertedTypeArguments[i] = new TypeReference[length2]; 283 for (int j = 0; j < length2; j++) { 284 convertedTypeArguments[i][j] = convert(typeArguments[i][j]); 285 if (convertedTypeArguments[i][j] == null) return null; 286 } 287 } 288 289 if (typeRef.resolvedType.isValidBinding()) { 290 ParameterizedQualifiedTypeReference convertedType = 291 new ParameterizedQualifiedTypeReference( 292 typeRef.tokens, 293 convertedTypeArguments, 294 typeRef.dimensions(), 295 new long[typeRef.tokens.length]); 296 convertedType.sourceStart = typeRef.sourceStart; 297 convertedType.sourceEnd = typeRef.sourceEnd; 298 return convertedType; 299 } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) { 300 if(((ReferenceBinding)typeRef.resolvedType.leafComponentType()).compoundName.length != 1) return null; 302 303 char[][] typeName = typeRef.getTypeName(); 304 char[][][] typeNames = findTypeNames(typeName); 305 if(typeNames == null || typeNames.length == 0) return null; 306 307 TypeReference[][] newConvertedTypeArguments = new TypeReference[typeNames[0].length][]; 308 for (int k = newConvertedTypeArguments.length - 1, l = convertedTypeArguments.length -1; k > -1 && l > -1;) { 309 newConvertedTypeArguments[k] = convertedTypeArguments[l]; 310 k--; 311 l--; 312 } 313 314 ParameterizedQualifiedTypeReference convertedType = 315 new ParameterizedQualifiedTypeReference( 316 typeNames[0], 317 newConvertedTypeArguments, 318 typeRef.dimensions(), 319 new long[typeNames[0].length]); 320 convertedType.sourceStart = typeRef.sourceStart; 321 convertedType.sourceEnd = (int)(typeRef.sourcePositions[0] & 0x00000000FFFFFFFFL); 322 this.substituedTypes.put(convertedType, typeNames); 323 this.originalTypes.put(convertedType, typeName); 324 this.combinationsCount *= typeNames.length; 325 return convertedType; 326 } 327 } 328 return null; 329 } 330 331 private TypeReference convert(ParameterizedSingleTypeReference typeRef) { 332 if (typeRef.resolvedType != null) { 333 TypeReference[] typeArguments = typeRef.typeArguments; 334 int length = typeArguments.length; 335 TypeReference[] convertedTypeArguments = new TypeReference[length]; 336 for (int i = 0; i < length; i++) { 337 convertedTypeArguments[i] = convert(typeArguments[i]); 338 if(convertedTypeArguments[i] == null) return null; 339 } 340 341 if (typeRef.resolvedType.isValidBinding()) { 342 ParameterizedSingleTypeReference convertedType = 343 new ParameterizedSingleTypeReference( 344 typeRef.token, 345 convertedTypeArguments, 346 typeRef.dimensions, 347 0); 348 convertedType.sourceStart = typeRef.sourceStart; 349 convertedType.sourceEnd = typeRef.sourceEnd; 350 return convertedType; 351 } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) { 352 char[][] typeName = typeRef.getTypeName(); 353 char[][][] typeNames = findTypeNames(typeName); 354 if(typeNames == null || typeNames.length == 0) return null; 355 356 TypeReference[][] allConvertedTypeArguments = new TypeReference[typeNames[0].length][]; 357 allConvertedTypeArguments[allConvertedTypeArguments.length - 1] = convertedTypeArguments; 358 359 ParameterizedQualifiedTypeReference convertedType = 360 new ParameterizedQualifiedTypeReference( 361 typeNames[0], 362 allConvertedTypeArguments, 363 typeRef.dimensions, 364 new long[typeNames[0].length]); 365 convertedType.sourceStart = typeRef.sourceStart; 366 convertedType.sourceEnd = typeRef.sourceEnd; 367 this.substituedTypes.put(convertedType, typeNames); 368 this.originalTypes.put(convertedType, typeName); 369 this.combinationsCount *= typeNames.length; 370 return convertedType; 371 } 372 } 373 return null; 374 } 375 376 private TypeReference convert(QualifiedTypeReference typeRef) { 377 if (typeRef.resolvedType != null) { 378 if (typeRef.resolvedType.isValidBinding()) { 379 QualifiedTypeReference convertedType = new QualifiedTypeReference(typeRef.tokens, typeRef.sourcePositions); 380 convertedType.sourceStart = typeRef.sourceStart; 381 convertedType.sourceEnd = typeRef.sourceEnd; 382 return convertedType; 383 } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) { 384 if(((ReferenceBinding)typeRef.resolvedType).compoundName.length != 1) return null; 386 387 char[][] typeName = typeRef.getTypeName(); 388 char[][][] typeNames = findTypeNames(typeName); 389 if(typeNames == null || typeNames.length == 0) return null; 390 QualifiedTypeReference convertedType = new QualifiedTypeReference(typeNames[0], new long[typeNames[0].length]); 391 convertedType.sourceStart = typeRef.sourceStart; 392 convertedType.sourceEnd = (int)(typeRef.sourcePositions[0] & 0x00000000FFFFFFFFL); 393 this.substituedTypes.put(convertedType, typeNames); 394 this.originalTypes.put(convertedType, typeName); 395 this.combinationsCount *= typeNames.length; 396 return convertedType; 397 } 398 } 399 return null; 400 } 401 402 private TypeReference convert(SingleTypeReference typeRef) { 403 if (typeRef.resolvedType != null) { 404 if (typeRef.resolvedType.isValidBinding()) { 405 SingleTypeReference convertedType = new SingleTypeReference(typeRef.token, 0); 406 convertedType.sourceStart = typeRef.sourceStart; 407 convertedType.sourceEnd = typeRef.sourceEnd; 408 return convertedType; 409 } else if((typeRef.resolvedType.problemId() & ProblemReasons.NotFound) != 0) { 410 char[][] typeName = typeRef.getTypeName(); 411 char[][][] typeNames = findTypeNames(typeName); 412 if(typeNames == null || typeNames.length == 0) return null; 413 QualifiedTypeReference convertedType = new QualifiedTypeReference(typeNames[0], new long[typeNames[0].length]); 414 convertedType.sourceStart = typeRef.sourceStart; 415 convertedType.sourceEnd = typeRef.sourceEnd; 416 this.substituedTypes.put(convertedType, typeNames); 417 this.originalTypes.put(convertedType, typeName); 418 this.combinationsCount *= typeNames.length; 419 return convertedType; 420 } 421 } 422 return null; 423 } 424 425 private TypeReference convert(TypeReference typeRef) { 426 if (typeRef instanceof ParameterizedSingleTypeReference) { 427 return convert((ParameterizedSingleTypeReference)typeRef); 428 } else if(typeRef instanceof ParameterizedQualifiedTypeReference) { 429 return convert((ParameterizedQualifiedTypeReference)typeRef); 430 } else if (typeRef instanceof ArrayTypeReference) { 431 return convert((ArrayTypeReference)typeRef); 432 } else if(typeRef instanceof ArrayQualifiedTypeReference) { 433 return convert((ArrayQualifiedTypeReference)typeRef); 434 } else if(typeRef instanceof Wildcard) { 435 return convert((Wildcard)typeRef); 436 } else if (typeRef instanceof SingleTypeReference) { 437 return convert((SingleTypeReference)typeRef); 438 } else if (typeRef instanceof QualifiedTypeReference) { 439 return convert((QualifiedTypeReference)typeRef); 440 } 441 return null; 442 } 443 444 private TypeReference convert(Wildcard typeRef) { 445 TypeReference bound = typeRef.bound; 446 TypeReference convertedBound = null; 447 if (bound != null) { 448 convertedBound = convert(bound); 449 if (convertedBound == null) return null; 450 } 451 Wildcard convertedType = new Wildcard(typeRef.kind); 452 convertedType.bound = convertedBound; 453 convertedType.sourceStart = typeRef.sourceStart; 454 convertedType.sourceEnd = typeRef.sourceEnd; 455 return convertedType; 456 } 457 458 private char[][][] findTypeNames(char[][] missingTypeName) { 459 char[] missingSimpleName = missingTypeName[missingTypeName.length - 1]; 460 final boolean isQualified = missingTypeName.length > 1; 461 final char[] missingFullyQualifiedName = 462 isQualified ? CharOperation.concatWith(missingTypeName, '.') : null; 463 final ArrayList results = new ArrayList (); 464 ISearchRequestor storage = new ISearchRequestor() { 465 466 public void acceptPackage(char[] packageName) { 467 } 469 public void acceptType( 470 char[] packageName, 471 char[] typeName, 472 char[][] enclosingTypeNames, 473 int modifiers, 474 AccessRestriction accessRestriction) { 475 char[] fullyQualifiedName = CharOperation.concat(packageName, CharOperation.concat(CharOperation.concatWith(enclosingTypeNames, '.'), typeName, '.'), '.'); 476 if (isQualified && !CharOperation.endsWith(fullyQualifiedName, missingFullyQualifiedName)) return; 477 char[][] compoundName = CharOperation.splitOn('.', fullyQualifiedName); 478 results.add(compoundName); 479 } 480 481 }; 482 nameEnvironment.findExactTypes(missingSimpleName, true, IJavaSearchConstants.TYPE, storage); 483 if(results.size() == 0) return null; 484 return (char[][][])results.toArray(new char[results.size()][0][0]); 485 } 486 487 private char[][] getOriginal(TypeReference typeRef) { 488 return (char[][])this.originalTypes.get(typeRef); 489 } 490 491 private QualifiedTypeReference[] getSubstituedTypes() { 492 Set types = this.substituedTypes.keySet(); 493 return (QualifiedTypeReference[]) types.toArray(new QualifiedTypeReference[types.size()]); 494 } 495 496 private char[][][] getSubstitution(TypeReference typeRef) { 497 return (char[][][])this.substituedTypes.get(typeRef); 498 } 499 500 public void guess(TypeReference typeRef, Scope scope, GuessedTypeRequestor requestor) { 501 this.substituedTypes = new HashMap (); 502 this.originalTypes = new HashMap (); 503 this.combinationsCount = 1; 504 505 TypeReference convertedType = convert(typeRef); 506 507 if(convertedType == null) return; 508 509 QualifiedTypeReference[] substituedTypeNodes = this.getSubstituedTypes(); 510 int length = substituedTypeNodes.length; 511 512 int[] substitutionsIndexes = new int[substituedTypeNodes.length]; 513 char[][][][] subtitutions = new char[substituedTypeNodes.length][][][]; 514 char[][][] originalTypeNames = new char[substituedTypeNodes.length][][]; 515 for (int i = 0; i < substituedTypeNodes.length; i++) { 516 subtitutions[i] = this.getSubstitution(substituedTypeNodes[i]); 517 originalTypeNames[i] = this.getOriginal(substituedTypeNodes[i]); 518 } 519 520 ResolutionCleaner resolutionCleaner = new ResolutionCleaner(); 521 for (int i = 0; i < this.combinationsCount; i++) { 522 523 nextSubstitution(substituedTypeNodes, subtitutions, substitutionsIndexes); 524 525 526 this.problemFactory.startCheckingProblems(); 527 TypeBinding guessedType = null; 528 switch (scope.kind) { 529 case Scope.METHOD_SCOPE : 530 case Scope.BLOCK_SCOPE : 531 resolutionCleaner.cleanUp(convertedType, (BlockScope)scope); 532 guessedType = convertedType.resolveType((BlockScope)scope); 533 break; 534 case Scope.CLASS_SCOPE : 535 resolutionCleaner.cleanUp(convertedType, (ClassScope)scope); 536 guessedType = convertedType.resolveType((ClassScope)scope); 537 break; 538 } 539 this.problemFactory.stopCheckingProblems(); 540 if (!this.problemFactory.hasForbiddenProblems) { 541 if (guessedType != null) { 542 Binding[] missingElements = new Binding[length]; 543 int[] missingElementsStarts = new int[length]; 544 int[] missingElementsEnds = new int[length]; 545 546 if(computeMissingElements( 547 substituedTypeNodes, 548 originalTypeNames, 549 missingElements, 550 missingElementsStarts, 551 missingElementsEnds)) { 552 requestor.accept( 553 guessedType.capture(scope, typeRef.sourceEnd), 554 missingElements, 555 missingElementsStarts, 556 missingElementsEnds, 557 this.problemFactory.hasAllowedProblems); 558 } 559 } 560 } 561 } 562 } 563 private void nextSubstitution( 564 QualifiedTypeReference[] substituedTypeNodes, 565 char[][][][] subtitutions, 566 int[] substitutionsIndexes) { 567 int length = substituedTypeNodes.length; 568 569 done : for (int i = 0; i < length; i++) { 570 if(substitutionsIndexes[i] < subtitutions[i].length - 1) { 571 substitutionsIndexes[i]++; 572 break done; 573 } else { 574 substitutionsIndexes[i] = 0; 575 } 576 } 577 578 for (int i = 0; i < length; i++) { 579 QualifiedTypeReference qualifiedTypeReference = substituedTypeNodes[i]; 580 qualifiedTypeReference.tokens = subtitutions[i][substitutionsIndexes[i]]; 581 qualifiedTypeReference.sourcePositions = new long[qualifiedTypeReference.tokens.length]; 582 if(qualifiedTypeReference instanceof ParameterizedQualifiedTypeReference) { 583 ParameterizedQualifiedTypeReference parameterizedQualifiedTypeReference = 584 (ParameterizedQualifiedTypeReference)qualifiedTypeReference; 585 TypeReference[][] typeArguments = parameterizedQualifiedTypeReference.typeArguments; 586 TypeReference[][] newTypeArguments = new TypeReference[qualifiedTypeReference.tokens.length][]; 587 for (int j = newTypeArguments.length - 1, k = typeArguments.length -1; j > -1 && k > -1;) { 588 newTypeArguments[j] = typeArguments[k]; 589 j--; 590 k--; 591 } 592 } 593 } 594 } 595 } 596 | Popular Tags |