| 1 11 package org.eclipse.jdt.internal.codeassist; 12 13 import java.util.Locale ; 14 import java.util.Map ; 15 16 import org.eclipse.jdt.core.Signature; 17 import org.eclipse.jdt.core.compiler.*; 18 import org.eclipse.jdt.core.search.IJavaSearchConstants; 19 import org.eclipse.jdt.internal.codeassist.impl.*; 20 import org.eclipse.jdt.internal.codeassist.select.*; 21 import org.eclipse.jdt.internal.compiler.*; 22 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 23 import org.eclipse.jdt.internal.compiler.env.*; 24 import org.eclipse.jdt.internal.compiler.ast.*; 25 import org.eclipse.jdt.internal.compiler.lookup.*; 26 import org.eclipse.jdt.internal.compiler.parser.*; 27 import org.eclipse.jdt.internal.compiler.problem.*; 28 import org.eclipse.jdt.internal.core.SearchableEnvironment; 29 import org.eclipse.jdt.internal.core.SelectionRequestor; 30 import org.eclipse.jdt.internal.core.SourceType; 31 import org.eclipse.jdt.internal.core.SourceTypeElementInfo; 32 import org.eclipse.jdt.internal.core.util.ASTNodeFinder; 33 34 43 public final class SelectionEngine extends Engine implements ISearchRequestor { 44 45 public static boolean DEBUG = false; 46 public static boolean PERF = false; 47 48 SelectionParser parser; 49 ISelectionRequestor requestor; 50 51 boolean acceptedAnswer; 52 53 private int actualSelectionStart; 54 private int actualSelectionEnd; 55 private char[] selectedIdentifier; 56 57 private char[][][] acceptedClasses; 58 private int[] acceptedClassesModifiers; 59 private char[][][] acceptedInterfaces; 60 private int[] acceptedInterfacesModifiers; 61 private char[][][] acceptedEnums; 62 private int[] acceptedEnumsModifiers; 63 private char[][][] acceptedAnnotations; 64 private int[] acceptedAnnotationsModifiers; 65 int acceptedClassesCount; 66 int acceptedInterfacesCount; 67 int acceptedEnumsCount; 68 int acceptedAnnotationsCount; 69 70 boolean noProposal = true; 71 CategorizedProblem problem = null; 72 73 90 public SelectionEngine( 91 SearchableEnvironment nameEnvironment, 92 ISelectionRequestor requestor, 93 Map settings) { 94 95 super(settings); 96 97 this.requestor = requestor; 98 this.nameEnvironment = nameEnvironment; 99 100 ProblemReporter problemReporter = 101 new ProblemReporter( 102 DefaultErrorHandlingPolicies.proceedWithAllProblems(), 103 this.compilerOptions, 104 new DefaultProblemFactory(Locale.getDefault())) { 105 106 public CategorizedProblem createProblem( 107 char[] fileName, 108 int problemId, 109 String [] problemArguments, 110 String [] messageArguments, 111 int severity, 112 int problemStartPosition, 113 int problemEndPosition, 114 int lineNumber, 115 int columnNumber) { 116 CategorizedProblem pb = super.createProblem( 117 fileName, 118 problemId, 119 problemArguments, 120 messageArguments, 121 severity, 122 problemStartPosition, 123 problemEndPosition, 124 lineNumber, 125 columnNumber); 126 if(SelectionEngine.this.problem == null && pb.isError() && (pb.getID() & IProblem.Syntax) == 0) { 127 SelectionEngine.this.problem = pb; 128 } 129 130 return pb; 131 } 132 }; 133 this.lookupEnvironment = 134 new LookupEnvironment(this, this.compilerOptions, problemReporter, nameEnvironment); 135 this.parser = new SelectionParser(problemReporter); 136 } 137 138 public void acceptType(char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, int modifiers, AccessRestriction accessRestriction) { 139 char[] typeName = enclosingTypeNames == null ? 140 simpleTypeName : 141 CharOperation.concat( 142 CharOperation.concatWith(enclosingTypeNames, '.'), 143 simpleTypeName, 144 '.'); 145 146 if (CharOperation.equals(simpleTypeName, this.selectedIdentifier)) { 147 char[] flatEnclosingTypeNames = 148 enclosingTypeNames == null || enclosingTypeNames.length == 0 ? 149 null : 150 CharOperation.concatWith(enclosingTypeNames, '.'); 151 if(mustQualifyType(packageName, simpleTypeName, flatEnclosingTypeNames, modifiers)) { 152 int length = 0; 153 int kind = modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation); 154 switch (kind) { 155 case ClassFileConstants.AccAnnotation: 156 case ClassFileConstants.AccAnnotation | ClassFileConstants.AccInterface: 157 char[][] acceptedAnnotation = new char[2][]; 158 acceptedAnnotation[0] = packageName; 159 acceptedAnnotation[1] = typeName; 160 161 if(this.acceptedAnnotations == null) { 162 this.acceptedAnnotations = new char[10][][]; 163 this.acceptedAnnotationsModifiers = new int[10]; 164 this.acceptedAnnotationsCount = 0; 165 } 166 length = this.acceptedAnnotations.length; 167 if(length == this.acceptedAnnotationsCount) { 168 int newLength = (length + 1)* 2; 169 System.arraycopy(this.acceptedAnnotations, 0, this.acceptedAnnotations = new char[newLength][][], 0, length); 170 System.arraycopy(this.acceptedAnnotationsModifiers, 0, this.acceptedAnnotationsModifiers = new int[newLength], 0, length); 171 } 172 this.acceptedAnnotationsModifiers[this.acceptedAnnotationsCount] = modifiers; 173 this.acceptedAnnotations[this.acceptedAnnotationsCount++] = acceptedAnnotation; 174 break; 175 case ClassFileConstants.AccEnum: 176 char[][] acceptedEnum = new char[2][]; 177 acceptedEnum[0] = packageName; 178 acceptedEnum[1] = typeName; 179 180 if(this.acceptedEnums == null) { 181 this.acceptedEnums = new char[10][][]; 182 this.acceptedEnumsModifiers = new int[10]; 183 this.acceptedEnumsCount = 0; 184 } 185 length = this.acceptedEnums.length; 186 if(length == this.acceptedEnumsCount) { 187 int newLength = (length + 1)* 2; 188 System.arraycopy(this.acceptedEnums, 0, this.acceptedEnums = new char[newLength][][], 0, length); 189 System.arraycopy(this.acceptedEnumsModifiers, 0, this.acceptedEnumsModifiers = new int[newLength], 0, length); 190 } 191 this.acceptedEnumsModifiers[this.acceptedEnumsCount] = modifiers; 192 this.acceptedEnums[this.acceptedEnumsCount++] = acceptedEnum; 193 break; 194 case ClassFileConstants.AccInterface: 195 char[][] acceptedInterface= new char[2][]; 196 acceptedInterface[0] = packageName; 197 acceptedInterface[1] = typeName; 198 199 if(this.acceptedInterfaces == null) { 200 this.acceptedInterfaces = new char[10][][]; 201 this.acceptedInterfacesModifiers = new int[10]; 202 this.acceptedInterfacesCount = 0; 203 } 204 length = this.acceptedInterfaces.length; 205 if(length == this.acceptedInterfacesCount) { 206 int newLength = (length + 1)* 2; 207 System.arraycopy(this.acceptedInterfaces, 0, this.acceptedInterfaces = new char[newLength][][], 0, length); 208 System.arraycopy(this.acceptedInterfacesModifiers, 0, this.acceptedInterfacesModifiers = new int[newLength], 0, length); 209 } 210 this.acceptedInterfacesModifiers[this.acceptedInterfacesCount] = modifiers; 211 this.acceptedInterfaces[this.acceptedInterfacesCount++] = acceptedInterface; 212 break; 213 default: 214 char[][] acceptedClass = new char[2][]; 215 acceptedClass[0] = packageName; 216 acceptedClass[1] = typeName; 217 218 if(this.acceptedClasses == null) { 219 this.acceptedClasses = new char[10][][]; 220 this.acceptedClassesModifiers = new int[10]; 221 this.acceptedClassesCount = 0; 222 } 223 length = this.acceptedClasses.length; 224 if(length == this.acceptedClassesCount) { 225 int newLength = (length + 1)* 2; 226 System.arraycopy(this.acceptedClasses, 0, this.acceptedClasses = new char[newLength][][], 0, length); 227 System.arraycopy(this.acceptedClassesModifiers, 0, this.acceptedClassesModifiers = new int[newLength], 0, length); 228 } 229 this.acceptedClassesModifiers[this.acceptedClassesCount] = modifiers; 230 this.acceptedClasses[this.acceptedClassesCount++] = acceptedClass; 231 break; 232 } 233 } else { 234 this.noProposal = false; 235 this.requestor.acceptType( 236 packageName, 237 typeName, 238 modifiers, 239 false, 240 null, 241 this.actualSelectionStart, 242 this.actualSelectionEnd); 243 this.acceptedAnswer = true; 244 } 245 } 246 } 247 248 256 public void acceptPackage(char[] packageName) { 257 } 259 260 private void acceptQualifiedTypes() { 261 if(this.acceptedClasses != null){ 262 this.acceptedAnswer = true; 263 for (int i = 0; i < this.acceptedClassesCount; i++) { 264 this.noProposal = false; 265 this.requestor.acceptType( 266 this.acceptedClasses[i][0], 267 this.acceptedClasses[i][1], 268 this.acceptedClassesModifiers[i], 269 false, 270 null, 271 this.actualSelectionStart, 272 this.actualSelectionEnd); 273 } 274 this.acceptedClasses = null; 275 this.acceptedClassesModifiers = null; 276 this.acceptedClassesCount = 0; 277 } 278 if(this.acceptedInterfaces != null){ 279 this.acceptedAnswer = true; 280 for (int i = 0; i < this.acceptedInterfacesCount; i++) { 281 this.noProposal = false; 282 this.requestor.acceptType( 283 this.acceptedInterfaces[i][0], 284 this.acceptedInterfaces[i][1], 285 this.acceptedInterfacesModifiers[i], 286 false, 287 null, 288 this.actualSelectionStart, 289 this.actualSelectionEnd); 290 } 291 this.acceptedInterfaces = null; 292 this.acceptedInterfacesModifiers = null; 293 this.acceptedInterfacesCount = 0; 294 } 295 if(this.acceptedAnnotations != null){ 296 this.acceptedAnswer = true; 297 for (int i = 0; i < this.acceptedAnnotationsCount; i++) { 298 this.noProposal = false; 299 this.requestor.acceptType( 300 this.acceptedAnnotations[i][0], 301 this.acceptedAnnotations[i][1], 302 this.acceptedAnnotationsModifiers[i], 303 false, 304 null, 305 this.actualSelectionStart, 306 this.actualSelectionEnd); 307 } 308 this.acceptedAnnotations = null; 309 this.acceptedAnnotationsModifiers = null; 310 this.acceptedAnnotationsCount = 0; 311 } 312 if(this.acceptedEnums != null){ 313 this.acceptedAnswer = true; 314 for (int i = 0; i < this.acceptedEnumsCount; i++) { 315 this.noProposal = false; 316 this.requestor.acceptType( 317 this.acceptedEnums[i][0], 318 this.acceptedEnums[i][1], 319 this.acceptedEnumsModifiers[i], 320 false, 321 null, 322 this.actualSelectionStart, 323 this.actualSelectionEnd); 324 } 325 this.acceptedEnums = null; 326 this.acceptedEnumsModifiers = null; 327 this.acceptedEnumsCount = 0; 328 } 329 } 330 private boolean checkSelection( 331 char[] source, 332 int selectionStart, 333 int selectionEnd) { 334 335 Scanner scanner = new Scanner(); 336 scanner.setSource(source); 337 338 int lastIdentifierStart = -1; 339 int lastIdentifierEnd = -1; 340 char[] lastIdentifier = null; 341 int token; 342 343 if(selectionStart > selectionEnd){ 344 int end = source.length - 1; 345 346 int currentPosition = selectionStart - 1; 348 int nextCharacterPosition = selectionStart; 349 char currentCharacter = ' '; 350 try { 351 lineLoop: while(currentPosition > 0){ 352 353 if(source[currentPosition] == '\\' && source[currentPosition+1] == 'u') { 354 int pos = currentPosition + 2; 355 int c1 = 0, c2 = 0, c3 = 0, c4 = 0; 356 while (source[pos] == 'u') { 357 pos++; 358 } 359 360 int endOfUnicode = pos + 3; 361 if (end < endOfUnicode) { 362 if (endOfUnicode < source.length) { 363 end = endOfUnicode; 364 } else { 365 return false; } 367 } 368 369 if ((c1 = ScannerHelper.getNumericValue(source[pos++])) > 15 370 || c1 < 0 371 || (c2 = ScannerHelper.getNumericValue(source[pos++])) > 15 372 || c2 < 0 373 || (c3 = ScannerHelper.getNumericValue(source[pos++])) > 15 374 || c3 < 0 375 || (c4 = ScannerHelper.getNumericValue(source[pos++])) > 15 376 || c4 < 0) { 377 return false; 378 } else { 379 currentCharacter = (char) (((c1 * 16 + c2) * 16 + c3) * 16 + c4); 380 nextCharacterPosition = pos; 381 } 382 } else { 383 currentCharacter = source[currentPosition]; 384 nextCharacterPosition = currentPosition+1; 385 } 386 387 switch(currentCharacter) { 388 case '\r': 389 case '\n': 390 case '/': 391 case '"': 392 case '\'': 393 break lineLoop; 394 } 395 currentPosition--; 396 } 397 } catch (ArrayIndexOutOfBoundsException e) { 398 return false; 399 } 400 401 scanner.resetTo(nextCharacterPosition, end); 403 do { 404 try { 405 token = scanner.getNextToken(); 406 } catch (InvalidInputException e) { 407 return false; 408 } 409 switch (token) { 410 case TerminalTokens.TokenNamethis: 411 case TerminalTokens.TokenNamesuper: 412 case TerminalTokens.TokenNameIdentifier: 413 if (scanner.startPosition <= selectionStart && selectionStart <= scanner.currentPosition) { 414 if (scanner.currentPosition == scanner.eofPosition) { 415 int temp = scanner.eofPosition; 416 scanner.eofPosition = scanner.source.length; 417 while(scanner.getNextCharAsJavaIdentifierPart()){} 418 scanner.eofPosition = temp; 419 } 420 lastIdentifierStart = scanner.startPosition; 421 lastIdentifierEnd = scanner.currentPosition - 1; 422 lastIdentifier = scanner.getCurrentTokenSource(); 423 } 424 break; 425 } 426 } while (token != TerminalTokens.TokenNameEOF); 427 } else { 428 scanner.resetTo(selectionStart, selectionEnd); 429 430 boolean expectingIdentifier = true; 431 try { 432 do { 433 token = scanner.getNextToken(); 434 435 switch (token) { 436 case TerminalTokens.TokenNamethis : 437 case TerminalTokens.TokenNamesuper : 438 case TerminalTokens.TokenNameIdentifier : 439 if (!expectingIdentifier) 440 return false; 441 lastIdentifier = scanner.getCurrentTokenSource(); 442 lastIdentifierStart = scanner.startPosition; 443 lastIdentifierEnd = scanner.currentPosition - 1; 444 if(lastIdentifierEnd > selectionEnd) { 445 lastIdentifierEnd = selectionEnd; 446 lastIdentifier = CharOperation.subarray(lastIdentifier, 0,lastIdentifierEnd - lastIdentifierStart + 1); 447 } 448 449 expectingIdentifier = false; 450 break; 451 case TerminalTokens.TokenNameDOT : 452 if (expectingIdentifier) 453 return false; 454 expectingIdentifier = true; 455 break; 456 case TerminalTokens.TokenNameEOF : 457 if (expectingIdentifier) 458 return false; 459 break; 460 case TerminalTokens.TokenNameLESS : 461 if(!checkTypeArgument(scanner)) 462 return false; 463 break; 464 case TerminalTokens.TokenNameAT: 465 if(scanner.startPosition != scanner.initialPosition) 466 return false; 467 break; 468 default : 469 return false; 470 } 471 } while (token != TerminalTokens.TokenNameEOF); 472 } catch (InvalidInputException e) { 473 return false; 474 } 475 } 476 if (lastIdentifierStart > 0) { 477 this.actualSelectionStart = lastIdentifierStart; 478 this.actualSelectionEnd = lastIdentifierEnd; 479 this.selectedIdentifier = lastIdentifier; 480 return true; 481 } 482 return false; 483 } 484 private boolean checkTypeArgument(Scanner scanner) throws InvalidInputException { 485 int depth = 1; 486 int token; 487 StringBuffer buffer = new StringBuffer (); 488 do { 489 token = scanner.getNextToken(); 490 491 switch(token) { 492 case TerminalTokens.TokenNameLESS : 493 depth++; 494 buffer.append(scanner.getCurrentTokenSource()); 495 break; 496 case TerminalTokens.TokenNameGREATER : 497 depth--; 498 buffer.append(scanner.getCurrentTokenSource()); 499 break; 500 case TerminalTokens.TokenNameRIGHT_SHIFT : 501 depth-=2; 502 buffer.append(scanner.getCurrentTokenSource()); 503 break; 504 case TerminalTokens.TokenNameUNSIGNED_RIGHT_SHIFT : 505 depth-=3; 506 buffer.append(scanner.getCurrentTokenSource()); 507 break; 508 case TerminalTokens.TokenNameextends : 509 case TerminalTokens.TokenNamesuper : 510 buffer.append(' '); 511 buffer.append(scanner.getCurrentTokenSource()); 512 buffer.append(' '); 513 break; 514 case TerminalTokens.TokenNameCOMMA : 515 if(depth == 1) { 516 int length = buffer.length(); 517 char[] typeRef = new char[length]; 518 buffer.getChars(0, length, typeRef, 0); 519 try { 520 Signature.createTypeSignature(typeRef, true); 521 buffer = new StringBuffer (); 522 } catch(IllegalArgumentException e) { 523 return false; 524 } 525 } 526 break; 527 default : 528 buffer.append(scanner.getCurrentTokenSource()); 529 break; 530 531 } 532 if(depth < 0) { 533 return false; 534 } 535 } while (depth != 0 && token != TerminalTokens.TokenNameEOF); 536 537 if(depth == 0) { 538 int length = buffer.length() - 1; 539 char[] typeRef = new char[length]; 540 buffer.getChars(0, length, typeRef, 0); 541 try { 542 Signature.createTypeSignature(typeRef, true); 543 return true; 544 } catch(IllegalArgumentException e) { 545 return false; 546 } 547 } 548 549 return false; 550 } 551 552 public AssistParser getParser() { 553 return this.parser; 554 } 555 556 560 private boolean isLocal(ReferenceBinding binding) { 561 if(binding instanceof ParameterizedTypeBinding) { 562 return isLocal(((ParameterizedTypeBinding)binding).genericType()); 563 } 564 if (!(binding instanceof SourceTypeBinding)) return false; 565 if (binding instanceof LocalTypeBinding) return true; 566 if (binding instanceof MemberTypeBinding) { 567 return isLocal(((MemberTypeBinding)binding).enclosingType); 568 } 569 return false; 570 } 571 572 583 public void select( 584 ICompilationUnit sourceUnit, 585 int selectionSourceStart, 586 int selectionSourceEnd) { 587 588 char[] source = sourceUnit.getContents(); 589 590 if(DEBUG) { 591 System.out.print("SELECTION IN "); System.out.print(sourceUnit.getFileName()); 593 System.out.print(" FROM "); System.out.print(selectionSourceStart); 595 System.out.print(" TO "); System.out.println(selectionSourceEnd); 597 System.out.println("SELECTION - Source :"); System.out.println(source); 599 } 600 if (!checkSelection(source, selectionSourceStart, selectionSourceEnd)) { 601 return; 602 } 603 if (DEBUG) { 604 System.out.print("SELECTION - Checked : \""); System.out.print(new String (source, actualSelectionStart, actualSelectionEnd-actualSelectionStart+1)); 606 System.out.println('"'); 607 } 608 try { 609 this.acceptedAnswer = false; 610 CompilationResult result = new CompilationResult(sourceUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit); 611 CompilationUnitDeclaration parsedUnit = 612 this.parser.dietParse(sourceUnit, result, this.actualSelectionStart, this.actualSelectionEnd); 613 614 if (parsedUnit != null) { 615 if(DEBUG) { 616 System.out.println("SELECTION - Diet AST :"); System.out.println(parsedUnit.toString()); 618 } 619 620 if (parsedUnit.currentPackage instanceof SelectionOnPackageReference) { 622 char[][] tokens = 623 ((SelectionOnPackageReference) parsedUnit.currentPackage).tokens; 624 this.noProposal = false; 625 this.requestor.acceptPackage(CharOperation.concatWith(tokens, '.')); 626 return; 627 } 628 ImportReference[] imports = parsedUnit.imports; 629 if (imports != null) { 630 for (int i = 0, length = imports.length; i < length; i++) { 631 ImportReference importReference = imports[i]; 632 if (importReference instanceof SelectionOnImportReference) { 633 char[][] tokens = ((SelectionOnImportReference) importReference).tokens; 634 this.noProposal = false; 635 this.requestor.acceptPackage(CharOperation.concatWith(tokens, '.')); 636 this.nameEnvironment.findTypes(CharOperation.concatWith(tokens, '.'), false, false, IJavaSearchConstants.TYPE, this); 637 638 &nb
|