1 11 package org.eclipse.jdt.internal.codeassist; 12 13 import org.eclipse.jdt.core.compiler.CharOperation; 14 import org.eclipse.jdt.internal.codeassist.complete.CompletionParser; 15 import org.eclipse.jdt.internal.codeassist.complete.CompletionScanner; 16 import org.eclipse.jdt.internal.compiler.ASTVisitor; 17 import org.eclipse.jdt.internal.compiler.ast.ASTNode; 18 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; 19 import org.eclipse.jdt.internal.compiler.ast.Argument; 20 import org.eclipse.jdt.internal.compiler.ast.Block; 21 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; 22 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; 23 import org.eclipse.jdt.internal.compiler.ast.Initializer; 24 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration; 25 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; 26 import org.eclipse.jdt.internal.compiler.ast.Statement; 27 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; 28 import org.eclipse.jdt.internal.compiler.lookup.BlockScope; 29 import org.eclipse.jdt.internal.compiler.lookup.ClassScope; 30 import org.eclipse.jdt.internal.compiler.lookup.MethodScope; 31 import org.eclipse.jdt.internal.compiler.lookup.Scope; 32 import org.eclipse.jdt.internal.compiler.util.SimpleSetOfCharArray; 33 import org.eclipse.jdt.internal.compiler.util.Util; 34 35 public class UnresolvedReferenceNameFinder extends ASTVisitor { 36 private static final int MAX_LINE_COUNT = 100; 37 private static final int FAKE_BLOCKS_COUNT = 20; 38 39 public static interface UnresolvedReferenceNameRequestor { 40 public void acceptName(char[] name); 41 } 42 43 private UnresolvedReferenceNameRequestor requestor; 44 45 private CompletionEngine completionEngine; 46 private CompletionParser parser; 47 private CompletionScanner completionScanner; 48 49 private int parentsPtr; 50 private ASTNode[] parents; 51 52 private int potentialVariableNamesPtr; 53 private char[][] potentialVariableNames; 54 private int[] potentialVariableNameStarts; 55 56 private SimpleSetOfCharArray acceptedNames = new SimpleSetOfCharArray(); 57 58 public UnresolvedReferenceNameFinder(CompletionEngine completionEngine) { 59 this.completionEngine = completionEngine; 60 this.parser = completionEngine.parser; 61 this.completionScanner = (CompletionScanner) parser.scanner; 62 } 63 64 private void acceptName(char[] name) { 65 if (name == null) return; 67 68 if (!CharOperation.prefixEquals(this.completionEngine.completionToken, name, false ) 69 && !(this.completionEngine.options.camelCaseMatch && CharOperation.camelCaseMatch(this.completionEngine.completionToken, name))) return; 70 71 if (acceptedNames.includes(name)) return; 72 73 this.acceptedNames.add(name); 74 75 this.requestor.acceptName(name); 77 } 78 79 public void find( 80 char[] startWith, 81 Initializer initializer, 82 ClassScope scope, 83 int from, 84 char[][] discouragedNames, 85 UnresolvedReferenceNameRequestor nameRequestor) { 86 MethodDeclaration fakeMethod = 87 this.findAfter(startWith, scope, from, initializer.bodyEnd, MAX_LINE_COUNT, false, discouragedNames, nameRequestor); 88 if (fakeMethod != null) fakeMethod.traverse(this, scope); 89 } 90 91 public void find( 92 char[] startWith, 93 AbstractMethodDeclaration methodDeclaration, 94 int from, 95 char[][] discouragedNames, 96 UnresolvedReferenceNameRequestor nameRequestor) { 97 MethodDeclaration fakeMethod = 98 this.findAfter(startWith, methodDeclaration.scope, from, methodDeclaration.bodyEnd, MAX_LINE_COUNT, false, discouragedNames, nameRequestor); 99 if (fakeMethod != null) fakeMethod.traverse(this, methodDeclaration.scope.classScope()); 100 } 101 102 public void findAfter( 103 char[] startWith, 104 Scope scope, 105 ClassScope classScope, 106 int from, 107 int to, 108 char[][] discouragedNames, 109 UnresolvedReferenceNameRequestor nameRequestor) { 110 MethodDeclaration fakeMethod = 111 this.findAfter(startWith, scope, from, to, MAX_LINE_COUNT / 2, true, discouragedNames, nameRequestor); 112 if (fakeMethod != null) fakeMethod.traverse(this, classScope); 113 } 114 115 private MethodDeclaration findAfter( 116 char[] startWith, 117 Scope s, 118 int from, 119 int to, 120 int maxLineCount, 121 boolean outsideEnclosingBlock, 122 char[][] discouragedNames, 123 UnresolvedReferenceNameRequestor nameRequestor) { 124 this.requestor = nameRequestor; 125 126 this.completionScanner.cursorLocation = 0; 128 129 if (!outsideEnclosingBlock) { 130 this.completionScanner.resetTo(from + 1, to); 132 this.completionScanner.jumpOverBlock(); 133 134 to = this.completionScanner.startPosition - 1; 135 } 136 137 int maxEnd = 138 this.completionScanner.getLineEnd( 139 Util.getLineNumber(from, this.completionScanner.lineEnds, 0, this.completionScanner.linePtr) + maxLineCount); 140 141 int end; 142 if (maxEnd < 0) { 143 end = to; 144 } else { 145 end = maxEnd < to ? maxEnd : to; 146 } 147 148 this.parser.startRecordingIdentifiers(from, end); 149 150 MethodDeclaration fakeMethod = this.parser.parseSomeStatements( 151 from, 152 end, 153 outsideEnclosingBlock ? FAKE_BLOCKS_COUNT : 0, 154 s.compilationUnitScope().referenceContext); 155 156 this.parser.stopRecordingIdentifiers(); 157 158 if(!this.initPotentialNamesTables(discouragedNames)) return null; 159 160 this.parentsPtr = -1; 161 this.parents = new ASTNode[10]; 162 163 return fakeMethod; 164 } 165 166 public void findBefore( 167 char[] startWith, 168 Scope scope, 169 ClassScope classScope, 170 int from, 171 int recordTo, 172 int parseTo, 173 char[][] discouragedNames, 174 UnresolvedReferenceNameRequestor nameRequestor) { 175 MethodDeclaration fakeMethod = 176 this.findBefore(startWith, scope, from, recordTo, parseTo, MAX_LINE_COUNT / 2, discouragedNames, nameRequestor); 177 if (fakeMethod != null) fakeMethod.traverse(this, classScope); 178 } 179 180 private MethodDeclaration findBefore( 181 char[] startWith, 182 Scope s, 183 int from, 184 int recordTo, 185 int parseTo, 186 int maxLineCount, 187 char[][] discouragedNames, 188 UnresolvedReferenceNameRequestor nameRequestor) { 189 this.requestor = nameRequestor; 190 191 this.completionScanner.cursorLocation = 0; 193 194 int minStart = 195 this.completionScanner.getLineStart( 196 Util.getLineNumber(recordTo, this.completionScanner.lineEnds, 0, this.completionScanner.linePtr) - maxLineCount); 197 198 int start; 199 int fakeBlocksCount; 200 if (minStart <= from) { 201 start = from; 202 fakeBlocksCount = 0; 203 } else { 204 start = minStart; 205 fakeBlocksCount = FAKE_BLOCKS_COUNT; 206 } 207 208 this.parser.startRecordingIdentifiers(start, recordTo); 209 210 MethodDeclaration fakeMethod = this.parser.parseSomeStatements( 211 start, 212 parseTo, 213 fakeBlocksCount, 214 s.compilationUnitScope().referenceContext); 215 216 this.parser.stopRecordingIdentifiers(); 217 218 if(!this.initPotentialNamesTables(discouragedNames)) return null; 219 220 this.parentsPtr = -1; 221 this.parents = new ASTNode[10]; 222 223 return fakeMethod; 224 } 225 226 private boolean initPotentialNamesTables(char[][] discouragedNames) { 227 char[][] pvns = this.parser.potentialVariableNames; 228 int[] pvnss = this.parser.potentialVariableNameStarts; 229 int pvnsPtr = this.parser.potentialVariableNamesPtr; 230 231 if (pvnsPtr < 0) return false; 233 int discouragedNamesCount = discouragedNames == null ? 0 : discouragedNames.length; 235 int j = -1; 236 next : for (int i = 0; i <= pvnsPtr; i++) { 237 char[] temp = pvns[i]; 238 239 if (temp == null) continue next; 240 241 for (int k = 0; k < discouragedNamesCount; k++) { 242 if (CharOperation.equals(temp, discouragedNames[k], false)) { 243 continue next; 244 } 245 } 246 247 pvns[i] = null; 248 pvns[++j] = temp; 249 pvnss[j] = pvnss[i]; 250 } 251 pvnsPtr = j; 252 253 if (pvnsPtr < 0) return false; 255 this.potentialVariableNames = pvns; 256 this.potentialVariableNameStarts = pvnss; 257 this.potentialVariableNamesPtr = pvnsPtr; 258 259 return true; 260 } 261 262 private void popParent() { 263 this.parentsPtr--; 264 } 265 private void pushParent(ASTNode parent) { 266 int length = this.parents.length; 267 if (this.parentsPtr >= length - 1) { 268 System.arraycopy(this.parents, 0, this.parents = new ASTNode[length * 2], 0, length); 269 } 270 this.parents[++this.parentsPtr] = parent; 271 } 272 273 private ASTNode getEnclosingDeclaration() { 274 int i = this.parentsPtr; 275 while (i > -1) { 276 ASTNode parent = parents[i]; 277 if (parent instanceof AbstractMethodDeclaration) { 278 return parent; 279 } else if (parent instanceof Initializer) { 280 return parent; 281 } else if (parent instanceof FieldDeclaration) { 282 return parent; 283 } else if (parent instanceof TypeDeclaration) { 284 return parent; 285 } 286 i--; 287 } 288 return null; 289 } 290 291 public boolean visit(Block block, BlockScope blockScope) { 292 ASTNode enclosingDeclaration = getEnclosingDeclaration(); 293 removeLocals(block.statements, enclosingDeclaration.sourceStart, block.sourceEnd); 294 pushParent(block); 295 return true; 296 } 297 298 public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope classScope) { 299 if (((constructorDeclaration.bits & ASTNode.IsDefaultConstructor) == 0) && !constructorDeclaration.isClinit()) { 300 removeLocals( 301 constructorDeclaration.arguments, 302 constructorDeclaration.declarationSourceStart, 303 constructorDeclaration.declarationSourceEnd); 304 removeLocals( 305 constructorDeclaration.statements, 306 constructorDeclaration.declarationSourceStart, 307 constructorDeclaration.declarationSourceEnd); 308 } 309 pushParent(constructorDeclaration); 310 return true; 311 } 312 313 public boolean visit(FieldDeclaration fieldDeclaration, MethodScope methodScope) { 314 pushParent(fieldDeclaration); 315 return true; 316 } 317 318 public boolean visit(Initializer initializer, MethodScope methodScope) { 319 pushParent(initializer); 320 return true; 321 } 322 323 public boolean visit(MethodDeclaration methodDeclaration, ClassScope classScope) { 324 removeLocals( 325 methodDeclaration.arguments, 326 methodDeclaration.declarationSourceStart, 327 methodDeclaration.declarationSourceEnd); 328 removeLocals( 329 methodDeclaration.statements, 330 methodDeclaration.declarationSourceStart, 331 methodDeclaration.declarationSourceEnd); 332 pushParent(methodDeclaration); 333 return true; 334 } 335 336 public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope blockScope) { 337 removeFields(localTypeDeclaration); 338 pushParent(localTypeDeclaration); 339 return true; 340 } 341 342 public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) { 343 removeFields(memberTypeDeclaration); 344 pushParent(memberTypeDeclaration); 345 return true; 346 } 347 348 public void endVisit(Block block, BlockScope blockScope) { 349 popParent(); 350 } 351 352 public void endVisit(Argument argument, BlockScope blockScope) { 353 endVisitRemoved(argument.declarationSourceStart, argument.sourceEnd); 354 } 355 356 public void endVisit(Argument argument, ClassScope classScope) { 357 endVisitRemoved(argument.declarationSourceStart, argument.sourceEnd); 358 } 359 360 public void endVisit(ConstructorDeclaration constructorDeclaration, ClassScope classScope) { 361 if (((constructorDeclaration.bits & ASTNode.IsDefaultConstructor) == 0) && !constructorDeclaration.isClinit()) { 362 endVisitPreserved(constructorDeclaration.bodyStart, constructorDeclaration.bodyEnd); 363 } 364 popParent(); 365 } 366 367 public void endVisit(FieldDeclaration fieldDeclaration, MethodScope methodScope) { 368 endVisitRemoved(fieldDeclaration.declarationSourceStart, fieldDeclaration.sourceEnd); 369 endVisitPreserved(fieldDeclaration.sourceEnd, fieldDeclaration.declarationEnd); 370 popParent(); 371 } 372 373 public void endVisit(Initializer initializer, MethodScope methodScope) { 374 endVisitPreserved(initializer.bodyStart, initializer.bodyEnd); 375 popParent(); 376 } 377 378 public void endVisit(LocalDeclaration localDeclaration, BlockScope blockScope) { 379 endVisitRemoved(localDeclaration.declarationSourceStart, localDeclaration.sourceEnd); 380 } 381 382 public void endVisit(MethodDeclaration methodDeclaration, ClassScope classScope) { 383 endVisitPreserved( 384 methodDeclaration.bodyStart, 385 methodDeclaration.bodyEnd); 386 popParent(); 387 } 388 389 public void endVisit(TypeDeclaration typeDeclaration, BlockScope blockScope) { 390 endVisitRemoved(typeDeclaration.sourceStart, typeDeclaration.declarationSourceEnd); 391 popParent(); 392 } 393 394 public void endVisit(TypeDeclaration typeDeclaration, ClassScope classScope) { 395 endVisitRemoved(typeDeclaration.sourceStart, typeDeclaration.declarationSourceEnd); 396 popParent(); 397 } 398 399 private int indexOfFisrtNameAfter(int position) { 400 int left = 0; 401 int right = this.potentialVariableNamesPtr; 402 403 next : while (true) { 404 if (right < left) return -1; 405 406 int mid = left + (right - left) / 2; 407 int midPosition = this.potentialVariableNameStarts[mid]; 408 if (midPosition < 0) { 409 int nextMid = indexOfNextName(mid); 410 if (nextMid < 0 || right < nextMid) { right = mid - 1; 412 continue next; 413 } 414 mid = nextMid; 415 midPosition = this.potentialVariableNameStarts[nextMid]; 416 417 if (mid == right) { int leftPosition = this.potentialVariableNameStarts[left]; 419 if (leftPosition < 0 || leftPosition < position) { int nextLeft = indexOfNextName(left); 421 if (nextLeft < 0) return - 1; 422 423 left = nextLeft; 424 continue next; 425 } 426 427 return left; 428 } 429 } 430 431 if (left != right) { 432 if (midPosition < position) { 433 left = mid + 1; 434 } else { 435 right = mid; 436 } 437 } else { 438 if (midPosition < position) { 439 return -1; 440 } 441 return mid; 442 } 443 } 444 } 445 446 private int indexOfNextName(int index) { 447 int nextIndex = index + 1; 448 while (nextIndex <= this.potentialVariableNamesPtr && 449 this.potentialVariableNames[nextIndex] == null) { 450 int jumpIndex = -this.potentialVariableNameStarts[nextIndex]; 451 if (jumpIndex > 0) { 452 nextIndex = jumpIndex; 453 } else { 454 nextIndex++; 455 } 456 } 457 458 if (this.potentialVariableNamesPtr < nextIndex) { 459 if (index < this.potentialVariableNamesPtr) { 460 this.potentialVariableNamesPtr = index; 461 } 462 return -1; 463 } 464 if (index + 1 < nextIndex) { 465 this.potentialVariableNameStarts[index + 1] = -nextIndex; 466 } 467 return nextIndex; 468 } 469 470 private void removeNameAt(int index) { 471 this.potentialVariableNames[index] = null; 472 int nextIndex = indexOfNextName(index); 473 if (nextIndex != -1) { 474 this.potentialVariableNameStarts[index] = -nextIndex; 475 } else { 476 this.potentialVariableNamesPtr = index - 1; 477 } 478 } 479 480 private void endVisitPreserved(int start, int end) { 481 int i = indexOfFisrtNameAfter(start); 482 done : while (i != -1) { 483 int nameStart = this.potentialVariableNameStarts[i]; 484 if (start < nameStart && nameStart < end) { 485 this.acceptName(this.potentialVariableNames[i]); 486 this.removeNameAt(i); 487 } 488 489 if (end < nameStart) break done; 490 i = indexOfNextName(i); 491 } 492 } 493 494 private void endVisitRemoved(int start, int end) { 495 int i = indexOfFisrtNameAfter(start); 496 done : while (i != -1) { 497 int nameStart = this.potentialVariableNameStarts[i]; 498 if (start < nameStart && nameStart < end) { 499 this.removeNameAt(i); 500 } 501 502 if (end < nameStart) break done; 503 i = indexOfNextName(i); 504 } 505 } 506 507 private void removeLocals(Statement[] statements, int start, int end) { 508 if (statements != null) { 509 for (int i = 0; i < statements.length; i++) { 510 if (statements[i] instanceof LocalDeclaration) { 511 LocalDeclaration localDeclaration = (LocalDeclaration) statements[i]; 512 int j = indexOfFisrtNameAfter(start); 513 done : while (j != -1) { 514 int nameStart = this.potentialVariableNameStarts[j]; 515 if (start <= nameStart && nameStart <= end) { 516 if (CharOperation.equals(this.potentialVariableNames[j], localDeclaration.name, false)) { 517 this.removeNameAt(j); 518 } 519 } 520 521 if (end < nameStart) break done; 522 j = indexOfNextName(j); 523 } 524 } 525 } 526 527 } 528 } 529 530 private void removeFields(TypeDeclaration typeDeclaration) { 531 int start = typeDeclaration.declarationSourceStart; 532 int end = typeDeclaration.declarationSourceEnd; 533 534 FieldDeclaration[] fieldDeclarations = typeDeclaration.fields; 535 if (fieldDeclarations != null) { 536 for (int i = 0; i < fieldDeclarations.length; i++) { 537 int j = indexOfFisrtNameAfter(start); 538 done : while (j != -1) { 539 int nameStart = this.potentialVariableNameStarts[j]; 540 if (start <= nameStart && nameStart <= end) { 541 if (CharOperation.equals(this.potentialVariableNames[j], fieldDeclarations[i].name, false)) { 542 this.removeNameAt(j); 543 } 544 } 545 546 if (end < nameStart) break done; 547 j = indexOfNextName(j); 548 } 549 } 550 } 551 } 552 } 553 | Popular Tags |