1 /*******************************************************************************
2 * Copyright (c) 2000, 2019 IBM Corporation and others.
3 *
4 * This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License 2.0
6 * which accompanies this distribution, and is available at
7 * https://www.eclipse.org/legal/epl-2.0/
8 *
9 * SPDX-License-Identifier: EPL-2.0
10 *
11 * Contributors:
12 * IBM Corporation - initial API and implementation
13 * Stephan Herrmann - Contribution for
14 * bug 401035 - [1.8] A few tests have started failing recently
15 * Jesper Steen Møller - Contributions for
16 * bug 529552 - [18.3] Add 'var' in completions
17 * Bug 529556 - [18.3] Add content assist support for 'var' as a type
18 *******************************************************************************/
19 package org.eclipse.jdt.internal.codeassist.complete;
20
21 /*
22 * Parser able to build specific completion parse nodes, given a cursorLocation.
23 *
24 * Cursor location denotes the position of the last character behind which completion
25 * got requested:
26 * -1 means completion at the very beginning of the source
27 * 0 means completion behind the first character
28 * n means completion behind the n-th character
29 */
30
31 import java.util.HashSet;
32
33 import org.eclipse.core.runtime.IProgressMonitor;
34 import org.eclipse.jdt.internal.compiler.*;
35 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
36 import org.eclipse.jdt.internal.compiler.env.*;
37 import org.eclipse.jdt.internal.compiler.ast.*;
38 import org.eclipse.jdt.internal.compiler.parser.*;
39 import org.eclipse.jdt.internal.compiler.problem.*;
40 import org.eclipse.jdt.internal.compiler.util.HashtableOfObjectToInt;
41 import org.eclipse.jdt.internal.compiler.util.Util;
42 import org.eclipse.jdt.core.compiler.CharOperation;
43 import org.eclipse.jdt.internal.codeassist.impl.*;
44
45 public class CompletionParser extends AssistParser {
46 // OWNER
47 protected static final int COMPLETION_PARSER = 1024;
48 protected static final int COMPLETION_OR_ASSIST_PARSER = ASSIST_PARSER + COMPLETION_PARSER;
49
50 // KIND : all values known by CompletionParser are between 1025 and 1549
51 protected static final int K_BLOCK_DELIMITER = COMPLETION_PARSER + 1; // whether we are inside a block
52 protected static final int K_SELECTOR_INVOCATION_TYPE = COMPLETION_PARSER + 2; // whether we are inside a message send
53 protected static final int K_SELECTOR_QUALIFIER = COMPLETION_PARSER + 3; // whether we are inside a message send
54 protected static final int K_BETWEEN_CATCH_AND_RIGHT_PAREN = COMPLETION_PARSER + 4; // whether we are between the keyword 'catch' and the following ')'
55 protected static final int K_NEXT_TYPEREF_IS_CLASS = COMPLETION_PARSER + 5; // whether the next type reference is a class
56 protected static final int K_NEXT_TYPEREF_IS_INTERFACE = COMPLETION_PARSER + 6; // whether the next type reference is an interface
57 protected static final int K_NEXT_TYPEREF_IS_EXCEPTION = COMPLETION_PARSER + 7; // whether the next type reference is an exception
58 protected static final int K_BETWEEN_NEW_AND_LEFT_BRACKET = COMPLETION_PARSER + 8; // whether we are between the keyword 'new' and the following left braket, i.e. '[', '(' or '{'
59 protected static final int K_INSIDE_THROW_STATEMENT = COMPLETION_PARSER + 9; // whether we are between the keyword 'throw' and the end of a throw statement
60 protected static final int K_INSIDE_RETURN_STATEMENT = COMPLETION_PARSER + 10; // whether we are between the keyword 'return' and the end of a return statement
61 protected static final int K_CAST_STATEMENT = COMPLETION_PARSER + 11; // whether we are between ')' and the end of a cast statement
62 protected static final int K_LOCAL_INITIALIZER_DELIMITER = COMPLETION_PARSER + 12;
63 protected static final int K_ARRAY_INITIALIZER = COMPLETION_PARSER + 13;
64 protected static final int K_ARRAY_CREATION = COMPLETION_PARSER + 14;
65 protected static final int K_UNARY_OPERATOR = COMPLETION_PARSER + 15;
66 protected static final int K_BINARY_OPERATOR = COMPLETION_PARSER + 16;
67 protected static final int K_ASSISGNMENT_OPERATOR = COMPLETION_PARSER + 17;
68 protected static final int K_CONDITIONAL_OPERATOR = COMPLETION_PARSER + 18;
69 protected static final int K_BETWEEN_IF_AND_RIGHT_PAREN = COMPLETION_PARSER + 19;
70 protected static final int K_BETWEEN_WHILE_AND_RIGHT_PAREN = COMPLETION_PARSER + 20;
71 protected static final int K_BETWEEN_FOR_AND_RIGHT_PAREN = COMPLETION_PARSER + 21;
72 protected static final int K_BETWEEN_SWITCH_AND_RIGHT_PAREN = COMPLETION_PARSER + 22;
73 protected static final int K_BETWEEN_SYNCHRONIZED_AND_RIGHT_PAREN = COMPLETION_PARSER + 23;
74 protected static final int K_INSIDE_ASSERT_STATEMENT = COMPLETION_PARSER + 24;
75 protected static final int K_SWITCH_LABEL= COMPLETION_PARSER + 25;
76 protected static final int K_BETWEEN_CASE_AND_COLON = COMPLETION_PARSER + 26;
77 protected static final int K_BETWEEN_DEFAULT_AND_COLON = COMPLETION_PARSER + 27;
78 protected static final int K_BETWEEN_LEFT_AND_RIGHT_BRACKET = COMPLETION_PARSER + 28;
79 protected static final int K_EXTENDS_KEYWORD = COMPLETION_PARSER + 29;
80 protected static final int K_PARAMETERIZED_METHOD_INVOCATION = COMPLETION_PARSER + 30;
81 protected static final int K_PARAMETERIZED_ALLOCATION = COMPLETION_PARSER + 31;
82 protected static final int K_PARAMETERIZED_CAST = COMPLETION_PARSER + 32;
83 protected static final int K_BETWEEN_ANNOTATION_NAME_AND_RPAREN = COMPLETION_PARSER + 33;
84 protected static final int K_INSIDE_BREAK_STATEMENT = COMPLETION_PARSER + 34;
85 protected static final int K_INSIDE_CONTINUE_STATEMENT = COMPLETION_PARSER + 35;
86 protected static final int K_LABEL = COMPLETION_PARSER + 36;
87 protected static final int K_MEMBER_VALUE_ARRAY_INITIALIZER = COMPLETION_PARSER + 37;
88 protected static final int K_CONTROL_STATEMENT_DELIMITER = COMPLETION_PARSER + 38;
89 protected static final int K_INSIDE_ASSERT_EXCEPTION = COMPLETION_PARSER + 39;
90 protected static final int K_INSIDE_FOR_CONDITIONAL = COMPLETION_PARSER + 40;
91 // added for https://bugs.eclipse.org/bugs/show_bug.cgi?id=261534
92 protected static final int K_BETWEEN_INSTANCEOF_AND_RPAREN = COMPLETION_PARSER + 41;
93 protected static final int K_INSIDE_IMPORT_STATEMENT = COMPLETION_PARSER + 43;
94 protected static final int K_INSIDE_EXPORTS_STATEMENT = COMPLETION_PARSER + 44;
95 protected static final int K_INSIDE_REQUIRES_STATEMENT = COMPLETION_PARSER + 45;
96 protected static final int K_INSIDE_USES_STATEMENT = COMPLETION_PARSER + 46;
97 protected static final int K_INSIDE_PROVIDES_STATEMENT = COMPLETION_PARSER + 47;
98 protected static final int K_AFTER_PACKAGE_IN_PACKAGE_VISIBILITY_STATEMENT = COMPLETION_PARSER + 48;
99 protected static final int K_AFTER_NAME_IN_PROVIDES_STATEMENT = COMPLETION_PARSER + 49;
100 protected static final int K_AFTER_WITH_IN_PROVIDES_STATEMENT = COMPLETION_PARSER + 50;
101 protected static final int K_INSIDE_OPENS_STATEMENT = COMPLETION_PARSER + 51;
102 protected static final int K_YIELD_KEYWORD = COMPLETION_PARSER + 52;
103
104
105 public final static char[] FAKE_TYPE_NAME = new char[]{' '};
106 public final static char[] FAKE_METHOD_NAME = new char[]{' '};
107 public final static char[] FAKE_ARGUMENT_NAME = new char[]{' '};
108 public final static char[] VALUE = new char[]{'v', 'a', 'l', 'u', 'e'};
109
110 /* public fields */
111
112 public int cursorLocation;
113 public ASTNode assistNodeParent; // the parent node of assist node
114 public ASTNode enclosingNode; // an enclosing node used by proposals inference
115
116 /* the following fields are internal flags */
117
118 // block kind
119 static final int IF = 1;
120 static final int TRY = 2;
121 static final int CATCH = 3;
122 static final int WHILE = 4;
123 static final int SWITCH = 5;
124 static final int FOR = 6;
125 static final int DO = 7;
126 static final int SYNCHRONIZED = 8;
127
128 // label kind
129 static final int DEFAULT = 1;
130
131 // invocation type constants
132 static final int EXPLICIT_RECEIVER = 0;
133 static final int NO_RECEIVER = -1;
134 static final int SUPER_RECEIVER = -2;
135 static final int NAME_RECEIVER = -3;
136 static final int ALLOCATION = -4;
137 static final int QUALIFIED_ALLOCATION = -5;
138
139 static final int QUESTION = 1;
140 static final int COLON = 2;
141
142 // K_BETWEEN_ANNOTATION_NAME_AND_RPAREN arguments
143 static final int LPAREN_NOT_CONSUMED = 1;
144 static final int LPAREN_CONSUMED = 2;
145 static final int ANNOTATION_NAME_COMPLETION = 4;
146
147 // K_PARAMETERIZED_METHOD_INVOCATION arguments
148 static final int INSIDE_NAME = 1;
149
150 // the type of the current invocation (one of the invocation type constants)
151 int invocationType;
152
153 // a pointer in the expression stack to the qualifier of a invocation
154 int qualifier;
155
156 // used to find if there is unused modifiers when building completion inside a method or an initializer
157 boolean hasUnusedModifiers;
158
159 // show if the current token can be an explicit constructor
160 int canBeExplicitConstructor = NO;
161 static final int NO = 0;
162 static final int NEXTTOKEN = 1;
163 static final int YES = 2;
164
165 protected static final int LabelStackIncrement = 10;
166 char[][] labelStack = new char[LabelStackIncrement][];
167 int labelPtr = -1;
168
169 boolean isAlreadyAttached;
170 boolean shouldStackAssistNode;
171
172 public boolean record = false;
173 public boolean skipRecord = false;
174 public int recordFrom;
175 public int recordTo;
176 public int potentialVariableNamesPtr;
177 public char[][] potentialVariableNames;
178 public int[] potentialVariableNameStarts;
179 public int[] potentialVariableNameEnds;
180
181 CompletionOnAnnotationOfType pendingAnnotation;
182
183 private boolean storeSourceEnds;
184 public HashtableOfObjectToInt sourceEnds;
185 private boolean inReferenceExpression;
186 private IProgressMonitor monitor;
187 private int resumeOnSyntaxError = 0;
188 private boolean consumedEnhancedFor;
189
CompletionParser(ProblemReporter problemReporter, boolean storeExtraSourceEnds)190 public CompletionParser(ProblemReporter problemReporter, boolean storeExtraSourceEnds) {
191 super(problemReporter);
192 this.reportSyntaxErrorIsRequired = false;
193 this.javadocParser.checkDocComment = true;
194 this.annotationRecoveryActivated = false;
195 if (storeExtraSourceEnds) {
196 this.storeSourceEnds = true;
197 this.sourceEnds = new HashtableOfObjectToInt();
198 }
199 }
CompletionParser(ProblemReporter problemReporter, boolean storeExtraSourceEnds, IProgressMonitor monitor)200 public CompletionParser(ProblemReporter problemReporter, boolean storeExtraSourceEnds, IProgressMonitor monitor) {
201 this(problemReporter, storeExtraSourceEnds);
202 this.monitor = monitor;
203 }
addPotentialName(char[] potentialVariableName, int start, int end)204 private void addPotentialName(char[] potentialVariableName, int start, int end) {
205 int length = this.potentialVariableNames.length;
206 if (this.potentialVariableNamesPtr >= length - 1) {
207 System.arraycopy(
208 this.potentialVariableNames,
209 0,
210 this.potentialVariableNames = new char[length * 2][],
211 0,
212 length);
213 System.arraycopy(
214 this.potentialVariableNameStarts,
215 0,
216 this.potentialVariableNameStarts = new int[length * 2],
217 0,
218 length);
219 System.arraycopy(
220 this.potentialVariableNameEnds,
221 0,
222 this.potentialVariableNameEnds = new int[length * 2],
223 0,
224 length);
225 }
226 this.potentialVariableNames[++this.potentialVariableNamesPtr] = potentialVariableName;
227 this.potentialVariableNameStarts[this.potentialVariableNamesPtr] = start;
228 this.potentialVariableNameEnds[this.potentialVariableNamesPtr] = end;
229 }
startRecordingIdentifiers(int from, int to)230 public void startRecordingIdentifiers(int from, int to) {
231 this.record = true;
232 this.skipRecord = false;
233 this.recordFrom = from;
234 this.recordTo = to;
235
236 this.potentialVariableNamesPtr = -1;
237 this.potentialVariableNames = new char[10][];
238 this.potentialVariableNameStarts = new int[10];
239 this.potentialVariableNameEnds = new int[10];
240 }
stopRecordingIdentifiers()241 public void stopRecordingIdentifiers() {
242 this.record = true;
243 this.skipRecord = false;
244 }
245 @Override
assistIdentifier()246 public char[] assistIdentifier(){
247 return ((CompletionScanner)this.scanner).completionIdentifier;
248 }
249 @Override
assistNodeParent()250 protected ASTNode assistNodeParent() {
251 return this.assistNodeParent;
252 }
253 @Override
enclosingNode()254 protected ASTNode enclosingNode() {
255 return this.enclosingNode;
256 }
attachOrphanCompletionNode()257 protected void attachOrphanCompletionNode(){
258 if(this.assistNode == null || this.isAlreadyAttached) return;
259
260 this.isAlreadyAttached = true;
261
262 if (this.isOrphanCompletionNode) {
263 ASTNode orphan = this.assistNode;
264 this.isOrphanCompletionNode = false;
265
266 if (this.currentElement instanceof RecoveredUnit){
267 if (orphan instanceof ImportReference){
268 this.currentElement.add((ImportReference)orphan, 0);
269 } else if (orphan instanceof ModuleDeclaration) {
270 this.currentElement.add((ModuleDeclaration)orphan, 0);
271 }
272 } else if (this.currentElement instanceof RecoveredType){ /* if in context of a type, then persists the identifier into a fake field return type */
273 RecoveredType recoveredType = (RecoveredType)this.currentElement;
274 /* filter out cases where scanner is still inside type header */
275 if (recoveredType.foundOpeningBrace) {
276 /* generate a pseudo field with a completion on type reference */
277 if (orphan instanceof TypeReference){
278 if (isInsideModuleInfo()) return; //taken care elsewhere
279
280 TypeReference fieldType;
281
282 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
283 int info = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER);
284 if(kind == K_BINARY_OPERATOR && info == LESS && this.identifierPtr > -1) {
285 if(this.genericsLengthStack[this.genericsLengthPtr] > 0) {
286 consumeTypeArguments();
287 }
288 pushOnGenericsStack(orphan);
289 consumeTypeArguments();
290 fieldType = getTypeReference(0);
291 this.assistNodeParent = fieldType;
292 } else {
293 fieldType = (TypeReference)orphan;
294 }
295
296 CompletionOnFieldType fieldDeclaration = new CompletionOnFieldType(fieldType, false);
297
298 // retrieve annotations if any
299 int length;
300 if ((length = this.expressionLengthStack[this.expressionLengthPtr]) != 0 &&
301 this.expressionStack[this.expressionPtr] instanceof Annotation) {
302 System.arraycopy(
303 this.expressionStack,
304 this.expressionPtr - length + 1,
305 fieldDeclaration.annotations = new Annotation[length],
306 0,
307 length);
308 }
309
310 // retrieve available modifiers if any
311 if (this.intPtr >= 2 && this.intStack[this.intPtr-1] == this.lastModifiersStart && this.intStack[this.intPtr-2] == this.lastModifiers){
312 fieldDeclaration.modifiersSourceStart = this.intStack[this.intPtr-1];
313 fieldDeclaration.modifiers = this.intStack[this.intPtr-2];
314 }
315
316 this.currentElement = this.currentElement.add(fieldDeclaration, 0);
317 return;
318 }
319 }
320 }
321 /* if in context of a method, persists if inside arguments as a type */
322 if (this.currentElement instanceof RecoveredMethod){
323 RecoveredMethod recoveredMethod = (RecoveredMethod)this.currentElement;
324 /* only consider if inside method header */
325 if (!recoveredMethod.foundOpeningBrace) {
326 //if (rParenPos < lParenPos){ // inside arguments
327 if (orphan instanceof TypeReference){
328 this.currentElement = this.currentElement.parent.add(
329 new CompletionOnFieldType((TypeReference)orphan, true), 0);
330 return;
331 }
332
333 if(orphan instanceof Annotation) {
334 CompletionOnAnnotationOfType fakeType =
335 new CompletionOnAnnotationOfType(
336 FAKE_TYPE_NAME,
337 this.compilationUnit.compilationResult(),
338 (Annotation)orphan);
339 fakeType.isParameter = true;
340 this.currentElement.parent.add(fakeType, 0);
341 this.pendingAnnotation = fakeType;
342 return;
343 }
344 }
345 }
346
347 if(orphan instanceof MemberValuePair) {
348 buildMoreAnnotationCompletionContext((MemberValuePair) orphan);
349 return;
350 }
351
352 if(orphan instanceof Annotation) {
353 popUntilCompletedAnnotationIfNecessary();
354
355 CompletionOnAnnotationOfType fakeType =
356 new CompletionOnAnnotationOfType(
357 FAKE_TYPE_NAME,
358 this.compilationUnit.compilationResult(),
359 (Annotation)orphan);
360 this.currentElement.add(fakeType, 0);
361
362 if (!isInsideAnnotation()) {
363 this.pendingAnnotation = fakeType;
364 }
365
366 return;
367 }
368
369 if ((topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_CATCH_AND_RIGHT_PAREN)) {
370 if (this.assistNode instanceof CompletionOnSingleTypeReference &&
371 ((CompletionOnSingleTypeReference)this.assistNode).isException()) {
372 buildMoreTryStatementCompletionContext((TypeReference)this.assistNode);
373 return;
374 } else if (this.assistNode instanceof CompletionOnQualifiedTypeReference &&
375 ((CompletionOnQualifiedTypeReference)this.assistNode).isException()) {
376 buildMoreTryStatementCompletionContext((TypeReference)this.assistNode);
377 return;
378 } else if (this.assistNode instanceof CompletionOnParameterizedQualifiedTypeReference &&
379 ((CompletionOnParameterizedQualifiedTypeReference)this.assistNode).isException()) {
380 buildMoreTryStatementCompletionContext((TypeReference)this.assistNode);
381 return;
382 }
383 }
384
385 // add the completion node to the method declaration or constructor declaration
386 if (orphan instanceof Statement) {
387 /* check for completion at the beginning of method body
388 behind an invalid signature
389 */
390 RecoveredMethod method = this.currentElement.enclosingMethod();
391 if (method != null){
392 AbstractMethodDeclaration methodDecl = method.methodDeclaration;
393 if ((methodDecl.bodyStart == methodDecl.sourceEnd+1) // was missing opening brace
394 && (Util.getLineNumber(orphan.sourceStart, this.scanner.lineEnds, 0, this.scanner.linePtr)
395 == Util.getLineNumber(methodDecl.sourceEnd, this.scanner.lineEnds, 0, this.scanner.linePtr))){
396 return;
397 }
398 }
399 // add the completion node as a statement to the list of block statements
400 this.currentElement = this.currentElement.add((Statement)orphan, 0);
401 return;
402 }
403 }
404
405 if (isInsideAnnotation()) {
406 // push top expression on ast stack if it contains the completion node
407 Expression expression;
408 if (this.expressionPtr > -1) {
409 expression = this.expressionStack[this.expressionPtr];
410 if(expression == this.assistNode) {
411 if (this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_MEMBER_VALUE_ARRAY_INITIALIZER ) {
412 ArrayInitializer arrayInitializer = new ArrayInitializer();
413 arrayInitializer.expressions = new Expression[]{expression};
414 char[] memberValueName = VALUE;
415 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, 1) == K_ATTRIBUTE_VALUE_DELIMITER) {
416 if (this.identifierLengthPtr > 0) {
417 memberValueName = this.identifierStack[this.identifierPtr];
418 int length = this.identifierLengthStack[this.identifierLengthPtr--];
419 this.identifierPtr -= length;
420 }
421 }
422 MemberValuePair memberValuePair = new MemberValuePair(memberValueName, expression.sourceStart,
423 expression.sourceEnd, arrayInitializer);
424 // The following if-statement is the result of inlining a call of buildMoreAnnotationCompletionContext
425 // that was previously here. It might not be needed.
426 if (this.astLengthPtr > -1) {
427 this.astLengthPtr--;
428 }
429 TypeReference typeReference = getAnnotationType();
430
431 NormalAnnotation annotation = new NormalAnnotation(typeReference, this.intStack[this.intPtr--]);
432 annotation.memberValuePairs = new MemberValuePair[] { memberValuePair };
433
434 CompletionOnAnnotationOfType fakeType = new CompletionOnAnnotationOfType(FAKE_TYPE_NAME,
435 this.compilationUnit.compilationResult(), annotation);
436
437 this.currentElement.add(fakeType, 0);
438 this.pendingAnnotation = fakeType;
439 this.assistNodeParent = new AssistNodeParentAnnotationArrayInitializer(typeReference, memberValueName);
440 } else if(this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_ANNOTATION_NAME_AND_RPAREN) {
441 if (expression instanceof SingleNameReference) {
442 SingleNameReference nameReference = (SingleNameReference) expression;
443 CompletionOnMemberValueName memberValueName = new CompletionOnMemberValueName(nameReference.token, nameReference.sourceStart, nameReference.sourceEnd);
444
445 buildMoreAnnotationCompletionContext(memberValueName);
446 return;
447 } else if (expression instanceof QualifiedNameReference || expression instanceof StringLiteral) {
448 MemberValuePair valuePair =
449 new MemberValuePair(VALUE, expression.sourceStart, expression.sourceEnd, expression);
450 buildMoreAnnotationCompletionContext(valuePair);
451 }
452 } else {
453 int index;
454 if((index = lastIndexOfElement(K_ATTRIBUTE_VALUE_DELIMITER)) != -1) {
455 int attributeIndentifierPtr = this.elementInfoStack[index];
456 int identLengthPtr = this.identifierLengthPtr;
457 int identPtr = this.identifierPtr;
458 while (attributeIndentifierPtr < identPtr) {
459 identPtr -= this.identifierLengthStack[identLengthPtr--];
460 }
461
462 if(attributeIndentifierPtr != identPtr) return;
463
464 this.identifierLengthPtr = identLengthPtr;
465 this.identifierPtr = identPtr;
466
467 this.identifierLengthPtr--;
468 MemberValuePair memberValuePair = new MemberValuePair(
469 this.identifierStack[this.identifierPtr--],
470 expression.sourceStart,
471 expression.sourceEnd,
472 expression);
473
474 buildMoreAnnotationCompletionContext(memberValuePair);
475 return;
476 }
477 }
478 } else {
479 CompletionNodeDetector detector = new CompletionNodeDetector(this.assistNode, expression);
480 if(detector.containsCompletionNode()) {
481 MemberValuePair valuePair =
482 new MemberValuePair(VALUE, expression.sourceStart, expression.sourceEnd, expression);
483 buildMoreAnnotationCompletionContext(valuePair);
484 }
485 }
486 }
487
488 if (this.astPtr > -1) {
489 ASTNode node = this.astStack[this.astPtr];
490 if(node instanceof MemberValuePair) {
491 MemberValuePair memberValuePair = (MemberValuePair) node;
492 CompletionNodeDetector detector = new CompletionNodeDetector(this.assistNode, memberValuePair);
493 if(detector.containsCompletionNode()) {
494 buildMoreAnnotationCompletionContext(memberValuePair);
495 this.assistNodeParent = detector.getCompletionNodeParent();
496 return;
497 }
498 }
499 }
500 }
501
502 if(this.genericsPtr > -1) {
503 ASTNode node = this.genericsStack[this.genericsPtr];
504 if(node instanceof Wildcard && ((Wildcard)node).bound == this.assistNode){
505 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
506 if (kind == K_BINARY_OPERATOR) {
507 int info = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER);
508 if (info == LESS) {
509 buildMoreGenericsCompletionContext(node, true);
510 return;
511 }
512 }
513 if(this.identifierLengthPtr > -1 && this.identifierLengthStack[this.identifierLengthPtr]!= 0) {
514 this.pushOnElementStack(K_BINARY_OPERATOR, LESS);
515 buildMoreGenericsCompletionContext(node, false);
516 return;
517 }
518 }
519 }
520
521 if(this.currentElement instanceof RecoveredType || this.currentElement instanceof RecoveredMethod) {
522 if(this.currentElement instanceof RecoveredType) {
523 RecoveredType recoveredType = (RecoveredType)this.currentElement;
524 if(recoveredType.foundOpeningBrace && this.genericsPtr > -1) {
525 if(this.genericsStack[this.genericsPtr] instanceof TypeParameter) {
526 TypeParameter typeParameter = (TypeParameter) this.genericsStack[this.genericsPtr];
527 CompletionNodeDetector detector = new CompletionNodeDetector(this.assistNode, typeParameter);
528 if(detector.containsCompletionNode()) {
529 this.currentElement.add(new CompletionOnMethodTypeParameter(new TypeParameter[]{typeParameter},this.compilationUnit.compilationResult()), 0);
530 }
531 return;
532 }
533 }
534 }
535
536 if ((!isInsideMethod() && !isInsideFieldInitialization())) {
537 if(this.genericsPtr > -1 && this.genericsLengthPtr > -1 && this.genericsIdentifiersLengthPtr > -1) {
538 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
539 int info = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER);
540 if(kind == K_BINARY_OPERATOR && info == LESS) {
541 consumeTypeArguments();
542 }
543 int numberOfIdentifiers = this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr];
544 int genPtr = this.genericsPtr;
545 done : for(int i = 0; i <= this.identifierLengthPtr && numberOfIdentifiers > 0; i++){
546 int identifierLength = this.identifierLengthStack[this.identifierLengthPtr - i];
547 int length = this.genericsLengthStack[this.genericsLengthPtr - i];
548 for(int j = 0; j < length; j++) {
549 ASTNode node = this.genericsStack[genPtr - j];
550 CompletionNodeDetector detector = new CompletionNodeDetector(this.assistNode, node);
551 if(detector.containsCompletionNode()) {
552 if(node == this.assistNode){
553 if(this.identifierLengthPtr > -1 && this.identifierLengthStack[this.identifierLengthPtr]!= 0) {
554 TypeReference ref = this.getTypeReference(0);
555 this.assistNodeParent = ref;
556 }
557 } else {
558 this.assistNodeParent = detector.getCompletionNodeParent();
559 }
560 break done;
561 }
562 }
563 genPtr -= length;
564 numberOfIdentifiers -= identifierLength;
565 }
566 if(this.assistNodeParent != null && this.assistNodeParent instanceof TypeReference) {
567 if(this.currentElement instanceof RecoveredType) {
568 this.currentElement = this.currentElement.add(new CompletionOnFieldType((TypeReference)this.assistNodeParent, false), 0);
569 } else {
570 this.currentElement = this.currentElement.add((TypeReference)this.assistNodeParent, 0);
571 }
572 }
573 }
574 }
575 }
576
577 // the following code applies only in methods, constructors or initializers
578 if ((!isInsideMethod() && !isInsideFieldInitialization() && !isInsideAttributeValue())) {
579 return;
580 }
581 if(this.assistNodeParent instanceof AssistNodeParentAnnotationArrayInitializer) {
582 return;
583 }
584
585 if(this.genericsPtr > -1) {
586 ASTNode node = this.genericsStack[this.genericsPtr];
587 CompletionNodeDetector detector = new CompletionNodeDetector(this.assistNode, node);
588 if(detector.containsCompletionNode()) {
589 /* check for completion at the beginning of method body
590 behind an invalid signature
591 */
592 RecoveredMethod method = this.currentElement.enclosingMethod();
593 if (method != null){
594 AbstractMethodDeclaration methodDecl = method.methodDeclaration;
595 if ((methodDecl.bodyStart == methodDecl.sourceEnd+1) // was missing opening brace
596 && (Util.getLineNumber(node.sourceStart, this.scanner.lineEnds, 0, this.scanner.linePtr)
597 == Util.getLineNumber(methodDecl.sourceEnd, this.scanner.lineEnds, 0, this.scanner.linePtr))){
598 return;
599 }
600 }
601 if(node == this.assistNode){
602 buildMoreGenericsCompletionContext(node, true);
603 }
604 }
605 }
606
607 // push top expression on ast stack if it contains the completion node
608 Expression expression;
609 if (this.expressionPtr > -1) {
610 expression = this.expressionStack[this.expressionPtr];
611 CompletionNodeDetector detector = new CompletionNodeDetector(this.assistNode, expression);
612 if(detector.containsCompletionNode()) {
613 /* check for completion at the beginning of method body
614 behind an invalid signature
615 */
616 RecoveredMethod method = this.currentElement.enclosingMethod();
617 if (method != null){
618 AbstractMethodDeclaration methodDecl = method.methodDeclaration;
619 if ((methodDecl.bodyStart == methodDecl.sourceEnd+1) // was missing opening brace
620 && (Util.getLineNumber(expression.sourceStart, this.scanner.lineEnds, 0, this.scanner.linePtr)
621 == Util.getLineNumber(methodDecl.sourceEnd, this.scanner.lineEnds, 0, this.scanner.linePtr))){
622 return;
623 }
624 }
625 if(expression == this.assistNode
626 || (expression instanceof Assignment // https://bugs.eclipse.org/bugs/show_bug.cgi?id=287939
627 && ((Assignment)expression).expression == this.assistNode
628 && ((this.expressionPtr > 0 && stackHasInstanceOfExpression(this.expressionStack, this.expressionPtr - 1))
629 // In case of error in compilation unit, expression stack might not have instanceof exp, so try elementObjectInfoStack
630 || (this.elementPtr >= 0 && stackHasInstanceOfExpression(this.elementObjectInfoStack, this.elementPtr))))
631 || (expression instanceof AllocationExpression
632 && ((AllocationExpression)expression).type == this.assistNode)
633 || (expression instanceof AND_AND_Expression
634 && (this.elementPtr >= 0 && this.elementObjectInfoStack[this.elementPtr] instanceof InstanceOfExpression))
635 || (expression instanceof ConditionalExpression
636 && ((ConditionalExpression) expression).valueIfFalse == this.assistNode)){
637 buildMoreCompletionContext(expression);
638 if (this.assistNodeParent == null
639 && expression instanceof Assignment) {
640 this.assistNodeParent = detector.getCompletionNodeParent();
641 }
642 return;
643 } else {
644 this.assistNodeParent = detector.getCompletionNodeParent();
645 if(this.assistNodeParent != null) {
646 this.currentElement = this.currentElement.add((Statement)this.assistNodeParent, 0);
647 } else {
648 this.currentElement = this.currentElement.add(expression, 0);
649 }
650 return;
651 }
652 }
653 }
654 if (this.astPtr > -1 && this.astStack[this.astPtr] instanceof LocalDeclaration) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=287939
655 // To take care of: if (a instance of X) int i = a.|
656 LocalDeclaration local = (LocalDeclaration) this.astStack[this.astPtr];
657 if (local.initialization == this.assistNode) {
658 Statement enclosing = buildMoreCompletionEnclosingContext(local);
659 if (enclosing instanceof IfStatement) {
660 if (this.currentElement instanceof RecoveredBlock) {
661 // RecoveredLocalVariable must be removed from its parent because the IfStatement will be added instead
662 RecoveredBlock recoveredBlock = (RecoveredBlock) this.currentElement;
663 recoveredBlock.statements[--recoveredBlock.statementCount] = null;
664 this.currentElement = this.currentElement.add(enclosing, 0);
665 }
666 }
667 }
668 }
669 }
670
671 private static class SavedState {
672 final ASTNode assistNodeParent;
673 final int parserCursorLocation;
674 final int scannerCursorLocation;
675
SavedState(int parserCursorLocation, int scannerCursorLocation, ASTNode assistNodeParent)676 public SavedState(int parserCursorLocation, int scannerCursorLocation, ASTNode assistNodeParent) {
677 this.parserCursorLocation = parserCursorLocation;
678 this.scannerCursorLocation = scannerCursorLocation;
679 this.assistNodeParent = assistNodeParent;
680 }
681 }
682 @Override
becomeSimpleParser()683 public Object becomeSimpleParser() {
684 CompletionScanner completionScanner = (CompletionScanner)this.scanner;
685 SavedState parserState = new SavedState(this.cursorLocation, completionScanner.cursorLocation, this.assistNodeParent);
686
687 this.cursorLocation = Integer.MAX_VALUE;
688 completionScanner.cursorLocation = Integer.MAX_VALUE;
689
690 return parserState;
691 }
buildMoreAnnotationCompletionContext(MemberValuePair memberValuePair)692 private void buildMoreAnnotationCompletionContext(MemberValuePair memberValuePair) {
693 if(this.identifierPtr < 0 || this.identifierLengthPtr < 0 ) return;
694
695 TypeReference typeReference = getAnnotationType();
696
697 int nodesToRemove = this.astPtr > -1 && this.astStack[this.astPtr] == memberValuePair ? 1 : 0;
698
699 NormalAnnotation annotation;
700 if (memberValuePair instanceof CompletionOnMemberValueName) {
701 MemberValuePair[] memberValuePairs = null;
702 int length;
703 if (this.astLengthPtr > -1 && (length = this.astLengthStack[this.astLengthPtr--]) > nodesToRemove) {
704 if (this.astStack[this.astPtr] instanceof MemberValuePair) {
705 System.arraycopy(
706 this.astStack,
707 (this.astPtr -= length) + 1,
708 memberValuePairs = new MemberValuePair[length - nodesToRemove],
709 0,
710 length - nodesToRemove);
711 }
712 }
713 annotation =
714 new CompletionOnAnnotationMemberValuePair(
715 typeReference,
716 this.intStack[this.intPtr--],
717 memberValuePairs,
718 memberValuePair);
719
720 this.assistNode = memberValuePair;
721 this.assistNodeParent = annotation;
722
723 if (memberValuePair.sourceEnd >= this.lastCheckPoint) {
724 this.lastCheckPoint = memberValuePair.sourceEnd + 1;
725 }
726 } else {
727 MemberValuePair[] memberValuePairs = null;
728 int length = 0;
729 if (this.astLengthPtr > -1 && (length = this.astLengthStack[this.astLengthPtr--]) > nodesToRemove) {
730 if (this.astStack[this.astPtr] instanceof MemberValuePair) {
731 System.arraycopy(
732 this.astStack,
733 (this.astPtr -= length) + 1,
734 memberValuePairs = new MemberValuePair[length - nodesToRemove + 1],
735 0,
736 length - nodesToRemove);
737 }
738 if(memberValuePairs != null) {
739 memberValuePairs[length - nodesToRemove] = memberValuePair;
740 } else {
741 memberValuePairs = new MemberValuePair[]{memberValuePair};
742 }
743 } else {
744 memberValuePairs = new MemberValuePair[]{memberValuePair};
745 }
746
747 annotation =
748 new NormalAnnotation(
749 typeReference,
750 this.intStack[this.intPtr--]);
751 annotation.memberValuePairs = memberValuePairs;
752 this.assistNodeParent = annotation;
753
754 }
755 CompletionOnAnnotationOfType fakeType =
756 new CompletionOnAnnotationOfType(
757 FAKE_TYPE_NAME,
758 this.compilationUnit.compilationResult(),
759 annotation);
760
761 this.currentElement.add(fakeType, 0);
762 this.pendingAnnotation = fakeType;
763 }
buildMoreCompletionContext(Expression expression)764 private void buildMoreCompletionContext(Expression expression) {
765 Statement statement = expression;
766 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
767 if(kind != 0) {
768 int info = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER);
769 nextElement : switch (kind) {
770 case K_SELECTOR_QUALIFIER :
771 int selector = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER, 2);
772 if(selector == THIS_CONSTRUCTOR || selector == SUPER_CONSTRUCTOR) {
773 ExplicitConstructorCall call = new ExplicitConstructorCall(
774 (selector == THIS_CONSTRUCTOR) ?
775 ExplicitConstructorCall.This :
776 ExplicitConstructorCall.Super
777 );
778 call.arguments = new Expression[] {expression};
779 call.sourceStart = expression.sourceStart;
780 call.sourceEnd = expression.sourceEnd;
781 this.assistNodeParent = call;
782 } else {
783 int invocType = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER,1);
784 int qualifierExprPtr = info;
785
786 // find arguments
787 int length = this.expressionLengthStack[this.expressionLengthPtr];
788
789 // search previous arguments if missing
790 if(this.expressionPtr > 0 && this.expressionLengthPtr > 0 && length == 1) {
791 int start = (int) (this.identifierPositionStack[selector] >>> 32);
792 if(this.expressionStack[this.expressionPtr-1] != null && this.expressionStack[this.expressionPtr-1].sourceStart > start) {
793 length += this.expressionLengthStack[this.expressionLengthPtr-1];
794 }
795
796 }
797
798 Expression[] arguments = null;
799 if (length != 0) {
800 arguments = new Expression[length];
801 this.expressionPtr -= length;
802 System.arraycopy(this.expressionStack, this.expressionPtr + 1, arguments, 0, length-1);
803 arguments[length-1] = expression;
804 }
805
806 if(invocType != ALLOCATION && invocType != QUALIFIED_ALLOCATION) {
807 MessageSend messageSend = new MessageSend();
808 messageSend.selector = this.identifierStack[selector];
809 messageSend.arguments = arguments;
810
811 // find receiver
812 switch (invocType) {
813 case NO_RECEIVER:
814 messageSend.receiver = ThisReference.implicitThis();
815 break;
816 case NAME_RECEIVER:
817 // remove special flags for primitive types
818 while (this.identifierLengthPtr >= 0 && this.identifierLengthStack[this.identifierLengthPtr] < 0) {
819 this.identifierLengthPtr--;
820 }
821
822 // remove selector
823 this.identifierPtr--;
824 if(this.genericsPtr > -1 && this.genericsLengthPtr > -1 && this.genericsLengthStack[this.genericsLengthPtr] > 0) {
825 // is inside a paremeterized method: bar.<X>.foo
826 this.identifierLengthPtr--;
827 } else {
828 this.identifierLengthStack[this.identifierLengthPtr]--;
829 length = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr--];
830 Annotation [] typeAnnotations;
831 if (length != 0) {
832 System.arraycopy(
833 this.typeAnnotationStack,
834 (this.typeAnnotationPtr -= length) + 1,
835 typeAnnotations = new Annotation[length],
836 0,
837 length);
838 problemReporter().misplacedTypeAnnotations(typeAnnotations[0], typeAnnotations[typeAnnotations.length - 1]);
839 }
840 }
841 // consume the receiver
842 int identifierLength = this.identifierLengthStack[this.identifierLengthPtr];
843 if(this.identifierPtr > -1 && identifierLength > 0 && this.identifierPtr + 1 >= identifierLength) {
844 messageSend.receiver = getUnspecifiedReference();
845 } else {
846 messageSend = null;
847 }
848 break;
849 case SUPER_RECEIVER:
850 messageSend.receiver = new SuperReference(0, 0);
851 break;
852 case EXPLICIT_RECEIVER:
853 messageSend.receiver = this.expressionStack[qualifierExprPtr];
854 break;
855 default :
856 messageSend.receiver = ThisReference.implicitThis();
857 break;
858 }
859 this.assistNodeParent = messageSend;
860 } else {
861 if(invocType == ALLOCATION) {
862 AllocationExpression allocationExpr = new AllocationExpression();
863 allocationExpr.arguments = arguments;
864 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
865 pushOnGenericsLengthStack(0);
866 allocationExpr.type = getTypeReference(0);
867 this.assistNodeParent = allocationExpr;
868 } else {
869 QualifiedAllocationExpression allocationExpr = new QualifiedAllocationExpression();
870 allocationExpr.enclosingInstance = this.expressionStack[qualifierExprPtr];
871 allocationExpr.arguments = arguments;
872 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
873 pushOnGenericsLengthStack(0);
874
875 allocationExpr.type = getTypeReference(0);
876 this.assistNodeParent = allocationExpr;
877 }
878 }
879 }
880 break nextElement;
881 case K_INSIDE_RETURN_STATEMENT :
882 if(info == this.bracketDepth) {
883 ReturnStatement returnStatement = new ReturnStatement(expression, expression.sourceStart, expression.sourceEnd);
884 this.assistNodeParent = returnStatement;
885 }
886 break nextElement;
887 case K_CAST_STATEMENT :
888 Expression castType;
889 if(this.expressionPtr > 0
890 && ((castType = this.expressionStack[this.expressionPtr-1]) instanceof TypeReference)) {
891 CastExpression cast = new CastExpression(expression, (TypeReference) castType);
892 cast.sourceStart = castType.sourceStart;
893 cast.sourceEnd= expression.sourceEnd;
894 this.assistNodeParent = cast;
895 }
896 break nextElement;
897 case K_UNARY_OPERATOR :
898 if(this.expressionPtr > -1) {
899 Expression operatorExpression = null;
900 switch (info) {
901 case PLUS_PLUS :
902 operatorExpression = new PrefixExpression(expression,IntLiteral.One, PLUS, expression.sourceStart);
903 break;
904 case MINUS_MINUS :
905 operatorExpression = new PrefixExpression(expression,IntLiteral.One, MINUS, expression.sourceStart);
906 break;
907 default :
908 operatorExpression = new UnaryExpression(expression, info);
909 break;
910 }
911 this.assistNodeParent = operatorExpression;
912 }
913 break nextElement;
914 case K_BINARY_OPERATOR :
915 if(this.expressionPtr > -1) {
916 Expression operatorExpression = null;
917 Expression left = null;
918 if(this.expressionPtr == 0) {
919 // it is a ***_NotName rule
920 if(this.identifierPtr > -1) {
921 left = getUnspecifiedReferenceOptimized();
922 }
923 } else {
924 left = this.expressionStack[this.expressionPtr-1];
925 // is it a ***_NotName rule ?
926 if(this.identifierPtr > -1) {
927 int start = (int) (this.identifierPositionStack[this.identifierPtr] >>> 32);
928 if(left.sourceStart < start) {
929 left = getUnspecifiedReferenceOptimized();
930 }
931 }
932 }
933
934 if(left != null) {
935 switch (info) {
936 case AND_AND :
937 operatorExpression = new AND_AND_Expression(left, expression, info);
938 break;
939 case OR_OR :
940 operatorExpression = new OR_OR_Expression(left, expression, info);
941 break;
942 case EQUAL_EQUAL :
943 case NOT_EQUAL :
944 operatorExpression = new EqualExpression(left, expression, info);
945 break;
946 default :
947 operatorExpression = new BinaryExpression(left, expression, info);
948 break;
949 }
950 }
951 if(operatorExpression != null) {
952 this.assistNodeParent = operatorExpression;
953 }
954 }
955 break nextElement;
956 case K_ARRAY_INITIALIZER :
957 ArrayInitializer arrayInitializer = new ArrayInitializer();
958 arrayInitializer.expressions = new Expression[]{expression};
959 this.expressionPtr -= this.expressionLengthStack[this.expressionLengthPtr--];
960
961 if(this.expressionLengthPtr > -1
962 && this.expressionPtr > -1
963 && this.expressionStack[this.expressionPtr] != null
964 && this.expressionStack[this.expressionPtr].sourceStart > info) {
965 this.expressionLengthPtr--;
966 }
967
968 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, 1) == K_ARRAY_CREATION) {
969 ArrayAllocationExpression allocationExpression = new ArrayAllocationExpression();
970 pushOnGenericsLengthStack(0);
971 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
972 allocationExpression.type = getTypeReference(0);
973 allocationExpression.type.bits |= ASTNode.IgnoreRawTypeCheck; // no need to worry about raw type usage
974 int length = this.expressionLengthStack[this.expressionLengthPtr];
975 allocationExpression.dimensions = new Expression[length];
976
977 allocationExpression.initializer = arrayInitializer;
978 this.assistNodeParent = allocationExpression;
979 } else if(this.currentElement instanceof RecoveredField && !(this.currentElement instanceof RecoveredInitializer)) {
980 RecoveredField recoveredField = (RecoveredField) this.currentElement;
981 if(recoveredField.fieldDeclaration.type.dimensions() == 0) {
982 Block block = new Block(0);
983 block.sourceStart = info;
984 this.currentElement = this.currentElement.add(block, 1);
985 } else {
986 statement = arrayInitializer;
987 }
988 } else if(this.currentElement instanceof RecoveredLocalVariable) {
989 RecoveredLocalVariable recoveredLocalVariable = (RecoveredLocalVariable) this.currentElement;
990 if(recoveredLocalVariable.localDeclaration.type.dimensions() == 0) {
991 Block block = new Block(0);
992 block.sourceStart = info;
993 this.currentElement = this.currentElement.add(block, 1);
994 } else {
995 statement = arrayInitializer;
996 }
997 } else {
998 statement = arrayInitializer;
999 }
1000 break nextElement;
1001 case K_ARRAY_CREATION :
1002 ArrayAllocationExpression allocationExpression = new ArrayAllocationExpression();
1003 allocationExpression.type = getTypeReference(0);
1004 allocationExpression.dimensions = new Expression[]{expression};
1005
1006 this.assistNodeParent = allocationExpression;
1007 break nextElement;
1008 case K_ASSISGNMENT_OPERATOR :
1009 if(this.expressionPtr > 0 && this.expressionStack[this.expressionPtr - 1] != null) {
1010 Assignment assignment;
1011 if(info == EQUAL) {
1012 assignment = new Assignment(
1013 this.expressionStack[this.expressionPtr - 1],
1014 expression,
1015 expression.sourceEnd
1016 );
1017 } else {
1018 assignment = new CompoundAssignment(
1019 this.expressionStack[this.expressionPtr - 1],
1020 expression,
1021 info,
1022 expression.sourceEnd
1023 );
1024 }
1025 this.assistNodeParent = assignment;
1026 }
1027 break nextElement;
1028 case K_CONDITIONAL_OPERATOR :
1029 if(info == QUESTION) {
1030 if(this.expressionPtr > 0) {
1031 this.expressionPtr--;
1032 this.expressionLengthPtr--;
1033 this.expressionStack[this.expressionPtr] = this.expressionStack[this.expressionPtr+1];
1034 popElement(K_CONDITIONAL_OPERATOR);
1035 buildMoreCompletionContext(expression);
1036 return;
1037 }
1038 } else {
1039 if(this.expressionPtr > 1) {
1040 this.expressionPtr = this.expressionPtr - 2;
1041 this.expressionLengthPtr = this.expressionLengthPtr - 2;
1042 this.expressionStack[this.expressionPtr] = this.expressionStack[this.expressionPtr+2];
1043 popElement(K_CONDITIONAL_OPERATOR);
1044 buildMoreCompletionContext(expression);
1045 return;
1046 }
1047 }
1048 break nextElement;
1049 case K_BETWEEN_LEFT_AND_RIGHT_BRACKET :
1050 ArrayReference arrayReference;
1051 if(this.identifierPtr < 0 && this.expressionPtr > 0 && this.expressionStack[this.expressionPtr] == expression) {
1052 arrayReference =
1053 new ArrayReference(
1054 this.expressionStack[this.expressionPtr-1],
1055 expression);
1056 } else {
1057 arrayReference =
1058 new ArrayReference(
1059 getUnspecifiedReferenceOptimized(),
1060 expression);
1061 }
1062 this.assistNodeParent = arrayReference;
1063 break;
1064 case K_BETWEEN_CASE_AND_COLON :
1065 if(this.expressionPtr > 0) {
1066 SwitchStatement switchStatement = new SwitchStatement();
1067 switchStatement.expression = this.expressionStack[this.expressionPtr - 1];
1068 if(this.astLengthPtr > -1 && this.astPtr > -1) {
1069 int length = this.astLengthStack[this.astLengthPtr];
1070 int newAstPtr = this.astPtr - length;
1071 ASTNode firstNode = this.astStack[newAstPtr + 1];
1072 if(length != 0 && firstNode.sourceStart > switchStatement.expression.sourceEnd) {
1073 switchStatement.statements = new Statement[length + 1];
1074 System.arraycopy(
1075 this.astStack,
1076 newAstPtr + 1,
1077 switchStatement.statements,
1078 0,
1079 length);
1080 }
1081 }
1082 CaseStatement caseStatement = new CaseStatement(expression, expression.sourceStart, expression.sourceEnd);
1083 if(switchStatement.statements == null) {
1084 switchStatement.statements = new Statement[]{caseStatement};
1085 } else {
1086 switchStatement.statements[switchStatement.statements.length - 1] = caseStatement;
1087 }
1088 this.assistNodeParent = switchStatement;
1089 }
1090 break;
1091 case K_BETWEEN_IF_AND_RIGHT_PAREN :
1092 IfStatement ifStatement = new IfStatement(expression, new EmptyStatement(expression.sourceEnd, expression.sourceEnd), expression.sourceStart, expression.sourceEnd);
1093 this.assistNodeParent = ifStatement;
1094 break nextElement;
1095 case K_BETWEEN_WHILE_AND_RIGHT_PAREN :
1096 WhileStatement whileStatement = new WhileStatement(expression, new EmptyStatement(expression.sourceEnd, expression.sourceEnd), expression.sourceStart, expression.sourceEnd);
1097 this.assistNodeParent = whileStatement;
1098 break nextElement;
1099 case K_INSIDE_FOR_CONDITIONAL: // https://bugs.eclipse.org/bugs/show_bug.cgi?id=253008
1100 ForStatement forStatement = new ForStatement(new Statement[0], expression, new Statement[0],
1101 new EmptyStatement(expression.sourceEnd, expression.sourceEnd),
1102 false,
1103 expression.sourceStart, expression.sourceEnd);
1104 this.assistNodeParent = forStatement;
1105 break nextElement;
1106 case K_BETWEEN_SWITCH_AND_RIGHT_PAREN:
1107 SwitchStatement switchStatement = new SwitchStatement();
1108 switchStatement.expression = expression;
1109 switchStatement.statements = new Statement[0];
1110 this.assistNodeParent = switchStatement;
1111 break nextElement;
1112 case K_BETWEEN_SYNCHRONIZED_AND_RIGHT_PAREN :
1113 SynchronizedStatement synchronizedStatement = new SynchronizedStatement(expression, new Block(0), expression.sourceStart, expression.sourceEnd);
1114 this.assistNodeParent = synchronizedStatement;
1115 break nextElement;
1116 case K_INSIDE_THROW_STATEMENT:
1117 if(info == this.bracketDepth) {
1118 ThrowStatement throwStatement = new ThrowStatement(expression, expression.sourceStart, expression.sourceEnd);
1119 this.assistNodeParent = throwStatement;
1120 }
1121 break nextElement;
1122 case K_INSIDE_ASSERT_STATEMENT:
1123 if(info == this.bracketDepth) {
1124 AssertStatement assertStatement = new AssertStatement(expression, expression.sourceStart);
1125 this.assistNodeParent = assertStatement;
1126 }
1127 break nextElement;
1128 case K_INSIDE_ASSERT_EXCEPTION:
1129 if(info == this.bracketDepth) {
1130 AssertStatement assertStatement = new AssertStatement(expression, new TrueLiteral(expression.sourceStart, expression.sourceStart), expression.sourceStart);
1131 this.assistNodeParent = assertStatement;
1132 }
1133 break nextElement;
1134 }
1135 }
1136 if(this.assistNodeParent != null) {
1137 this.currentElement = this.currentElement.add(buildMoreCompletionEnclosingContext((Statement)this.assistNodeParent), 0);
1138 } else {
1139 if(this.currentElement instanceof RecoveredField && !(this.currentElement instanceof RecoveredInitializer)
1140 && ((RecoveredField) this.currentElement).fieldDeclaration.initialization == null) {
1141 if (lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) <= lastIndexOfElement(K_FIELD_INITIALIZER_DELIMITER))
1142 this.assistNodeParent = ((RecoveredField) this.currentElement).fieldDeclaration;
1143 this.currentElement = this.currentElement.add(buildMoreCompletionEnclosingContext(statement), 0);
1144 } else if(this.currentElement instanceof RecoveredLocalVariable
1145 && ((RecoveredLocalVariable) this.currentElement).localDeclaration.initialization == null) {
1146
1147 this.assistNodeParent = ((RecoveredLocalVariable) this.currentElement).localDeclaration;
1148 this.currentElement = this.currentElement.add(buildMoreCompletionEnclosingContext(statement), 0);
1149 } else {
1150 this.currentElement = this.currentElement.add(buildMoreCompletionEnclosingContext(expression), 0);
1151 }
1152 }
1153 }
buildMoreCompletionEnclosingContext(Statement statement)1154 private Statement buildMoreCompletionEnclosingContext(Statement statement) {
1155 IfStatement ifStatement = null;
1156 int index = -1;
1157 /*
1158 * What happens here? When we have an "instanceof" after the last
1159 * K_CONTROL_STATEMENT_DELIMITER (which represents if or else-if), the former
1160 * is taken to be the current point. Otherwise, the standard rule applies: i.e.
1161 * pick the block if it comes after the K_CONTROL_STATEMENT_DELIMITER, otherwise pick the
1162 * K_BLOCK_DELIMITER.
1163 */
1164 int blockIndex = lastIndexOfElement(K_BLOCK_DELIMITER);
1165 int controlIndex = lastIndexOfElement(K_CONTROL_STATEMENT_DELIMITER);
1166 int instanceOfIndex = lastIndexOfElement(K_BETWEEN_INSTANCEOF_AND_RPAREN);
1167 if (instanceOfIndex != -1 && instanceOfIndex > controlIndex) {
1168 index = instanceOfIndex;
1169 } else if (controlIndex == -1) {
1170 index = blockIndex;
1171 } else {
1172 index = blockIndex != -1 && controlIndex < blockIndex ? blockIndex : controlIndex;
1173 }
1174 while (index >= 0) {
1175 // Try to find an enclosing if statement even if one is not found immediately preceding the completion node.
1176 if (index != -1 && this.elementInfoStack[index] == IF && this.elementObjectInfoStack[index] != null) {
1177 Expression condition = (Expression)this.elementObjectInfoStack[index];
1178
1179 // If currentElement is a RecoveredLocalVariable then it can be contained in the if statement
1180 if (this.currentElement instanceof RecoveredLocalVariable &&
1181 this.currentElement.parent instanceof RecoveredBlock) {
1182 RecoveredLocalVariable recoveredLocalVariable = (RecoveredLocalVariable) this.currentElement;
1183 if (recoveredLocalVariable.localDeclaration.initialization == null &&
1184 statement instanceof Expression && ((Expression) statement).isTrulyExpression() &&
1185 condition.sourceStart < recoveredLocalVariable.localDeclaration.sourceStart) {
1186 this.currentElement.add(statement, 0);
1187
1188 statement = recoveredLocalVariable.updatedStatement(0, new HashSet<TypeDeclaration>());
1189
1190 // RecoveredLocalVariable must be removed from its parent because the IfStatement will be added instead
1191 RecoveredBlock recoveredBlock = (RecoveredBlock) recoveredLocalVariable.parent;
1192 recoveredBlock.statements[--recoveredBlock.statementCount] = null;
1193
1194 this.currentElement = recoveredBlock;
1195
1196 }
1197 }
1198 if (statement instanceof AND_AND_Expression && this.assistNode instanceof Statement) {
1199 statement = (Statement) this.assistNode;
1200 }
1201 ifStatement =
1202 new IfStatement(
1203 condition,
1204 statement,
1205 condition.sourceStart,
1206 statement.sourceEnd);
1207 index--;
1208 break;
1209 }
1210 index--;
1211 }
1212 if (ifStatement == null) {
1213 return statement;
1214 }
1215 // collect all if statements with instanceof expressions that enclose the completion node
1216 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=304006
1217 while (index >= 0) {
1218 if (this.elementInfoStack[index] == IF && this.elementObjectInfoStack[index] instanceof InstanceOfExpression) {
1219 InstanceOfExpression condition = (InstanceOfExpression)this.elementObjectInfoStack[index];
1220 ifStatement =
1221 new IfStatement(
1222 condition,
1223 ifStatement,
1224 condition.sourceStart,
1225 ifStatement.sourceEnd);
1226 }
1227 index--;
1228 }
1229 this.enclosingNode = ifStatement;
1230 return ifStatement;
1231 }
buildMoreGenericsCompletionContext(ASTNode node, boolean consumeTypeArguments)1232 private void buildMoreGenericsCompletionContext(ASTNode node, boolean consumeTypeArguments) {
1233 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
1234 if(kind != 0) {
1235 int info = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER);
1236 nextElement : switch (kind) {
1237 case K_BINARY_OPERATOR :
1238 int prevKind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, 1);
1239 switch (prevKind) {
1240 case K_PARAMETERIZED_ALLOCATION :
1241 if(this.invocationType == ALLOCATION || this.invocationType == QUALIFIED_ALLOCATION) {
1242 this.currentElement = this.currentElement.add((TypeReference)node, 0);
1243 }
1244 break nextElement;
1245 case K_PARAMETERIZED_METHOD_INVOCATION :
1246 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER, 1) == 0) {
1247 this.currentElement = this.currentElement.add((TypeReference)node, 0);
1248 break nextElement;
1249 }
1250 }
1251 if(info == LESS && node instanceof TypeReference) {
1252 if(this.identifierLengthPtr > -1 && this.identifierLengthStack[this.identifierLengthPtr]!= 0) {
1253 if (consumeTypeArguments) consumeTypeArguments();
1254 TypeReference ref = this.getTypeReference(0);
1255 if(prevKind == K_PARAMETERIZED_CAST) {
1256 ref = computeQualifiedGenericsFromRightSide(ref, 0, null);
1257 }
1258 if(this.currentElement instanceof RecoveredType) {
1259 this.currentElement = this.currentElement.add(new CompletionOnFieldType(ref, false), 0);
1260 } else {
1261
1262 if (prevKind == K_BETWEEN_NEW_AND_LEFT_BRACKET) {
1263
1264 AllocationExpression exp;
1265 if (this.expressionPtr > -1 && this.expressionStack[this.expressionPtr] instanceof AllocationExpression
1266 && this.invocationType == QUALIFIED_ALLOCATION) { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=361963
1267 exp = new QualifiedAllocationExpression();
1268 exp.type = ref;
1269 ((QualifiedAllocationExpression)exp).enclosingInstance = this.expressionStack[this.expressionPtr];
1270 } else {
1271 exp = new AllocationExpression();
1272 exp.type = ref;
1273 }
1274 if (isInsideReturn()) {
1275 ReturnStatement returnStatement = new ReturnStatement(exp, exp.sourceStart, exp.sourceEnd);
1276 this.enclosingNode = returnStatement;
1277 this.currentElement = this.currentElement.add(returnStatement,0);
1278 } else if (this.currentElement instanceof RecoveredLocalVariable) {
1279 if (((RecoveredLocalVariable)this.currentElement).localDeclaration.initialization == null) {
1280 this.enclosingNode = ((RecoveredLocalVariable) this.currentElement).localDeclaration;
1281 this.currentElement = this.currentElement.add(exp, 0);
1282 }
1283 } else if (this.currentElement instanceof RecoveredField) {
1284 if (((RecoveredField) this.currentElement).fieldDeclaration.initialization == null) {
1285 this.enclosingNode = ((RecoveredField) this.currentElement).fieldDeclaration;
1286 this.currentElement = this.currentElement.add(exp, 0);
1287 }
1288 } else {
1289 this.currentElement = this.currentElement.add(ref, 0);
1290 }
1291 } else {
1292 this.currentElement = this.currentElement.add(ref, 0);
1293 }
1294 }
1295 } else if (this.currentElement.enclosingMethod() != null &&
1296 this.currentElement.enclosingMethod().methodDeclaration.isConstructor()) {
1297 this.currentElement = this.currentElement.add((TypeReference)node, 0);
1298 }
1299 }
1300 break;
1301 }
1302 }
1303 }
buildMoreTryStatementCompletionContext(TypeReference exceptionRef)1304 private void buildMoreTryStatementCompletionContext(TypeReference exceptionRef) {
1305 if (this.astLengthPtr > 0 &&
1306 this.astPtr > 2 &&
1307 this.astStack[this.astPtr -1] instanceof Block &&
1308 this.astStack[this.astPtr - 2] instanceof Argument) {
1309 TryStatement tryStatement = new TryStatement();
1310
1311 int newAstPtr = this.astPtr - 1;
1312
1313 int length = this.astLengthStack[this.astLengthPtr - 1];
1314 Block[] bks = (tryStatement.catchBlocks = new Block[length + 1]);
1315 Argument[] args = (tryStatement.catchArguments = new Argument[length + 1]);
1316 if (length != 0) {
1317 while (length-- > 0) {
1318 bks[length] = (Block) this.astStack[newAstPtr--];
1319 bks[length].statements = null; // statements of catch block won't be used
1320 args[length] = (Argument) this.astStack[newAstPtr--];
1321 }
1322 }
1323
1324 bks[bks.length - 1] = new Block(0);
1325 if (this.astStack[this.astPtr] instanceof UnionTypeReference) {
1326 UnionTypeReference unionTypeReference = (UnionTypeReference) this.astStack[this.astPtr];
1327 args[args.length - 1] = new Argument(FAKE_ARGUMENT_NAME,0,unionTypeReference,0);
1328 } else {
1329 args[args.length - 1] = new Argument(FAKE_ARGUMENT_NAME,0,exceptionRef,0);
1330 }
1331
1332 tryStatement.tryBlock = (Block) this.astStack[newAstPtr--];
1333
1334 this.assistNodeParent = tryStatement;
1335
1336 this.currentElement.add(tryStatement, 0);
1337 } else if (this.astLengthPtr > -1 &&
1338 this.astPtr > 0 &&
1339 this.astStack[this.astPtr - 1] instanceof Block) {
1340 TryStatement tryStatement = new TryStatement();
1341
1342 int newAstPtr = this.astPtr - 1;
1343
1344 Block[] bks = (tryStatement.catchBlocks = new Block[1]);
1345 Argument[] args = (tryStatement.catchArguments = new Argument[1]);
1346
1347 bks[0] = new Block(0);
1348 if (this.astStack[this.astPtr] instanceof UnionTypeReference) {
1349 UnionTypeReference unionTypeReference = (UnionTypeReference) this.astStack[this.astPtr];
1350 args[0] = new Argument(FAKE_ARGUMENT_NAME,0,unionTypeReference,0);
1351 } else {
1352 args[0] = new Argument(FAKE_ARGUMENT_NAME,0,exceptionRef,0);
1353 }
1354
1355 tryStatement.tryBlock = (Block) this.astStack[newAstPtr--];
1356
1357 this.assistNodeParent = tryStatement;
1358
1359 this.currentElement.add(tryStatement, 0);
1360 }else {
1361 this.currentElement = this.currentElement.add(exceptionRef, 0);
1362 }
1363 }
1364 @Override
bodyEnd(AbstractMethodDeclaration method)1365 public int bodyEnd(AbstractMethodDeclaration method){
1366 return this.cursorLocation;
1367 }
1368 @Override
bodyEnd(Initializer initializer)1369 public int bodyEnd(Initializer initializer){
1370 return this.cursorLocation;
1371 }
1372 @Override
checkAndSetModifiers(int flag)1373 protected void checkAndSetModifiers(int flag) {
1374 super.checkAndSetModifiers(flag);
1375
1376 if (isInsideMethod()) {
1377 this.hasUnusedModifiers = true;
1378 }
1379 }
1380 @Override
consumePushCombineModifiers()1381 protected void consumePushCombineModifiers() {
1382 super.consumePushCombineModifiers();
1383
1384 if (isInsideMethod()) {
1385 this.hasUnusedModifiers = true;
1386 }
1387 }
1388 /**
1389 * Checks if the completion is on the type following a 'new'.
1390 * Returns whether we found a completion node.
1391 */
checkClassInstanceCreation()1392 private boolean checkClassInstanceCreation() {
1393 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_NEW_AND_LEFT_BRACKET) {
1394 int length = this.identifierLengthStack[this.identifierLengthPtr];
1395 int numberOfIdentifiers = this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr];
1396 if (length != numberOfIdentifiers || this.genericsLengthStack[this.genericsLengthPtr] != 0) {
1397 // no class instance creation with a parameterized type
1398 return true;
1399 }
1400
1401 // completion on type inside an allocation expression
1402
1403 TypeReference type;
1404 if (this.invocationType == ALLOCATION) {
1405 // non qualified allocation expression
1406 AllocationExpression allocExpr = new AllocationExpression();
1407 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, 1) == K_INSIDE_THROW_STATEMENT
1408 && topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER, 1) == this.bracketDepth) {
1409 pushOnElementStack(K_NEXT_TYPEREF_IS_EXCEPTION);
1410 type = getTypeReference(0);
1411 popElement(K_NEXT_TYPEREF_IS_EXCEPTION);
1412 } else {
1413 type = getTypeReference(0);
1414 }
1415 if(type instanceof CompletionOnSingleTypeReference) {
1416 ((CompletionOnSingleTypeReference)type).isConstructorType = true;
1417 } else if (type instanceof CompletionOnQualifiedTypeReference) {
1418 ((CompletionOnQualifiedTypeReference)type).isConstructorType = true;
1419 }
1420 allocExpr.type = type;
1421 allocExpr.sourceStart = type.sourceStart;
1422 allocExpr.sourceEnd = type.sourceEnd;
1423 pushOnExpressionStack(allocExpr);
1424 this.isOrphanCompletionNode = false;
1425 } else {
1426 // qualified allocation expression
1427 QualifiedAllocationExpression allocExpr = new QualifiedAllocationExpression();
1428 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
1429 pushOnGenericsLengthStack(0);
1430 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, 1) == K_INSIDE_THROW_STATEMENT
1431 && topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER, 1) == this.bracketDepth) {
1432 pushOnElementStack(K_NEXT_TYPEREF_IS_EXCEPTION);
1433 type = getTypeReference(0);
1434 popElement(K_NEXT_TYPEREF_IS_EXCEPTION);
1435 } else {
1436 type = getTypeReference(0);
1437 }
1438 if(type instanceof CompletionOnSingleTypeReference) {
1439 ((CompletionOnSingleTypeReference)type).isConstructorType = true;
1440 }
1441 allocExpr.type = type;
1442 allocExpr.enclosingInstance = this.expressionStack[this.qualifier];
1443 allocExpr.sourceStart = this.intStack[this.intPtr--];
1444 allocExpr.sourceEnd = type.sourceEnd;
1445 this.expressionStack[this.qualifier] = allocExpr; // attach it now (it replaces the qualifier expression)
1446 this.isOrphanCompletionNode = false;
1447 }
1448 this.assistNode = type;
1449 this.lastCheckPoint = type.sourceEnd + 1;
1450
1451 popElement(K_BETWEEN_NEW_AND_LEFT_BRACKET);
1452 return true;
1453 }
1454 return false;
1455 }
1456 /**
1457 * Checks if the completion is on the dot following an array type,
1458 * a primitive type or an primitive array type.
1459 * Returns whether we found a completion node.
1460 */
checkClassLiteralAccess()1461 private boolean checkClassLiteralAccess() {
1462 if (this.identifierLengthPtr >= 1 && this.previousToken == TokenNameDOT) { // (NB: the top id length is 1 and it is for the completion identifier)
1463 int length;
1464 // if the penultimate id length is negative,
1465 // the completion is after a primitive type or a primitive array type
1466 if ((length = this.identifierLengthStack[this.identifierLengthPtr-1]) < 0) {
1467 // build the primitive type node
1468 int dim = isAfterArrayType() ? this.intStack[this.intPtr--] : 0;
1469 Annotation [][] annotationsOnDimensions = dim == 0 ? null : getAnnotationsOnDimensions(dim);
1470 SingleTypeReference typeRef = (SingleTypeReference)TypeReference.baseTypeReference(-length, dim, annotationsOnDimensions);
1471 typeRef.sourceStart = this.intStack[this.intPtr--];
1472 if (dim == 0) {
1473 typeRef.sourceEnd = this.intStack[this.intPtr--];
1474 } else {
1475 this.intPtr--;
1476 typeRef.sourceEnd = this.endPosition;
1477 }
1478 //typeRef.sourceEnd = typeRef.sourceStart + typeRef.token.length; // NB: It's ok to use the length of the token since it doesn't contain any unicode
1479
1480 // find the completion identifier and its source positions
1481 char[] source = this.identifierStack[this.identifierPtr];
1482 long pos = this.identifierPositionStack[this.identifierPtr--];
1483 this.identifierLengthPtr--; // it can only be a simple identifier (so its length is one)
1484
1485 // build the completion on class literal access node
1486 CompletionOnClassLiteralAccess access = new CompletionOnClassLiteralAccess(pos, typeRef);
1487 access.completionIdentifier = source;
1488 this.identifierLengthPtr--; // pop the length that was used to say it is a primitive type
1489 this.assistNode = access;
1490 this.isOrphanCompletionNode = true;
1491 return true;
1492 }
1493
1494 // if the completion is after a regular array type
1495 if (isAfterArrayType()) {
1496 // find the completion identifier and its source positions
1497 char[] source = this.identifierStack[this.identifierPtr];
1498 long pos = this.identifierPositionStack[this.identifierPtr--];
1499 this.identifierLengthPtr--; // it can only be a simple identifier (so its length is one)
1500
1501 // get the type reference
1502 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
1503 pushOnGenericsLengthStack(0);
1504
1505 TypeReference typeRef = getTypeReference(this.intStack[this.intPtr--]);
1506
1507 // build the completion on class literal access node
1508 CompletionOnClassLiteralAccess access = new CompletionOnClassLiteralAccess(pos, typeRef);
1509 access.completionIdentifier = source;
1510 this.assistNode = access;
1511 this.isOrphanCompletionNode = true;
1512 return true;
1513 }
1514
1515 }
1516 return false;
1517 }
checkKeyword()1518 private boolean checkKeyword() {
1519 if (this.currentElement instanceof RecoveredUnit) {
1520 RecoveredUnit unit = (RecoveredUnit) this.currentElement;
1521 if (unit.unitDeclaration.isModuleInfo()) return false;
1522 int index = -1;
1523 if ((index = this.indexOfAssistIdentifier()) > -1) {
1524 int ptr = this.identifierPtr - this.identifierLengthStack[this.identifierLengthPtr] + index + 1;
1525
1526 char[] ident = this.identifierStack[ptr];
1527 long pos = this.identifierPositionStack[ptr];
1528
1529 char[][] keywords = new char[Keywords.COUNT][];
1530 int count = 0;
1531 if(unit.typeCount == 0
1532 && (!this.compilationUnit.isPackageInfo() || this.compilationUnit.currentPackage != null)
1533 && this.lastModifiers == ClassFileConstants.AccDefault) {
1534 keywords[count++] = Keywords.IMPORT;
1535 }
1536 if(unit.typeCount == 0
1537 && unit.importCount == 0
1538 && this.lastModifiers == ClassFileConstants.AccDefault
1539 && this.compilationUnit.currentPackage == null) {
1540 keywords[count++] = Keywords.PACKAGE;
1541 }
1542 if (!this.compilationUnit.isPackageInfo()) {
1543 if((this.lastModifiers & ClassFileConstants.AccPublic) == 0) {
1544 boolean hasNoPublicType = true;
1545 for (int i = 0; i < unit.typeCount; i++) {
1546 if((unit.types[i].typeDeclaration.modifiers & ClassFileConstants.AccPublic) != 0) {
1547 hasNoPublicType = false;
1548 }
1549 }
1550 if(hasNoPublicType) {
1551 keywords[count++] = Keywords.PUBLIC;
1552 }
1553 }
1554 if((this.lastModifiers & ClassFileConstants.AccAbstract) == 0
1555 && (this.lastModifiers & ClassFileConstants.AccFinal) == 0) {
1556 keywords[count++] = Keywords.ABSTRACT;
1557 }
1558 if((this.lastModifiers & ClassFileConstants.AccAbstract) == 0
1559 && (this.lastModifiers & ClassFileConstants.AccFinal) == 0) {
1560 keywords[count++] = Keywords.FINAL;
1561 }
1562
1563 keywords[count++] = Keywords.CLASS;
1564 if (this.options.complianceLevel >= ClassFileConstants.JDK1_5) {
1565 keywords[count++] = Keywords.ENUM;
1566 }
1567
1568 if((this.lastModifiers & ClassFileConstants.AccFinal) == 0) {
1569 keywords[count++] = Keywords.INTERFACE;
1570 }
1571 }
1572 if(count != 0) {
1573 System.arraycopy(keywords, 0, keywords = new char[count][], 0, count);
1574
1575 this.assistNode = new CompletionOnKeyword2(ident, pos, keywords);
1576 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
1577 this.isOrphanCompletionNode = true;
1578 return true;
1579 }
1580 }
1581 }
1582 return false;
1583 }
1584
1585 private enum ModuleKeyword {
1586 FIRST_ALL,
1587 TO,
1588 PROVIDES_WITH,
1589 NOT_A_KEYWORD
1590 }
1591
getKeyword()1592 private ModuleKeyword getKeyword() {
1593 ModuleKeyword keyword = ModuleKeyword.FIRST_ALL;
1594 if (isInModuleStatements()) {
1595 if (foundToken(K_AFTER_PACKAGE_IN_PACKAGE_VISIBILITY_STATEMENT)) keyword = ModuleKeyword.TO;
1596 else if (foundToken(K_AFTER_NAME_IN_PROVIDES_STATEMENT)) keyword = ModuleKeyword.PROVIDES_WITH;
1597 else keyword = ModuleKeyword.NOT_A_KEYWORD;
1598 }
1599 return keyword;
1600 }
getModuleKeywords(ModuleKeyword keyword)1601 private char[][] getModuleKeywords(ModuleKeyword keyword) {
1602 if (keyword == ModuleKeyword.TO) return new char[][]{Keywords.TO};
1603 else if (keyword == ModuleKeyword.PROVIDES_WITH) return new char[][]{Keywords.WITH};
1604 else return new char[][]{Keywords.EXPORTS, Keywords.OPENS, Keywords.REQUIRES, Keywords.PROVIDES, Keywords.USES};
1605 }
checkModuleInfoConstructs()1606 private boolean checkModuleInfoConstructs() {
1607
1608 if (!isInsideModuleInfo()) return false;
1609
1610 int index = -1;
1611 if ((index = this.indexOfAssistIdentifier()) <= -1) return false;
1612
1613 if (this.currentElement instanceof RecoveredModule) {
1614 RecoveredModule module = (RecoveredModule) this.currentElement;
1615 if (checkModuleInfoKeyword(module, index)) return true;
1616 } else {
1617 ModuleKeyword keyword = ModuleKeyword.NOT_A_KEYWORD;
1618 if (isInModuleStatements()) {
1619 if (foundToken(K_AFTER_PACKAGE_IN_PACKAGE_VISIBILITY_STATEMENT)) keyword = ModuleKeyword.TO;
1620 if (foundToken(K_AFTER_NAME_IN_PROVIDES_STATEMENT)) keyword = ModuleKeyword.PROVIDES_WITH;
1621 }
1622 if (keyword == ModuleKeyword.NOT_A_KEYWORD) return false;
1623
1624 int length = this.identifierLengthStack[this.identifierLengthPtr];
1625 int ptr = this.identifierPtr - length + index + 1;
1626
1627 char[] ident = this.identifierStack[ptr];
1628 long pos = this.identifierPositionStack[ptr];
1629 char[][] keywords = getModuleKeywords(keyword);
1630 if (this.currentElement instanceof RecoveredPackageVisibilityStatement) {
1631 RecoveredPackageVisibilityStatement rPvs = (RecoveredPackageVisibilityStatement) this.currentElement;
1632 rPvs.add(new CompletionOnKeywordModule2(ident, pos, keywords), 0);
1633 return true;
1634 } else if (this.currentElement instanceof RecoveredProvidesStatement) {
1635 RecoveredProvidesStatement rPs = (RecoveredProvidesStatement) this.currentElement;
1636 rPs.add(new CompletionOnKeyword1(ident, pos, keywords), 0);
1637 return true;
1638 }
1639 }
1640 return false;
1641 }
checkModuleInfoKeyword(RecoveredModule module, int index)1642 private boolean checkModuleInfoKeyword(RecoveredModule module, int index) {
1643 ModuleKeyword keyword = getKeyword();
1644 if (keyword == ModuleKeyword.NOT_A_KEYWORD) return false;
1645
1646 int length = this.identifierLengthStack[this.identifierLengthPtr];
1647 int ptr = this.identifierPtr - length + index + 1;
1648
1649 char[] ident = this.identifierStack[ptr];
1650 long pos = this.identifierPositionStack[ptr];
1651 char[][] keywords = getModuleKeywords(keyword);
1652 module.add(new CompletionOnKeywordModuleInfo(ident, pos, keywords), 0);
1653 return true;
1654 }
1655
checkInstanceofKeyword()1656 private boolean checkInstanceofKeyword() {
1657 if(isInsideMethod()) {
1658 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
1659 int index;
1660 if(kind != K_BLOCK_DELIMITER
1661 && (index = indexOfAssistIdentifier()) > -1
1662 && this.expressionPtr > -1
1663 && this.expressionLengthStack[this.expressionPtr] == 1) {
1664
1665 int ptr = this.identifierPtr - this.identifierLengthStack[this.identifierLengthPtr] + index + 1;
1666 if(this.identifierStack[ptr].length > 0 && CharOperation.prefixEquals(this.identifierStack[ptr], Keywords.INSTANCEOF)) {
1667 this.assistNode = new CompletionOnKeyword3(
1668 this.identifierStack[ptr],
1669 this.identifierPositionStack[ptr],
1670 Keywords.INSTANCEOF);
1671 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
1672 this.isOrphanCompletionNode = true;
1673 return true;
1674 }
1675 }
1676 }
1677 return false;
1678 }
checkYieldKeyword()1679 private boolean checkYieldKeyword() {
1680 // Clients to ensure that we are already inside a method
1681 char[] id = this.scanner.getCurrentIdentifierSource();
1682 if(id.length > 0 && CharOperation.prefixEquals(id, Keywords.YIELD)) {
1683 return true;
1684 }
1685 return false;
1686 }
1687 /**
1688 * Checks if the completion is inside a method invocation or a constructor invocation.
1689 * Returns whether we found a completion node.
1690 */
checkInvocation()1691 private boolean checkInvocation() {
1692 Expression topExpression = this.expressionPtr >= 0 ?
1693 this.expressionStack[this.expressionPtr] :
1694 null;
1695 boolean isEmptyNameCompletion = false;
1696 boolean isEmptyAssistIdentifier = false;
1697 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SELECTOR_QUALIFIER
1698 && ((isEmptyNameCompletion = topExpression == this.assistNode && isEmptyNameCompletion()) // e.g. it is something like "this.fred([cursor]" but it is not something like "this.fred(1 + [cursor]"
1699 || (isEmptyAssistIdentifier = this.indexOfAssistIdentifier() >= 0 && this.identifierStack[this.identifierPtr].length == 0))) { // e.g. it is something like "this.fred(1 [cursor]"
1700
1701 // pop empty name completion
1702 if (isEmptyNameCompletion) {
1703 this.expressionPtr--;
1704 this.expressionLengthStack[this.expressionLengthPtr]--;
1705 } else if (isEmptyAssistIdentifier) {
1706 this.identifierPtr--;
1707 this.identifierLengthPtr--;
1708 }
1709
1710 // find receiver and qualifier
1711 int invocType = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER, 1);
1712 int qualifierExprPtr = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER);
1713
1714 // find arguments
1715 int numArgs = this.expressionPtr - qualifierExprPtr;
1716 int argStart = qualifierExprPtr + 1;
1717 Expression[] arguments = null;
1718 if (numArgs > 0) {
1719 // remember the arguments
1720 arguments = new Expression[numArgs];
1721 System.arraycopy(this.expressionStack, argStart, arguments, 0, numArgs);
1722
1723 // consume the expression arguments
1724 this.expressionPtr -= numArgs;
1725 int count = numArgs;
1726 while (count > 0) {
1727 count -= this.expressionLengthStack[this.expressionLengthPtr--];
1728 }
1729 }
1730
1731 // build ast node
1732 if (invocType != ALLOCATION && invocType != QUALIFIED_ALLOCATION) {
1733 // creates completion on message send
1734 CompletionOnMessageSend messageSend = new CompletionOnMessageSend();
1735 messageSend.arguments = arguments;
1736 switch (invocType) {
1737 case NO_RECEIVER:
1738 // implicit this
1739 messageSend.receiver = ThisReference.implicitThis();
1740 break;
1741 case NAME_RECEIVER:
1742 // remove special flags for primitive types
1743 while (this.identifierLengthPtr >= 0 && this.identifierLengthStack[this.identifierLengthPtr] < 0) {
1744 this.identifierLengthPtr--;
1745 }
1746
1747 // remove selector
1748 this.identifierPtr--;
1749 if(this.genericsPtr > -1 && this.genericsLengthPtr > -1 && this.genericsLengthStack[this.genericsLengthPtr] > 0) {
1750 // is inside a paremeterized method: bar.<X>.foo
1751 this.identifierLengthPtr--;
1752 } else {
1753 this.identifierLengthStack[this.identifierLengthPtr]--;
1754 int length = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr--];
1755 Annotation [] typeAnnotations;
1756 if (length != 0) {
1757 System.arraycopy(
1758 this.typeAnnotationStack,
1759 (this.typeAnnotationPtr -= length) + 1,
1760 typeAnnotations = new Annotation[length],
1761 0,
1762 length);
1763 problemReporter().misplacedTypeAnnotations(typeAnnotations[0], typeAnnotations[typeAnnotations.length - 1]);
1764 }
1765 }
1766 // consume the receiver
1767 messageSend.receiver = getUnspecifiedReference();
1768 break;
1769 case SUPER_RECEIVER:
1770 messageSend.receiver = new SuperReference(0, 0);
1771 break;
1772 case EXPLICIT_RECEIVER:
1773 messageSend.receiver = this.expressionStack[qualifierExprPtr];
1774 }
1775
1776 // set selector
1777 int selectorPtr = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER, 2);
1778 messageSend.selector = this.identifierStack[selectorPtr];
1779 // remove selector
1780 if (this.identifierLengthPtr >=0 && this.identifierLengthStack[this.identifierLengthPtr] == 1) {
1781 this.identifierPtr--;
1782 this.identifierLengthPtr--;
1783 }
1784
1785 // the entire message may be replaced in case qualification is needed
1786 messageSend.sourceStart = (int)(this.identifierPositionStack[selectorPtr] >> 32); //this.cursorLocation + 1;
1787 messageSend.sourceEnd = this.cursorLocation;
1788
1789 // remember the message send as an orphan completion node
1790 this.assistNode = messageSend;
1791 this.lastCheckPoint = messageSend.sourceEnd + 1;
1792 this.isOrphanCompletionNode = true;
1793 return true;
1794 } else {
1795 int selectorPtr = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER, 2);
1796 if (selectorPtr == THIS_CONSTRUCTOR || selectorPtr == SUPER_CONSTRUCTOR) {
1797 // creates an explicit constructor call
1798 CompletionOnExplicitConstructorCall call = new CompletionOnExplicitConstructorCall(
1799 (selectorPtr == THIS_CONSTRUCTOR) ? ExplicitConstructorCall.This : ExplicitConstructorCall.Super);
1800 call.arguments = arguments;
1801 if (invocType == QUALIFIED_ALLOCATION) {
1802 call.qualification = this.expressionStack[qualifierExprPtr];
1803 }
1804
1805 // no source is going to be replaced
1806 call.sourceStart = this.cursorLocation + 1;
1807 call.sourceEnd = this.cursorLocation;
1808
1809 // remember the explicit constructor call as an orphan completion node
1810 this.assistNode = call;
1811 this.lastCheckPoint = call.sourceEnd + 1;
1812 this.isOrphanCompletionNode = true;
1813 return true;
1814 } else {
1815 // creates an allocation expression
1816 CompletionOnQualifiedAllocationExpression allocExpr = new CompletionOnQualifiedAllocationExpression();
1817 allocExpr.arguments = arguments;
1818 if(this.genericsLengthPtr < 0) {
1819 pushOnGenericsLengthStack(0);
1820 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
1821 }
1822 allocExpr.type = super.getTypeReference(0); // we don't want a completion node here, so call super
1823 if (invocType == QUALIFIED_ALLOCATION) {
1824 allocExpr.enclosingInstance = this.expressionStack[qualifierExprPtr];
1825 }
1826 // no source is going to be replaced
1827 allocExpr.sourceStart = this.cursorLocation + 1;
1828 allocExpr.sourceEnd = this.cursorLocation;
1829
1830 // remember the allocation expression as an orphan completion node
1831 this.assistNode = allocExpr;
1832 this.lastCheckPoint = allocExpr.sourceEnd + 1;
1833 this.isOrphanCompletionNode = true;
1834 return true;
1835 }
1836 }
1837 }
1838 return false;
1839 }
checkLabelStatement()1840 private boolean checkLabelStatement() {
1841 if(isInsideMethod() || isInsideFieldInitialization()) {
1842
1843 int kind = this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
1844 if(kind != K_INSIDE_BREAK_STATEMENT && kind != K_INSIDE_CONTINUE_STATEMENT) return false;
1845
1846 if (indexOfAssistIdentifier() != 0) return false;
1847
1848 char[][] labels = new char[this.labelPtr + 1][];
1849 int labelCount = 0;
1850
1851 int labelKind = kind;
1852 int index = 1;
1853 while(labelKind != 0 && labelKind != K_METHOD_DELIMITER) {
1854 labelKind = this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, index);
1855 if(labelKind == K_LABEL) {
1856 int ptr = this.topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER, index);
1857 labels[labelCount++] = this.labelStack[ptr];
1858 }
1859 index++;
1860 }
1861 System.arraycopy(labels, 0, labels = new char[labelCount][], 0, labelCount);
1862
1863 long position = this.identifierPositionStack[this.identifierPtr];
1864 CompletionOnBranchStatementLabel statementLabel =
1865 new CompletionOnBranchStatementLabel(
1866 kind == K_INSIDE_BREAK_STATEMENT ? CompletionOnBranchStatementLabel.BREAK : CompletionOnBranchStatementLabel.CONTINUE,
1867 this.identifierStack[this.identifierPtr--],
1868 (int) (position >>> 32),
1869 (int)position,
1870 labels);
1871
1872 this.assistNode = statementLabel;
1873 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
1874 this.isOrphanCompletionNode = true;
1875 return true;
1876 }
1877 return false;
1878 }
1879 /**
1880 * Checks if the completion is on a member access (i.e. in an identifier following a dot).
1881 * Returns whether we found a completion node.
1882 */
checkMemberAccess()1883 private boolean checkMemberAccess() {
1884 if (this.previousToken == TokenNameDOT && this.qualifier > -1 && this.expressionPtr == this.qualifier) {
1885 if (this.identifierLengthPtr > 1 && this.identifierLengthStack[this.identifierLengthPtr - 1] < 0) {
1886 // its not a member access because the receiver is a base type
1887 // fix for bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=137623
1888 return false;
1889 }
1890 // the receiver is an expression
1891 pushCompletionOnMemberAccessOnExpressionStack(false);
1892 return true;
1893 }
1894 return false;
1895 }
1896 /**
1897 * Checks if the completion is on a name reference.
1898 * Returns whether we found a completion node.
1899 */
checkNameCompletion()1900 private boolean checkNameCompletion() {
1901 /*
1902 We didn't find any other completion, but the completion identifier is on the identifier stack,
1903 so it can only be a completion on name.
1904 Note that we allow the completion on a name even if nothing is expected (e.g. foo() b[cursor] would
1905 be a completion on 'b'). This policy gives more to the user than he/she would expect, but this
1906 simplifies the problem. To fix this, the recovery must be changed to work at a 'statement' granularity
1907 instead of at the 'expression' granularity as it does right now.
1908 */
1909
1910 // NB: at this point the completion identifier is on the identifier stack
1911 this.assistNode = getUnspecifiedReferenceOptimized();
1912 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
1913 this.isOrphanCompletionNode = true;
1914 if (this.hasUnusedModifiers &&
1915 this.assistNode instanceof CompletionOnSingleNameReference) {
1916 ((CompletionOnSingleNameReference)this.assistNode).isPrecededByModifiers = true;
1917 }
1918 return true;
1919 }
checkParemeterizedMethodName()1920 private boolean checkParemeterizedMethodName() {
1921 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_METHOD_INVOCATION &&
1922 topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == INSIDE_NAME) {
1923 if(this.identifierLengthPtr > -1 && this.genericsLengthPtr > -1 && this.genericsIdentifiersLengthPtr == -1) {
1924 CompletionOnMessageSendName m = null;
1925 switch (this.invocationType) {
1926 case EXPLICIT_RECEIVER:
1927 case NO_RECEIVER: // this case occurs with 'bar().foo'
1928 if(this.expressionPtr > -1 && this.expressionLengthStack[this.expressionLengthPtr] == 1) {
1929 char[] selector = this.identifierStack[this.identifierPtr];
1930 long position = this.identifierPositionStack[this.identifierPtr--];
1931 this.identifierLengthPtr--;
1932 int end = (int) position;
1933 int start = (int) (position >>> 32);
1934 m = new CompletionOnMessageSendName(selector, start, end);
1935
1936 // handle type arguments
1937 int length = this.genericsLengthStack[this.genericsLengthPtr--];
1938 this.genericsPtr -= length;
1939 System.arraycopy(this.genericsStack, this.genericsPtr + 1, m.typeArguments = new TypeReference[length], 0, length);
1940 this.intPtr--;
1941
1942 m.receiver = this.expressionStack[this.expressionPtr--];
1943 this.expressionLengthPtr--;
1944 }
1945 break;
1946 case NAME_RECEIVER:
1947 if(this.identifierPtr > 0) {
1948 char[] selector = this.identifierStack[this.identifierPtr];
1949 long position = this.identifierPositionStack[this.identifierPtr--];
1950 this.identifierLengthPtr--;
1951 int end = (int) position;
1952 int start = (int) (position >>> 32);
1953 m = new CompletionOnMessageSendName(selector, start, end);
1954
1955 // handle type arguments
1956 int length = this.genericsLengthStack[this.genericsLengthPtr--];
1957 this.genericsPtr -= length;
1958 System.arraycopy(this.genericsStack, this.genericsPtr + 1, m.typeArguments = new TypeReference[length], 0, length);
1959 this.intPtr--;
1960
1961 m.receiver = getUnspecifiedReference();
1962 }
1963 break;
1964 case SUPER_RECEIVER:
1965 char[] selector = this.identifierStack[this.identifierPtr];
1966 long position = this.identifierPositionStack[this.identifierPtr--];
1967 this.identifierLengthPtr--;
1968 int end = (int) position;
1969 int start = (int) (position >>> 32);
1970 m = new CompletionOnMessageSendName(selector, start, end);
1971
1972 // handle type arguments
1973 int length = this.genericsLengthStack[this.genericsLengthPtr--];
1974 this.genericsPtr -= length;
1975 System.arraycopy(this.genericsStack, this.genericsPtr + 1, m.typeArguments = new TypeReference[length], 0, length);
1976 this.intPtr--;
1977
1978 m.receiver = new SuperReference(start, end);
1979 break;
1980 }
1981
1982 if(m != null) {
1983 pushOnExpressionStack(m);
1984
1985 this.assistNode = m;
1986 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
1987 this.isOrphanCompletionNode = true;
1988 return true;
1989 }
1990 }
1991 }
1992 return false;
1993 }
checkParemeterizedType()1994 private boolean checkParemeterizedType() {
1995 if(this.identifierLengthPtr > -1 && this.genericsLengthPtr > -1 && this.genericsIdentifiersLengthPtr > -1) {
1996 int length = this.identifierLengthStack[this.identifierLengthPtr];
1997 int numberOfIdentifiers = this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr];
1998 if (length != numberOfIdentifiers || this.genericsLengthStack[this.genericsLengthPtr] != 0) {
1999 this.genericsIdentifiersLengthPtr--;
2000 this.identifierLengthPtr--;
2001 // generic type
2002 this.assistNode = getAssistTypeReferenceForGenericType(0, length, numberOfIdentifiers);
2003 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
2004 this.isOrphanCompletionNode = true;
2005 return true;
2006 } else if(this.genericsPtr > -1 && this.genericsStack[this.genericsPtr] instanceof TypeReference) {
2007 // type of a cast expression
2008 numberOfIdentifiers++;
2009
2010 this.genericsIdentifiersLengthPtr--;
2011 this.identifierLengthPtr--;
2012 // generic type
2013 this.assistNode = getAssistTypeReferenceForGenericType(0, length, numberOfIdentifiers);
2014 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
2015 this.isOrphanCompletionNode = true;
2016 return true;
2017 }
2018 }
2019 return false;
2020 }
2021 /**
2022 * Checks if the completion is in the context of a method and on the type of one of its arguments
2023 * Returns whether we found a completion node.
2024 */
checkRecoveredMethod()2025 private boolean checkRecoveredMethod() {
2026 if (this.currentElement instanceof RecoveredMethod){
2027 /* check if current awaiting identifier is the completion identifier */
2028 if (this.indexOfAssistIdentifier() < 0) return false;
2029
2030 /* check if on line with an error already - to avoid completing inside
2031 illegal type names e.g. int[<cursor> */
2032 if (this.lastErrorEndPosition <= this.cursorLocation
2033 && Util.getLineNumber(this.lastErrorEndPosition, this.scanner.lineEnds, 0, this.scanner.linePtr)
2034 == Util.getLineNumber(((CompletionScanner)this.scanner).completedIdentifierStart, this.scanner.lineEnds, 0, this.scanner.linePtr)){
2035 return false;
2036 }
2037 RecoveredMethod recoveredMethod = (RecoveredMethod)this.currentElement;
2038 /* only consider if inside method header */
2039 if (!recoveredMethod.foundOpeningBrace
2040 && this.lastIgnoredToken == -1) {
2041 //if (rParenPos < lParenPos){ // inside arguments
2042 this.assistNode = this.getTypeReference(0);
2043 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
2044 this.isOrphanCompletionNode = true;
2045 return true;
2046 }
2047 }
2048 return false;
2049 }
checkMemberValueName()2050 private boolean checkMemberValueName() {
2051 /* check if current awaiting identifier is the completion identifier */
2052 if (this.indexOfAssistIdentifier() < 0) return false;
2053
2054 if (this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) != K_BETWEEN_ANNOTATION_NAME_AND_RPAREN) return false;
2055
2056 if(this.identifierPtr > -1 && this.identifierLengthPtr > -1 && this.identifierLengthStack[this.identifierLengthPtr] == 1) {
2057 char[] simpleName = this.identifierStack[this.identifierPtr];
2058 long position = this.identifierPositionStack[this.identifierPtr--];
2059 this.identifierLengthPtr--;
2060 int end = (int) position;
2061 int start = (int) (position >>> 32);
2062
2063
2064 CompletionOnMemberValueName memberValueName = new CompletionOnMemberValueName(simpleName,start, end);
2065 this.assistNode = memberValueName;
2066 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
2067 this.isOrphanCompletionNode = true;
2068
2069 return true;
2070 }
2071 return false;
2072 }
2073 /**
2074 * Checks if the completion is in the context of a type and on a type reference in this type.
2075 * Persists the identifier into a fake field return type
2076 * Returns whether we found a completion node.
2077 */
checkRecoveredType()2078 private boolean checkRecoveredType() {
2079 if (this.currentElement instanceof RecoveredType){
2080 /* check if current awaiting identifier is the completion identifier */
2081 if (this.indexOfAssistIdentifier() < 0) return false;
2082
2083 /* check if on line with an error already - to avoid completing inside
2084 illegal type names e.g. int[<cursor> */
2085 if (this.lastErrorEndPosition <= this.cursorLocation
2086 && ((RecoveredType)this.currentElement).lastMemberEnd() < this.lastErrorEndPosition
2087 && Util.getLineNumber(this.lastErrorEndPosition, this.scanner.lineEnds, 0, this.scanner.linePtr)
2088 == Util.getLineNumber(((CompletionScanner)this.scanner).completedIdentifierStart, this.scanner.lineEnds, 0, this.scanner.linePtr)){
2089 return false;
2090 }
2091 RecoveredType recoveredType = (RecoveredType)this.currentElement;
2092 /* filter out cases where scanner is still inside type header */
2093 if (recoveredType.foundOpeningBrace) {
2094 // complete generics stack if necessary
2095 if((this.genericsIdentifiersLengthPtr < 0 && this.identifierPtr > -1)
2096 || (this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr] <= this.identifierPtr)) {
2097 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
2098 pushOnGenericsLengthStack(0); // handle type arguments
2099 }
2100 this.assistNode = this.getTypeReference(0);
2101 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
2102 this.isOrphanCompletionNode = true;
2103 return true;
2104 } else {
2105 if(recoveredType.typeDeclaration.superclass == null &&
2106 this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_EXTENDS_KEYWORD) {
2107 consumeClassOrInterfaceName();
2108 this.pushOnElementStack(K_NEXT_TYPEREF_IS_CLASS);
2109 this.assistNode = this.getTypeReference(0);
2110 popElement(K_NEXT_TYPEREF_IS_CLASS);
2111 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
2112 this.isOrphanCompletionNode = true;
2113 return true;
2114 }
2115 }
2116 }
2117 return false;
2118 }
classHeaderExtendsOrImplements(boolean isInterface, boolean isRecord)2119 private void classHeaderExtendsOrImplements(boolean isInterface, boolean isRecord) {
2120 if (this.currentElement != null
2121 && this.currentToken == TokenNameIdentifier
2122 && this.cursorLocation+1 >= this.scanner.startPosition
2123 && this.cursorLocation < this.scanner.currentPosition){
2124 this.pushIdentifier();
2125 int index = -1;
2126 /* check if current awaiting identifier is the completion identifier */
2127 if ((index = this.indexOfAssistIdentifier()) > -1) {
2128 int ptr = this.identifierPtr - this.identifierLengthStack[this.identifierLengthPtr] + index + 1;
2129 RecoveredType recoveredType = (RecoveredType)this.currentElement;
2130 /* filter out cases where scanner is still inside type header */
2131 if (!recoveredType.foundOpeningBrace) {
2132 TypeDeclaration type = recoveredType.typeDeclaration;
2133 if(!isInterface) {
2134 char[][] keywords = new char[Keywords.COUNT][];
2135 int count = 0;
2136
2137
2138 if(type.superInterfaces == null) {
2139 if(!isRecord) {
2140 if(type.superclass == null) {
2141 keywords[count++] = Keywords.EXTENDS;
2142 }
2143 }
2144 keywords[count++] = Keywords.IMPLEMENTS;
2145 }
2146
2147 System.arraycopy(keywords, 0, keywords = new char[count][], 0, count);
2148
2149 if(count > 0) {
2150 CompletionOnKeyword1 completionOnKeyword = new CompletionOnKeyword1(
2151 this.identifierStack[ptr],
2152 this.identifierPositionStack[ptr],
2153 keywords);
2154 type.superclass = completionOnKeyword;
2155 type.superclass.bits |= ASTNode.IsSuperType;
2156 this.assistNode = completionOnKeyword;
2157 this.lastCheckPoint = completionOnKeyword.sourceEnd + 1;
2158 }
2159 } else {
2160 if(type.superInterfaces == null) {
2161 CompletionOnKeyword1 completionOnKeyword = new CompletionOnKeyword1(
2162 this.identifierStack[ptr],
2163 this.identifierPositionStack[ptr],
2164 Keywords.EXTENDS);
2165 type.superInterfaces = new TypeReference[]{completionOnKeyword};
2166 type.superInterfaces[0].bits |= ASTNode.IsSuperType;
2167 this.assistNode = completionOnKeyword;
2168 this.lastCheckPoint = completionOnKeyword.sourceEnd + 1;
2169 }
2170 }
2171 }
2172 }
2173 }
2174 }
2175 /*
2176 * Check whether about to shift beyond the completion token.
2177 * If so, depending on the context, a special node might need to be created
2178 * and attached to the existing recovered structure so as to be remember in the
2179 * resulting parsed structure.
2180 */
completionIdentifierCheck()2181 public void completionIdentifierCheck(){
2182 //if (assistNode != null) return;
2183
2184 if (checkMemberValueName()) return;
2185 if (checkKeyword()) return;
2186 if (checkModuleInfoConstructs()) return;
2187 if (checkRecoveredType()) return;
2188 if (checkRecoveredMethod()) return;
2189
2190 // if not in a method in non diet mode and if not inside a field initializer, only record references attached to types
2191 if (!(isInsideMethod() && !this.diet)
2192 && !isIndirectlyInsideFieldInitialization()
2193 && !isIndirectlyInsideEnumConstantnitialization()
2194 && !isInsideAttributeValue()
2195 && !isInsideModuleInfo()) return;
2196
2197 /*
2198 In some cases, the completion identifier may not have yet been consumed,
2199 e.g. int.[cursor]
2200 This is because the grammar does not allow any (empty) identifier to follow
2201 a base type. We thus have to manually force the identifier to be consumed
2202 (that is, pushed).
2203 */
2204 if (assistIdentifier() == null && this.currentToken == TokenNameIdentifier) { // Test below copied from CompletionScanner.getCurrentIdentifierSource()
2205 if (this.cursorLocation < this.scanner.startPosition && this.scanner.currentPosition == this.scanner.startPosition){ // fake empty identifier got issued
2206 this.pushIdentifier();
2207 } else if (this.cursorLocation+1 >= this.scanner.startPosition && this.cursorLocation < this.scanner.currentPosition){
2208 this.pushIdentifier();
2209 }
2210 }
2211
2212 // check for different scenarii
2213 // no need to go further if we found a non empty completion node
2214 // (we still need to store labels though)
2215 if (this.assistNode != null) {
2216 // however inside an invocation, the completion identifier may already have been consumed into an empty name
2217 // completion, so this check should be before we check that we are at the cursor location
2218 if (!isEmptyNameCompletion() || checkInvocation()) return;
2219 }
2220
2221 // no need to check further if we are not at the cursor location
2222 if (this.indexOfAssistIdentifier() < 0) return;
2223
2224 if (checkModuleInfoConstructs()) return;
2225 if (checkClassInstanceCreation()) return;
2226 if (checkMemberAccess()) return;
2227 if (checkClassLiteralAccess()) return;
2228 if (checkInstanceofKeyword()) return;
2229
2230 // if the completion was not on an empty name, it can still be inside an invocation (e.g. this.fred("abc"[cursor])
2231 // (NB: Put this check before checkNameCompletion() because the selector of the invocation can be on the identifier stack)
2232 if (checkInvocation()) return;
2233
2234 if (checkParemeterizedType()) return;
2235 if (checkParemeterizedMethodName()) return;
2236 if (checkLabelStatement()) return;
2237 if (checkNameCompletion()) return;
2238 }
2239 @Override
consumeArrayCreationExpressionWithInitializer()2240 protected void consumeArrayCreationExpressionWithInitializer() {
2241 super.consumeArrayCreationExpressionWithInitializer();
2242 popElement(K_ARRAY_CREATION);
2243 }
2244 @Override
consumeArrayCreationExpressionWithoutInitializer()2245 protected void consumeArrayCreationExpressionWithoutInitializer() {
2246 super.consumeArrayCreationExpressionWithoutInitializer();
2247 popElement(K_ARRAY_CREATION);
2248 }
2249 @Override
consumeArrayCreationHeader()2250 protected void consumeArrayCreationHeader() {
2251 // nothing to do
2252 }
2253 @Override
consumeAssignment()2254 protected void consumeAssignment() {
2255 popElement(K_ASSISGNMENT_OPERATOR);
2256 super.consumeAssignment();
2257 }
2258 @Override
consumeAssignmentOperator(int pos)2259 protected void consumeAssignmentOperator(int pos) {
2260 super.consumeAssignmentOperator(pos);
2261 pushOnElementStack(K_ASSISGNMENT_OPERATOR, pos);
2262 }
2263 @Override
consumeBinaryExpression(int op)2264 protected void consumeBinaryExpression(int op) {
2265 super.consumeBinaryExpression(op);
2266 popElement(K_BINARY_OPERATOR);
2267
2268 if(this.expressionStack[this.expressionPtr] instanceof BinaryExpression) {
2269 BinaryExpression exp = (BinaryExpression) this.expressionStack[this.expressionPtr];
2270 if(this.assistNode != null && exp.right == this.assistNode) {
2271 this.assistNodeParent = exp;
2272 }
2273 }
2274 }
2275 @Override
consumeBinaryExpressionWithName(int op)2276 protected void consumeBinaryExpressionWithName(int op) {
2277 super.consumeBinaryExpressionWithName(op);
2278 popElement(K_BINARY_OPERATOR);
2279
2280 if(this.expressionStack[this.expressionPtr] instanceof BinaryExpression) {
2281 BinaryExpression exp = (BinaryExpression) this.expressionStack[this.expressionPtr];
2282 if(this.assistNode != null && exp.right == this.assistNode) {
2283 this.assistNodeParent = exp;
2284 }
2285 }
2286 }
2287 @Override
consumeCaseLabel()2288 protected void consumeCaseLabel() {
2289 super.consumeCaseLabel();
2290 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) != K_SWITCH_LABEL) {
2291 pushOnElementStack(K_SWITCH_LABEL);
2292 }
2293 }
2294 @Override
consumeCastExpressionWithPrimitiveType()2295 protected void consumeCastExpressionWithPrimitiveType() {
2296 popElement(K_CAST_STATEMENT);
2297
2298 Expression exp;
2299 Expression cast;
2300 TypeReference castType;
2301 this.expressionPtr--;
2302 this.expressionLengthPtr--;
2303 this.expressionStack[this.expressionPtr] = cast = new CastExpression(exp = this.expressionStack[this.expressionPtr+1], castType = (TypeReference) this.expressionStack[this.expressionPtr]);
2304 cast.sourceStart = castType.sourceStart - 1;
2305 cast.sourceEnd = exp.sourceEnd;
2306 }
2307 @Override
consumeCastExpressionWithGenericsArray()2308 protected void consumeCastExpressionWithGenericsArray() {
2309 popElement(K_CAST_STATEMENT);
2310
2311 Expression exp;
2312 Expression cast;
2313 TypeReference castType;
2314 this.expressionPtr--;
2315 this.expressionLengthPtr--;
2316 this.expressionStack[this.expressionPtr] = cast = new CastExpression(exp = this.expressionStack[this.expressionPtr + 1], castType = (TypeReference) this.expressionStack[this.expressionPtr]);
2317 cast.sourceStart = castType.sourceStart - 1;
2318 cast.sourceEnd = exp.sourceEnd;
2319 }
2320
2321 @Override
consumeCastExpressionWithQualifiedGenericsArray()2322 protected void consumeCastExpressionWithQualifiedGenericsArray() {
2323 popElement(K_CAST_STATEMENT);
2324
2325 Expression exp;
2326 Expression cast;
2327 TypeReference castType;
2328 this.expressionPtr--;
2329 this.expressionLengthPtr--;
2330 this.expressionStack[this.expressionPtr] = cast = new CastExpression(exp = this.expressionStack[this.expressionPtr + 1], castType = (TypeReference) this.expressionStack[this.expressionPtr]);
2331 cast.sourceStart = castType.sourceStart - 1;
2332 cast.sourceEnd = exp.sourceEnd;
2333 }
2334 @Override
consumeCastExpressionWithNameArray()2335 protected void consumeCastExpressionWithNameArray() {
2336 // CastExpression ::= PushLPAREN Name Dims PushRPAREN InsideCastExpression UnaryExpressionNotPlusMinus
2337 popElement(K_CAST_STATEMENT);
2338
2339 Expression exp;
2340 Expression cast;
2341 TypeReference castType;
2342 this.expressionPtr--;
2343 this.expressionLengthPtr--;
2344 this.expressionStack[this.expressionPtr] = cast = new CastExpression(exp = this.expressionStack[this.expressionPtr+1], castType = (TypeReference) this.expressionStack[this.expressionPtr]);
2345 cast.sourceStart = castType.sourceStart - 1;
2346 cast.sourceEnd = exp.sourceEnd;
2347 }
2348 @Override
consumeCastExpressionLL1()2349 protected void consumeCastExpressionLL1() {
2350 popElement(K_CAST_STATEMENT);
2351 super.consumeCastExpressionLL1();
2352 }
2353 @Override
consumeCatchFormalParameter()2354 protected void consumeCatchFormalParameter() {
2355 if (this.indexOfAssistIdentifier() < 0) {
2356 super.consumeCatchFormalParameter();
2357 if (this.pendingAnnotation != null) {
2358 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2359 this.pendingAnnotation = null;
2360 }
2361 } else {
2362 this.identifierLengthPtr--;
2363 char[] identifierName = this.identifierStack[this.identifierPtr];
2364 long namePositions = this.identifierPositionStack[this.identifierPtr--];
2365 this.intPtr--; // dimension from the variabledeclaratorid
2366 TypeReference type = (TypeReference) this.astStack[this.astPtr--];
2367 this.intPtr -= 2;
2368 CompletionOnArgumentName arg =
2369 new CompletionOnArgumentName(
2370 identifierName,
2371 namePositions,
2372 type,
2373 this.intStack[this.intPtr + 1] & ~ClassFileConstants.AccDeprecated); // modifiers
2374 arg.bits &= ~ASTNode.IsArgument;
2375 // consume annotations
2376 int length;
2377 if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
2378 System.arraycopy(
2379 this.expressionStack,
2380 (this.expressionPtr -= length) + 1,
2381 arg.annotations = new Annotation[length],
2382 0,
2383 length);
2384 }
2385
2386 arg.isCatchArgument = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_CATCH_AND_RIGHT_PAREN;
2387 pushOnAstStack(arg);
2388
2389 this.assistNode = arg;
2390 this.lastCheckPoint = (int) namePositions;
2391 this.isOrphanCompletionNode = true;
2392
2393 /* if incomplete method header, listLength counter will not have been reset,
2394 indicating that some arguments are available on the stack */
2395 this.listLength++;
2396 }
2397 }
2398 @Override
consumeClassBodyDeclaration()2399 protected void consumeClassBodyDeclaration() {
2400 popElement(K_BLOCK_DELIMITER);
2401 super.consumeClassBodyDeclaration();
2402 this.pendingAnnotation = null; // the pending annotation cannot be attached to next nodes
2403 }
2404 @Override
consumeClassBodyopt()2405 protected void consumeClassBodyopt() {
2406 popElement(K_SELECTOR_QUALIFIER);
2407 popElement(K_SELECTOR_INVOCATION_TYPE);
2408 super.consumeClassBodyopt();
2409 }
2410
2411 @Override
consumeClassDeclaration()2412 protected void consumeClassDeclaration() {
2413 if (this.astPtr >= 0) {
2414 int length = this.astLengthStack[this.astLengthPtr];
2415 TypeDeclaration typeDeclaration = (TypeDeclaration) this.astStack[this.astPtr-length];
2416 this.javadoc = null;
2417 CompletionJavadocParser completionJavadocParser = (CompletionJavadocParser)this.javadocParser;
2418 completionJavadocParser.allPossibleTags = true;
2419 checkComment();
2420 if (this.javadoc != null && this.cursorLocation > this.javadoc.sourceStart && this.cursorLocation < this.javadoc.sourceEnd) {
2421 // completion is in an orphan javadoc comment => replace in last read declaration to allow completion resolution
2422 typeDeclaration.javadoc = this.javadoc;
2423 }
2424 completionJavadocParser.allPossibleTags = false;
2425 }
2426 super.consumeClassDeclaration();
2427 }
2428 @Override
consumeClassHeaderName1()2429 protected void consumeClassHeaderName1() {
2430 super.consumeClassHeaderName1();
2431 this.hasUnusedModifiers = false;
2432 if (this.pendingAnnotation != null) {
2433 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2434 this.pendingAnnotation = null;
2435 }
2436 classHeaderExtendsOrImplements(false,false);
2437 }
2438
2439 @Override
consumeRecordHeaderPart()2440 protected void consumeRecordHeaderPart() {
2441 super.consumeRecordHeaderPart();
2442 this.hasUnusedModifiers = false;
2443 if (this.pendingAnnotation != null) {
2444 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2445 this.pendingAnnotation = null;
2446 }
2447 classHeaderExtendsOrImplements(false,true);
2448 }
2449
2450 @Override
consumeClassHeaderExtends()2451 protected void consumeClassHeaderExtends() {
2452 pushOnElementStack(K_NEXT_TYPEREF_IS_CLASS);
2453 super.consumeClassHeaderExtends();
2454 if (this.assistNode != null && this.assistNodeParent == null) {
2455 TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr];
2456 if (typeDecl != null && typeDecl.superclass == this.assistNode)
2457 this.assistNodeParent = typeDecl;
2458 }
2459 popElement(K_NEXT_TYPEREF_IS_CLASS);
2460 popElement(K_EXTENDS_KEYWORD);
2461
2462 if (this.currentElement != null
2463 && this.currentToken == TokenNameIdentifier
2464 && this.cursorLocation+1 >= this.scanner.startPosition
2465 && this.cursorLocation < this.scanner.currentPosition){
2466 this.pushIdentifier();
2467
2468 int index = -1;
2469 /* check if current awaiting identifier is the completion identifier */
2470 if ((index = this.indexOfAssistIdentifier()) > -1) {
2471 int ptr = this.identifierPtr - this.identifierLengthStack[this.identifierLengthPtr] + index + 1;
2472 RecoveredType recoveredType = (RecoveredType)this.currentElement;
2473 /* filter out cases where scanner is still inside type header */
2474 if (!recoveredType.foundOpeningBrace) {
2475 TypeDeclaration type = recoveredType.typeDeclaration;
2476 if(type.superInterfaces == null) {
2477 type.superclass = new CompletionOnKeyword1(
2478 this.identifierStack[ptr],
2479 this.identifierPositionStack[ptr],
2480 Keywords.IMPLEMENTS);
2481 type.superclass.bits |= ASTNode.IsSuperType;
2482 this.assistNode = type.superclass;
2483 this.lastCheckPoint = type.superclass.sourceEnd + 1;
2484 }
2485 }
2486 }
2487 }
2488 }
2489 @Override
consumeClassHeaderImplements()2490 protected void consumeClassHeaderImplements() {
2491 super.consumeClassHeaderImplements();
2492 if (this.assistNode != null && this.assistNodeParent == null) {
2493 TypeDeclaration typeDecl = (TypeDeclaration) this.astStack[this.astPtr];
2494 if (typeDecl != null) {
2495 TypeReference[] superInterfaces = typeDecl.superInterfaces;
2496 int length = superInterfaces == null ? 0 : superInterfaces.length;
2497 for (int i = 0; i < length; i++) {
2498 if (superInterfaces[i] == this.assistNode) {
2499 this.assistNodeParent = typeDecl;
2500 }
2501 }
2502 }
2503 }
2504 }
2505 @Override
consumeClassInstanceCreationExpressionName()2506 protected void consumeClassInstanceCreationExpressionName() {
2507 super.consumeClassInstanceCreationExpressionName();
2508 this.invocationType = QUALIFIED_ALLOCATION;
2509 this.qualifier = this.expressionPtr;
2510 }
2511 @Override
consumeClassTypeElt()2512 protected void consumeClassTypeElt() {
2513 pushOnElementStack(K_NEXT_TYPEREF_IS_EXCEPTION);
2514 super.consumeClassTypeElt();
2515 popElement(K_NEXT_TYPEREF_IS_EXCEPTION);
2516 }
2517
2518 @Override
consumeCompilationUnit()2519 protected void consumeCompilationUnit() {
2520 this.javadoc = null;
2521 checkComment();
2522 if (this.javadoc != null && this.cursorLocation > this.javadoc.sourceStart && this.cursorLocation < this.javadoc.sourceEnd) {
2523 // completion is in an orphan javadoc comment => replace compilation unit one to allow completion resolution
2524 this.compilationUnit.javadoc = this.javadoc;
2525 // create a fake interface declaration to allow resolution
2526 if (this.compilationUnit.types == null) {
2527 this.compilationUnit.types = new TypeDeclaration[1];
2528 TypeDeclaration declaration = new TypeDeclaration(this.compilationUnit.compilationResult);
2529 declaration.name = FAKE_TYPE_NAME;
2530 declaration.modifiers = ClassFileConstants.AccDefault | ClassFileConstants.AccInterface;
2531 this.compilationUnit.types[0] = declaration;
2532 }
2533 }
2534 super.consumeCompilationUnit();
2535 }
2536 @Override
consumeSwitchExpression()2537 protected void consumeSwitchExpression() {
2538 super.consumeSwitchExpression();
2539 if (this.assistNode != null) {
2540 SwitchExpression expr = (SwitchExpression) this.expressionStack[this.expressionPtr];
2541 expr.resolveAll = true;
2542 }
2543 }
2544 @Override
consumeConditionalExpression(int op)2545 protected void consumeConditionalExpression(int op) {
2546 popElement(K_CONDITIONAL_OPERATOR);
2547 super.consumeConditionalExpression(op);
2548 }
2549 @Override
consumeConditionalExpressionWithName(int op)2550 protected void consumeConditionalExpressionWithName(int op) {
2551 popElement(K_CONDITIONAL_OPERATOR);
2552 super.consumeConditionalExpressionWithName(op);
2553 }
2554 @Override
consumeConstructorBody()2555 protected void consumeConstructorBody() {
2556 popElement(K_BLOCK_DELIMITER);
2557 super.consumeConstructorBody();
2558 }
2559 @Override
consumeConstructorHeader()2560 protected void consumeConstructorHeader() {
2561 super.consumeConstructorHeader();
2562 pushOnElementStack(K_BLOCK_DELIMITER);
2563 }
2564 @Override
consumeConstructorHeaderName()2565 protected void consumeConstructorHeaderName() {
2566
2567 /* no need to take action if not inside assist identifiers */
2568 if (indexOfAssistIdentifier() < 0) {
2569 long selectorSourcePositions = this.identifierPositionStack[this.identifierPtr];
2570 int selectorSourceEnd = (int) selectorSourcePositions;
2571 int currentAstPtr = this.astPtr;
2572 /* recovering - might be an empty message send */
2573 if (this.currentElement != null && this.lastIgnoredToken == TokenNamenew){ // was an allocation expression
2574 super.consumeConstructorHeaderName();
2575 } else {
2576 super.consumeConstructorHeaderName();
2577 if (this.pendingAnnotation != null) {
2578 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2579 this.pendingAnnotation = null;
2580 }
2581 }
2582 if (this.sourceEnds != null && this.astPtr > currentAstPtr) { // if ast node was pushed on the ast stack
2583 this.sourceEnds.put(this.astStack[this.astPtr], selectorSourceEnd);
2584 }
2585 return;
2586 }
2587
2588 /* force to start recovering in order to get fake field behavior */
2589 if (this.currentElement == null){
2590 this.hasReportedError = true; // do not report any error
2591 }
2592 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
2593 pushOnGenericsLengthStack(0); // handle type arguments
2594 this.restartRecovery = true;
2595 }
2596 @Override
consumeConstructorHeaderNameWithTypeParameters()2597 protected void consumeConstructorHeaderNameWithTypeParameters() {
2598 long selectorSourcePositions = this.identifierPositionStack[this.identifierPtr];
2599 int selectorSourceEnd = (int) selectorSourcePositions;
2600 int currentAstPtr = this.astPtr;
2601 if (this.currentElement != null && this.lastIgnoredToken == TokenNamenew){ // was an allocation expression
2602 super.consumeConstructorHeaderNameWithTypeParameters();
2603 } else {
2604 super.consumeConstructorHeaderNameWithTypeParameters();
2605 if (this.pendingAnnotation != null) {
2606 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2607 this.pendingAnnotation = null;
2608 }
2609 }
2610 if (this.sourceEnds != null && this.astPtr > currentAstPtr) { // if ast node was pushed on the ast stack
2611 this.sourceEnds.put(this.astStack[this.astPtr], selectorSourceEnd);
2612 }
2613 }
2614 @Override
consumeDefaultLabel()2615 protected void consumeDefaultLabel() {
2616 super.consumeDefaultLabel();
2617 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SWITCH_LABEL) {
2618 popElement(K_SWITCH_LABEL);
2619 }
2620 pushOnElementStack(K_SWITCH_LABEL, DEFAULT);
2621 }
2622 @Override
consumeDimWithOrWithOutExpr()2623 protected void consumeDimWithOrWithOutExpr() {
2624 // DimWithOrWithOutExpr ::= '[' ']'
2625 pushOnExpressionStack(null);
2626 }
2627 @Override
consumeEmptyStatement()2628 protected void consumeEmptyStatement() {
2629 super.consumeEmptyStatement();
2630 /* Sneak in the assist node. The reason we can't do that when we see the assist node is that
2631 we don't know whether it is the first or subsequent statement in a block to be able to
2632 decide whether to call contactNodeLists. See Parser.consumeBlockStatement(s)
2633 */
2634 if (this.shouldStackAssistNode && this.assistNode != null)
2635 this.astStack[this.astPtr] = this.assistNodeParent instanceof MessageSend ? this.assistNodeParent : this.assistNode;
2636 this.shouldStackAssistNode = false;
2637 }
2638 @Override
consumeBlockStatement()2639 protected void consumeBlockStatement() {
2640 super.consumeBlockStatement();
2641 if (this.shouldStackAssistNode && this.assistNode != null) {
2642 Statement stmt = (Statement) this.astStack[this.astPtr];
2643 if (stmt.sourceStart <= this.assistNode.sourceStart && stmt.sourceEnd >= this.assistNode.sourceEnd)
2644 this.shouldStackAssistNode = false;
2645 }
2646 }
2647 @Override
consumeEnhancedForStatement()2648 protected void consumeEnhancedForStatement() {
2649 super.consumeEnhancedForStatement();
2650
2651 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_CONTROL_STATEMENT_DELIMITER) {
2652 popElement(K_CONTROL_STATEMENT_DELIMITER);
2653 }
2654 }
2655 @Override
consumeEnhancedForStatementHeader()2656 protected void consumeEnhancedForStatementHeader(){
2657 this.consumedEnhancedFor = true;
2658 super.consumeEnhancedForStatementHeader();
2659
2660 }
2661
2662 @Override
consumeEnhancedForStatementHeaderInit(boolean hasModifiers)2663 protected void consumeEnhancedForStatementHeaderInit(boolean hasModifiers) {
2664 super.consumeEnhancedForStatementHeaderInit(hasModifiers);
2665 this.hasUnusedModifiers = false;
2666 if (this.pendingAnnotation != null) {
2667 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2668 this.pendingAnnotation = null;
2669 }
2670 }
2671 @Override
consumeEnterAnonymousClassBody(boolean qualified)2672 protected void consumeEnterAnonymousClassBody(boolean qualified) {
2673 popElement(K_SELECTOR_QUALIFIER);
2674 popElement(K_SELECTOR_INVOCATION_TYPE);
2675 super.consumeEnterAnonymousClassBody(qualified);
2676 }
2677 @Override
consumeEnterVariable()2678 protected void consumeEnterVariable() {
2679 this.identifierPtr--;
2680 this.identifierLengthPtr--;
2681
2682 boolean isLocalDeclaration = this.nestedMethod[this.nestedType] != 0;
2683 int variableIndex = this.variablesCounter[this.nestedType];
2684
2685 this.hasUnusedModifiers = false;
2686
2687 if(isLocalDeclaration || indexOfAssistIdentifier() < 0 || variableIndex != 0) {
2688 this.identifierPtr++;
2689 this.identifierLengthPtr++;
2690
2691 if (this.pendingAnnotation != null &&
2692 this.assistNode != null &&
2693 this.currentElement != null &&
2694 this.currentElement instanceof RecoveredMethod &&
2695 !this.currentElement.foundOpeningBrace &&
2696 ((RecoveredMethod)this.currentElement).methodDeclaration.declarationSourceEnd == 0) {
2697 // this is a method parameter
2698 super.consumeEnterVariable();
2699 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2700 this.pendingAnnotation.isParameter = true;
2701 this.pendingAnnotation = null;
2702
2703 } else {
2704 super.consumeEnterVariable();
2705 if (this.pendingAnnotation != null) {
2706 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2707 this.pendingAnnotation = null;
2708 }
2709 }
2710 } else {
2711 this.restartRecovery = true;
2712
2713 // recovery
2714 if (this.currentElement != null) {
2715 if(!checkKeyword() && !(this.currentElement instanceof RecoveredUnit && ((RecoveredUnit)this.currentElement).typeCount == 0)) {
2716 int nameSourceStart = (int)(this.identifierPositionStack[this.identifierPtr] >>> 32);
2717 this.intPtr--;
2718 TypeReference type = getTypeReference(this.intStack[this.intPtr--]);
2719 this.intPtr--;
2720
2721 if (!(this.currentElement instanceof RecoveredType)
2722 && (this.currentToken == TokenNameDOT
2723 || (Util.getLineNumber(type.sourceStart, this.scanner.lineEnds, 0, this.scanner.linePtr)
2724 != Util.getLineNumber(nameSourceStart, this.scanner.lineEnds, 0, this.scanner.linePtr)))){
2725 this.lastCheckPoint = nameSourceStart;
2726 this.restartRecovery = true;
2727 return;
2728 }
2729
2730 FieldDeclaration completionFieldDecl = new CompletionOnFieldType(type, false);
2731 // consume annotations
2732 int length;
2733 if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
2734 System.arraycopy(
2735 this.expressionStack,
2736 (this.expressionPtr -= length) + 1,
2737 completionFieldDecl.annotations = new Annotation[length],
2738 0,
2739 length);
2740 }
2741 completionFieldDecl.modifiers = this.intStack[this.intPtr--];
2742 this.assistNode = completionFieldDecl;
2743 this.lastCheckPoint = type.sourceEnd + 1;
2744 this.currentElement = this.currentElement.add(completionFieldDecl, 0);
2745 this.lastIgnoredToken = -1;
2746 }
2747 }
2748 }
2749 }
2750 @Override
consumeEnumConstantHeaderName()2751 protected void consumeEnumConstantHeaderName() {
2752 if (this.currentElement != null) {
2753 if (!(this.currentElement instanceof RecoveredType
2754 || (this.currentElement instanceof RecoveredField && ((RecoveredField)this.currentElement).fieldDeclaration.type == null))
2755 || (this.lastIgnoredToken == TokenNameDOT)) {
2756 super.consumeEnumConstantHeaderName();
2757 return;
2758 }
2759 }
2760 super.consumeEnumConstantHeaderName();
2761 if (this.pendingAnnotation != null) {
2762 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2763 this.pendingAnnotation = null;
2764 }
2765 }
2766 @Override
consumeEnumConstantNoClassBody()2767 protected void consumeEnumConstantNoClassBody() {
2768 super.consumeEnumConstantNoClassBody();
2769 if ((this.currentToken == TokenNameCOMMA || this.currentToken == TokenNameSEMICOLON)
2770 && this.astStack[this.astPtr] instanceof FieldDeclaration) {
2771 if (this.sourceEnds != null) {
2772 this.sourceEnds.put(this.astStack[this.astPtr], this.scanner.currentPosition - 1);
2773 }
2774 }
2775 }
2776 @Override
consumeEnumConstantWithClassBody()2777 protected void consumeEnumConstantWithClassBody() {
2778 super.consumeEnumConstantWithClassBody();
2779 if ((this.currentToken == TokenNameCOMMA || this.currentToken == TokenNameSEMICOLON)
2780 && this.astStack[this.astPtr] instanceof FieldDeclaration) {
2781 if (this.sourceEnds != null) {
2782 this.sourceEnds.put(this.astStack[this.astPtr], this.scanner.currentPosition - 1);
2783 }
2784 }
2785 }
2786 @Override
consumeEnumHeaderName()2787 protected void consumeEnumHeaderName() {
2788 super.consumeEnumHeaderName();
2789 this.hasUnusedModifiers = false;
2790 if (this.pendingAnnotation != null) {
2791 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2792 this.pendingAnnotation = null;
2793 }
2794 }
2795 @Override
consumeEnumHeaderNameWithTypeParameters()2796 protected void consumeEnumHeaderNameWithTypeParameters() {
2797 super.consumeEnumHeaderNameWithTypeParameters();
2798 if (this.pendingAnnotation != null) {
2799 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2800 this.pendingAnnotation = null;
2801 }
2802 }
2803 @Override
consumeEqualityExpression(int op)2804 protected void consumeEqualityExpression(int op) {
2805 super.consumeEqualityExpression(op);
2806 popElement(K_BINARY_OPERATOR);
2807
2808 BinaryExpression exp = (BinaryExpression) this.expressionStack[this.expressionPtr];
2809 if(this.assistNode != null && exp.right == this.assistNode) {
2810 this.assistNodeParent = exp;
2811 }
2812 }
2813 @Override
consumeEqualityExpressionWithName(int op)2814 protected void consumeEqualityExpressionWithName(int op) {
2815 super.consumeEqualityExpressionWithName(op);
2816 popElement(K_BINARY_OPERATOR);
2817
2818 BinaryExpression exp = (BinaryExpression) this.expressionStack[this.expressionPtr];
2819 if(this.assistNode != null && exp.right == this.assistNode) {
2820 this.assistNodeParent = exp;
2821 }
2822 }
2823 @Override
consumeExitVariableWithInitialization()2824 protected void consumeExitVariableWithInitialization() {
2825 super.consumeExitVariableWithInitialization();
2826 if ((this.currentToken == TokenNameCOMMA || this.currentToken == TokenNameSEMICOLON)
2827 && this.astStack[this.astPtr] instanceof FieldDeclaration) {
2828 if (this.sourceEnds != null) {
2829 this.sourceEnds.put(this.astStack[this.astPtr], this.scanner.currentPosition - 1);
2830 }
2831 }
2832
2833 // does not keep the initialization if completion is not inside
2834 AbstractVariableDeclaration variable = (AbstractVariableDeclaration) this.astStack[this.astPtr];
2835 if (this.cursorLocation + 1 < variable.initialization.sourceStart ||
2836 this.cursorLocation > variable.initialization.sourceEnd) {
2837 if (!variable.type.isTypeNameVar(null)) {
2838 if (! (variable instanceof LocalDeclaration && ((LocalDeclaration)variable).isTypeNameVar(this.compilationUnit.scope))) {
2839 variable.initialization = null;
2840 }
2841 }
2842 } else if (this.assistNode != null && this.assistNode == variable.initialization) {
2843 this.assistNodeParent = variable;
2844 }
2845 if (triggerRecoveryUponLambdaClosure(variable, false)) {
2846 if (this.currentElement != null) {
2847 this.restartRecovery = true;
2848 }
2849 }
2850 }
2851 @Override
consumeExitVariableWithoutInitialization()2852 protected void consumeExitVariableWithoutInitialization() {
2853 // ExitVariableWithoutInitialization ::= $empty
2854 // do nothing by default
2855 super.consumeExitVariableWithoutInitialization();
2856 if ((this.currentToken == TokenNameCOMMA || this.currentToken == TokenNameSEMICOLON)
2857 && this.astStack[this.astPtr] instanceof FieldDeclaration) {
2858 if (this.sourceEnds != null) {
2859 this.sourceEnds.put(this.astStack[this.astPtr], this.scanner.currentPosition - 1);
2860 }
2861 }
2862 }
2863 @Override
consumeExplicitConstructorInvocation(int flag, int recFlag)2864 protected void consumeExplicitConstructorInvocation(int flag, int recFlag) {
2865 popElement(K_SELECTOR_QUALIFIER);
2866 popElement(K_SELECTOR_INVOCATION_TYPE);
2867 super.consumeExplicitConstructorInvocation(flag, recFlag);
2868 }
2869 /*
2870 * Copy of code from superclass with the following change:
2871 * If the cursor location is on the field access, then create a
2872 * CompletionOnMemberAccess instead.
2873 */
2874 @Override
consumeFieldAccess(boolean isSuperAccess)2875 protected void consumeFieldAccess(boolean isSuperAccess) {
2876 // FieldAccess ::= Primary '.' 'Identifier'
2877 // FieldAccess ::= 'super' '.' 'Identifier'
2878
2879 // potential receiver is being poped, so reset potential receiver
2880 this.invocationType = NO_RECEIVER;
2881 this.qualifier = -1;
2882
2883 if (this.indexOfAssistIdentifier() < 0) {
2884 super.consumeFieldAccess(isSuperAccess);
2885 } else {
2886 pushCompletionOnMemberAccessOnExpressionStack(isSuperAccess);
2887 }
2888 }
2889 @Override
consumeForceNoDiet()2890 protected void consumeForceNoDiet() {
2891 super.consumeForceNoDiet();
2892 if (isInsideMethod()) {
2893 pushOnElementStack(K_LOCAL_INITIALIZER_DELIMITER);
2894 }
2895 }
2896 @Override
consumeFormalParameter(boolean isVarArgs)2897 protected void consumeFormalParameter(boolean isVarArgs) {
2898
2899 this.invocationType = NO_RECEIVER;
2900 this.qualifier = -1;
2901
2902 if (this.indexOfAssistIdentifier() < 0) {
2903 super.consumeFormalParameter(isVarArgs);
2904 if (this.pendingAnnotation != null) {
2905 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
2906 this.pendingAnnotation = null;
2907 }
2908 } else {
2909 boolean isReceiver = this.intStack[this.intPtr--] == 0;
2910 if (isReceiver) {
2911 this.expressionPtr--;
2912 this.expressionLengthPtr --;
2913 }
2914 this.identifierLengthPtr--;
2915 char[] identifierName = this.identifierStack[this.identifierPtr];
2916 long namePositions = this.identifierPositionStack[this.identifierPtr--];
2917 int extendedDimensions = this.intStack[this.intPtr--];
2918 Annotation [][] annotationsOnExtendedDimensions = extendedDimensions == 0 ? null : getAnnotationsOnDimensions(extendedDimensions);
2919 Annotation [] varArgsAnnotations = null;
2920 int length;
2921 int endOfEllipsis = 0;
2922 if (isVarArgs) {
2923 endOfEllipsis = this.intStack[this.intPtr--];
2924 if ((length = this.typeAnnotationLengthStack[this.typeAnnotationLengthPtr--]) != 0) {
2925 System.arraycopy(
2926 this.typeAnnotationStack,
2927 (this.typeAnnotationPtr -= length) + 1,
2928 varArgsAnnotations = new Annotation[length],
2929 0,
2930 length);
2931 }
2932 }
2933 int firstDimensions = this.intStack[this.intPtr--];
2934 TypeReference type = getTypeReference(firstDimensions);
2935
2936 if (isVarArgs || extendedDimensions != 0) {
2937 if (isVarArgs) {
2938 type = augmentTypeWithAdditionalDimensions(type, 1, varArgsAnnotations != null ? new Annotation[][] { varArgsAnnotations } : null, true);
2939 }
2940 if (extendedDimensions != 0) { // combination illegal.
2941 type = augmentTypeWithAdditionalDimensions(type, extendedDimensions, annotationsOnExtendedDimensions, false);
2942 }
2943 type.sourceEnd = type.isParameterizedTypeReference() ? this.endStatementPosition : this.endPosition;
2944 }
2945 if (isVarArgs) {
2946 if (extendedDimensions == 0) {
2947 type.sourceEnd = endOfEllipsis;
2948 }
2949 type.bits |= ASTNode.IsVarArgs; // set isVarArgs
2950 }
2951 this.intPtr -= 2;
2952 CompletionOnArgumentName arg =
2953 new CompletionOnArgumentName(
2954 identifierName,
2955 namePositions,
2956 type,
2957 this.intStack[this.intPtr + 1] & ~ClassFileConstants.AccDeprecated); // modifiers
2958 // consume annotations
2959 if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
2960 System.arraycopy(
2961 this.expressionStack,
2962 (this.expressionPtr -= length) + 1,
2963 arg.annotations = new Annotation[length],
2964 0,
2965 length);
2966 RecoveredType currentRecoveryType = this.currentRecoveryType();
2967 if (currentRecoveryType != null)
2968 currentRecoveryType.annotationsConsumed(arg.annotations);
2969 }
2970
2971 arg.isCatchArgument = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_CATCH_AND_RIGHT_PAREN;
2972 pushOnAstStack(arg);
2973
2974 this.assistNode = arg;
2975 this.lastCheckPoint = (int) namePositions;
2976 this.isOrphanCompletionNode = true;
2977
2978 /* if incomplete method header, listLength counter will not have been reset,
2979 indicating that some arguments are available on the stack */
2980 this.listLength++;
2981 }
2982 }
2983 @Override
consumeGenericTypeWithDiamond()2984 protected void consumeGenericTypeWithDiamond() {
2985 super.consumeGenericTypeWithDiamond();
2986 // we need to pop the <> of the diamond from the stack.
2987 // This is not required in usual case when the type argument isn't elided
2988 // since the < and > get popped while parsing the type argument.
2989 popElement(K_BINARY_OPERATOR); // pop >
2990 popElement(K_BINARY_OPERATOR); // pop <
2991 }
2992 @Override
consumeStatementFor()2993 protected void consumeStatementFor() {
2994 super.consumeStatementFor();
2995
2996 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_CONTROL_STATEMENT_DELIMITER) {
2997 popElement(K_CONTROL_STATEMENT_DELIMITER);
2998 }
2999 }
3000 @Override
consumeStatementIfNoElse()3001 protected void consumeStatementIfNoElse() {
3002 super.consumeStatementIfNoElse();
3003
3004 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_CONTROL_STATEMENT_DELIMITER) {
3005 popElement(K_CONTROL_STATEMENT_DELIMITER);
3006 }
3007 }
3008 @Override
consumeStatementIfWithElse()3009 protected void consumeStatementIfWithElse() {
3010 super.consumeStatementIfWithElse();
3011
3012 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_CONTROL_STATEMENT_DELIMITER) {
3013 popElement(K_CONTROL_STATEMENT_DELIMITER);
3014 }
3015 }
3016 @Override
consumeInsideCastExpression()3017 protected void consumeInsideCastExpression() {
3018 TypeReference[] bounds = null;
3019 int additionalBoundsLength = this.genericsLengthStack[this.genericsLengthPtr--];
3020 if (additionalBoundsLength > 0) {
3021 bounds = new TypeReference[additionalBoundsLength + 1];
3022 this.genericsPtr -= additionalBoundsLength;
3023 System.arraycopy(this.genericsStack, this.genericsPtr + 1, bounds, 1, additionalBoundsLength);
3024 }
3025
3026 int end = this.intStack[this.intPtr--];
3027 boolean isParameterized =(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_CAST);
3028 if(isParameterized) {
3029 popElement(K_PARAMETERIZED_CAST);
3030
3031 if(this.identifierLengthStack[this.identifierLengthPtr] > 0) {
3032 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
3033 }
3034 } else {
3035 if(this.identifierLengthStack[this.identifierLengthPtr] > 0) {
3036 pushOnGenericsIdentifiersLengthStack(this.identifierLengthStack[this.identifierLengthPtr]);
3037 pushOnGenericsLengthStack(0);
3038 }
3039 }
3040 Expression castType = getTypeReference(this.intStack[this.intPtr--]);
3041 if (additionalBoundsLength > 0) {
3042 bounds[0] = (TypeReference) castType;
3043 castType = createIntersectionCastTypeReference(bounds);
3044 }
3045 if(isParameterized) {
3046 this.intPtr--;
3047 }
3048 castType.sourceEnd = end - 1;
3049 castType.sourceStart = this.intStack[this.intPtr--] + 1;
3050 pushOnExpressionStack(castType);
3051
3052 pushOnElementStack(K_CAST_STATEMENT);
3053 }
3054 @Override
consumeInsideCastExpressionLL1()3055 protected void consumeInsideCastExpressionLL1() {
3056 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_CAST) {
3057 popElement(K_PARAMETERIZED_CAST);
3058 }
3059 if (!this.record) {
3060 super.consumeInsideCastExpressionLL1();
3061 } else {
3062 boolean temp = this.skipRecord;
3063 try {
3064 this.skipRecord = true;
3065 super.consumeInsideCastExpressionLL1();
3066 if (this.record) {
3067 Expression typeReference = this.expressionStack[this.expressionPtr];
3068 if (!isAlreadyPotentialName(typeReference.sourceStart)) {
3069 addPotentialName(null, typeReference.sourceStart, typeReference.sourceEnd);
3070 }
3071 }
3072 } finally {
3073 this.skipRecord = temp;
3074 }
3075 }
3076 pushOnElementStack(K_CAST_STATEMENT);
3077 }
3078 @Override
consumeInsideCastExpressionLL1WithBounds()3079 protected void consumeInsideCastExpressionLL1WithBounds() {
3080 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_CAST) {
3081 popElement(K_PARAMETERIZED_CAST);
3082 }
3083 if (!this.record) {
3084 super.consumeInsideCastExpressionLL1WithBounds();
3085 } else {
3086 boolean temp = this.skipRecord;
3087 try {
3088 this.skipRecord = true;
3089 super.consumeInsideCastExpressionLL1WithBounds();
3090 if (this.record) {
3091 int length = this.expressionLengthStack[this.expressionLengthPtr];
3092 for (int i = 0; i < length; i++) {
3093 Expression typeReference = this.expressionStack[this.expressionPtr - length + i + 1];
3094 if (!isAlreadyPotentialName(typeReference.sourceStart)) {
3095 addPotentialName(null, typeReference.sourceStart, typeReference.sourceEnd);
3096 }
3097 }
3098 }
3099 } finally {
3100 this.skipRecord = temp;
3101 }
3102 }
3103 pushOnElementStack(K_CAST_STATEMENT);
3104 }
3105 @Override
consumeInsideCastExpressionWithQualifiedGenerics()3106 protected void consumeInsideCastExpressionWithQualifiedGenerics() {
3107 popElement(K_PARAMETERIZED_CAST);
3108
3109 Expression castType;
3110 int end = this.intStack[this.intPtr--];
3111
3112 int dim = this.intStack[this.intPtr--];
3113 Annotation[][] annotationsOnDimensions = dim == 0 ? null : getAnnotationsOnDimensions(dim);
3114
3115 TypeReference[] bounds = null;
3116 int additionalBoundsLength = this.genericsLengthStack[this.genericsLengthPtr--];
3117 if (additionalBoundsLength > 0) {
3118 bounds = new TypeReference[additionalBoundsLength + 1];
3119 this.genericsPtr -= additionalBoundsLength;
3120 System.arraycopy(this.genericsStack, this.genericsPtr + 1, bounds, 1, additionalBoundsLength);
3121 }
3122
3123 TypeReference rightSide = getTypeReference(0);
3124
3125 castType = computeQualifiedGenericsFromRightSide(rightSide, dim, annotationsOnDimensions);
3126 if (additionalBoundsLength > 0) {
3127 bounds[0] = (TypeReference) castType;
3128 castType = createIntersectionCastTypeReference(bounds);
3129 }
3130 this.intPtr--;
3131 castType.sourceEnd = end - 1;
3132 castType.sourceStart = this.intStack[this.intPtr--] + 1;
3133 pushOnExpressionStack(castType);
3134
3135 pushOnElementStack(K_CAST_STATEMENT);
3136 }
3137 @Override
consumeInstanceOfExpression()3138 protected void consumeInstanceOfExpression() {
3139 super.consumeInstanceOfExpression();
3140 popElement(K_BINARY_OPERATOR);
3141 // to handle https://bugs.eclipse.org/bugs/show_bug.cgi?id=261534
3142 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_IF_AND_RIGHT_PAREN) {
3143 pushOnElementStack(K_BETWEEN_INSTANCEOF_AND_RPAREN, IF, this.expressionStack[this.expressionPtr]);
3144 }
3145
3146 InstanceOfExpression exp = (InstanceOfExpression) this.expressionStack[this.expressionPtr];
3147 if(this.assistNode != null && exp.type == this.assistNode) {
3148 this.assistNodeParent = exp;
3149 }
3150 }
3151 @Override
consumeInstanceOfExpressionWithName()3152 protected void consumeInstanceOfExpressionWithName() {
3153 super.consumeInstanceOfExpressionWithName();
3154 popElement(K_BINARY_OPERATOR);
3155
3156 InstanceOfExpression exp = (InstanceOfExpression) this.expressionStack[this.expressionPtr];
3157 if(this.assistNode != null && exp.type == this.assistNode) {
3158 this.assistNodeParent = exp;
3159 }
3160 }
3161 @Override
consumeInterfaceHeaderName1()3162 protected void consumeInterfaceHeaderName1() {
3163 super.consumeInterfaceHeaderName1();
3164 this.hasUnusedModifiers = false;
3165 if (this.pendingAnnotation != null) {
3166 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
3167 this.pendingAnnotation = null;
3168 }
3169 classHeaderExtendsOrImplements(true, false);
3170 }
3171 @Override
consumeInterfaceHeaderExtends()3172 protected void consumeInterfaceHeaderExtends() {
3173 super.consumeInterfaceHeaderExtends();
3174 popElement(K_EXTENDS_KEYWORD);
3175 }
3176 @Override
consumeInterfaceType()3177 protected void consumeInterfaceType() {
3178 pushOnElementStack(K_NEXT_TYPEREF_IS_INTERFACE);
3179 super.consumeInterfaceType();
3180 popElement(K_NEXT_TYPEREF_IS_INTERFACE);
3181 }
3182 @Override
consumeMethodInvocationName()3183 protected void consumeMethodInvocationName() {
3184 popElement(K_SELECTOR_QUALIFIER);
3185 popElement(K_SELECTOR_INVOCATION_TYPE);
3186 super.consumeMethodInvocationName();
3187 }
3188 @Override
consumeMethodInvocationNameWithTypeArguments()3189 protected void consumeMethodInvocationNameWithTypeArguments() {
3190 popElement(K_SELECTOR_QUALIFIER);
3191 popElement(K_SELECTOR_INVOCATION_TYPE);
3192 super.consumeMethodInvocationNameWithTypeArguments();
3193 }
3194 @Override
consumeMethodInvocationPrimary()3195 protected void consumeMethodInvocationPrimary() {
3196 popElement(K_SELECTOR_QUALIFIER);
3197 popElement(K_SELECTOR_INVOCATION_TYPE);
3198 super.consumeMethodInvocationPrimary();
3199 }
3200 @Override
consumeMethodInvocationPrimaryWithTypeArguments()3201 protected void consumeMethodInvocationPrimaryWithTypeArguments() {
3202 popElement(K_SELECTOR_QUALIFIER);
3203 popElement(K_SELECTOR_INVOCATION_TYPE);
3204 super.consumeMethodInvocationPrimaryWithTypeArguments();
3205 }
3206 @Override
consumeMethodInvocationSuper()3207 protected void consumeMethodInvocationSuper() {
3208 popElement(K_SELECTOR_QUALIFIER);
3209 popElement(K_SELECTOR_INVOCATION_TYPE);
3210 super.consumeMethodInvocationSuper();
3211 }
3212 @Override
consumeMethodInvocationSuperWithTypeArguments()3213 protected void consumeMethodInvocationSuperWithTypeArguments() {
3214 popElement(K_SELECTOR_QUALIFIER);
3215 popElement(K_SELECTOR_INVOCATION_TYPE);
3216 super.consumeMethodInvocationSuperWithTypeArguments();
3217 }
3218 @Override
consumeMethodHeaderName(boolean isAnnotationMethod)3219 protected void consumeMethodHeaderName(boolean isAnnotationMethod) {
3220 if(this.indexOfAssistIdentifier() < 0) {
3221 this.identifierPtr--;
3222 this.identifierLengthPtr--;
3223 if(this.indexOfAssistIdentifier() != 0 ||
3224 this.identifierLengthStack[this.identifierLengthPtr] != this.genericsIdentifiersLengthStack[this.genericsIdentifiersLengthPtr]) {
3225 this.identifierPtr++;
3226 this.identifierLengthPtr++;
3227 long selectorSourcePositions = this.identifierPositionStack[this.identifierPtr];
3228 int selectorSourceEnd = (int) selectorSourcePositions;
3229 int currentAstPtr = this.astPtr;
3230 super.consumeMethodHeaderName(isAnnotationMethod);
3231 if (this.sourceEnds != null && this.astPtr > currentAstPtr) { // if ast node was pushed on the ast stack
3232 this.sourceEnds.put(this.astStack[this.astPtr], selectorSourceEnd);
3233 }
3234 if (this.pendingAnnotation != null) {
3235 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
3236 this.pendingAnnotation = null;
3237 }
3238 } else {
3239 this.restartRecovery = true;
3240
3241 // recovery
3242 if (this.currentElement != null) {
3243 //name
3244 char[] selector = this.identifierStack[this.identifierPtr + 1];
3245 long selectorSource = this.identifierPositionStack[this.identifierPtr + 1];
3246
3247 //type
3248 TypeReference type = getTypeReference(this.intStack[this.intPtr--]);
3249 ((CompletionOnSingleTypeReference)type).isCompletionNode = false;
3250 //modifiers
3251 int declarationSourceStart = this.intStack[this.intPtr--];
3252 int mod = this.intStack[this.intPtr--];
3253
3254 if(Util.getLineNumber(type.sourceStart, this.scanner.lineEnds, 0, this.scanner.linePtr)
3255 != Util.getLineNumber((int) (selectorSource >>> 32), this.scanner.lineEnds, 0, this.scanner.linePtr)) {
3256 FieldDeclaration completionFieldDecl = new CompletionOnFieldType(type, false);
3257 // consume annotations
3258 int length;
3259 if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
3260 System.arraycopy(
3261 this.expressionStack,
3262 (this.expressionPtr -= length) + 1,
3263 completionFieldDecl.annotations = new Annotation[length],
3264 0,
3265 length);
3266 }
3267 completionFieldDecl.modifiers = mod;
3268 this.assistNode = completionFieldDecl;
3269 this.lastCheckPoint = type.sourceEnd + 1;
3270 this.currentElement = this.currentElement.add(completionFieldDecl, 0);
3271 this.lastIgnoredToken = -1;
3272 } else {
3273 CompletionOnMethodReturnType md = new CompletionOnMethodReturnType(type, this.compilationUnit.compilationResult);
3274 // consume annotations
3275 int length;
3276 if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
3277 System.arraycopy(
3278 this.expressionStack,
3279 (this.expressionPtr -= length) + 1,
3280 md.annotations = new Annotation[length],
3281 0,
3282 length);
3283 }
3284 md.selector = selector;
3285 md.declarationSourceStart = declarationSourceStart;
3286 md.modifiers = mod;
3287 md.bodyStart = this.lParenPos+1;
3288 this.listLength = 0; // initialize listLength before reading parameters/throws
3289 this.assistNode = md;
3290 this.lastCheckPoint = md.bodyStart;
3291 this.currentElement = this.currentElement.add(md, 0);
3292 this.lastIgnoredToken = -1;
3293 // javadoc
3294 md.javadoc = this.javadoc;
3295 this.javadoc = null;
3296 }
3297 }
3298 }
3299 } else {
3300 // MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
3301 CompletionOnMethodName md = new CompletionOnMethodName(this.compilationUnit.compilationResult);
3302
3303 //name
3304 md.selector = this.identifierStack[this.identifierPtr];
3305 long selectorSource = this.identifierPositionStack[this.identifierPtr--];
3306 this.identifierLengthPtr--;
3307 //type
3308 md.returnType = getTypeReference(this.intStack[this.intPtr--]);
3309 md.bits |= (md.returnType.bits & ASTNode.HasTypeAnnotations);
3310 //modifiers
3311 md.declarationSourceStart = this.intStack[this.intPtr--];
3312 md.modifiers = this.intStack[this.intPtr--];
3313 // consume annotations
3314 int length;
3315 if ((length = this.expressionLengthStack[this.expressionLengthPtr--]) != 0) {
3316 System.arraycopy(
3317 this.expressionStack,
3318 (this.expressionPtr -= length) + 1,
3319 md.annotations = new Annotation[length],
3320 0,
3321 length);
3322 }
3323 // javadoc
3324 md.javadoc = this.javadoc;
3325 this.javadoc = null;
3326
3327 //highlight starts at selector start
3328 md.sourceStart = (int) (selectorSource >>> 32);
3329 md.selectorEnd = (int) selectorSource;
3330 pushOnAstStack(md);
3331 md.sourceEnd = this.lParenPos;
3332 md.bodyStart = this.lParenPos+1;
3333 this.listLength = 0; // initialize listLength before reading parameters/throws
3334
3335 this.assistNode = md;
3336 this.lastCheckPoint = md.sourceEnd;
3337 // recovery
3338 if (this.currentElement != null){
3339 if (this.currentElement instanceof RecoveredType
3340 //|| md.modifiers != 0
3341 || (Util.getLineNumber(md.returnType.sourceStart, this.scanner.lineEnds, 0, this.scanner.linePtr)
3342 == Util.getLineNumber(md.sourceStart, this.scanner.lineEnds, 0, this.scanner.linePtr))){
3343 this.lastCheckPoint = md.bodyStart;
3344 this.currentElement = this.currentElement.add(md, 0);
3345 this.lastIgnoredToken = -1;
3346 } else {
3347 this.lastCheckPoint = md.sourceStart;
3348 this.restartRecovery = true;
3349 }
3350 }
3351 }
3352 }
3353 @Override
consumeMethodHeaderNameWithTypeParameters( boolean isAnnotationMethod)3354 protected void consumeMethodHeaderNameWithTypeParameters( boolean isAnnotationMethod) {
3355 long selectorSourcePositions = this.identifierPositionStack[this.identifierPtr];
3356 int selectorSourceEnd = (int) selectorSourcePositions;
3357 int currentAstPtr = this.astPtr;
3358 super.consumeMethodHeaderNameWithTypeParameters(isAnnotationMethod);
3359 if (this.sourceEnds != null && this.astPtr > currentAstPtr) {// if ast node was pushed on the ast stack
3360 this.sourceEnds.put(this.astStack[this.astPtr], selectorSourceEnd);
3361 }
3362 if (this.pendingAnnotation != null) {
3363 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
3364 this.pendingAnnotation = null;
3365 }
3366 }
3367 @Override
consumeMethodHeaderRightParen()3368 protected void consumeMethodHeaderRightParen() {
3369 super.consumeMethodHeaderRightParen();
3370
3371 if (this.currentElement != null
3372 && this.currentToken == TokenNameIdentifier
3373 && this.cursorLocation+1 >= this.scanner.startPosition
3374 && this.cursorLocation < this.scanner.currentPosition){
3375 this.pushIdentifier();
3376
3377 int index = -1;
3378 /* check if current awaiting identifier is the completion identifier */
3379 if ((index = this.indexOfAssistIdentifier()) > -1) {
3380 int ptr = this.identifierPtr - this.identifierLengthStack[this.identifierLengthPtr] + index + 1;
3381 if (this.currentElement instanceof RecoveredMethod){
3382 RecoveredMethod recoveredMethod = (RecoveredMethod)this.currentElement;
3383 /* filter out cases where scanner is still inside type header */
3384 if (!recoveredMethod.foundOpeningBrace) {
3385 AbstractMethodDeclaration method = recoveredMethod.methodDeclaration;
3386 if(method.thrownExceptions == null) {
3387 CompletionOnKeyword1 completionOnKeyword = new CompletionOnKeyword1(
3388 this.identifierStack[ptr],
3389 this.identifierPositionStack[ptr],
3390 Keywords.THROWS);
3391 method.thrownExceptions = new TypeReference[]{completionOnKeyword};
3392 recoveredMethod.foundOpeningBrace = true;
3393 this.assistNode = completionOnKeyword;
3394 this.lastCheckPoint = completionOnKeyword.sourceEnd + 1;
3395 }
3396 }
3397 }
3398 }
3399 }
3400 }
3401 @Override
consumeMethodHeaderExtendedDims()3402 protected void consumeMethodHeaderExtendedDims() {
3403 super.consumeMethodHeaderExtendedDims();
3404
3405 if (this.currentElement != null
3406 && this.currentToken == TokenNameIdentifier
3407 && this.cursorLocation+1 >= this.scanner.startPosition
3408 && this.cursorLocation < this.scanner.currentPosition){
3409 this.pushIdentifier();
3410
3411 int index = -1;
3412 /* check if current awaiting identifier is the completion identifier */
3413 if ((index = this.indexOfAssistIdentifier()) > -1) {
3414 int ptr = this.identifierPtr - this.identifierLengthStack[this.identifierLengthPtr] + index + 1;
3415 RecoveredMethod recoveredMethod = (RecoveredMethod)this.currentElement;
3416 /* filter out cases where scanner is still inside type header */
3417 if (!recoveredMethod.foundOpeningBrace) {
3418 AbstractMethodDeclaration method = recoveredMethod.methodDeclaration;
3419 if(method.thrownExceptions == null) {
3420 CompletionOnKeyword1 completionOnKeyword = new CompletionOnKeyword1(
3421 this.identifierStack[ptr],
3422 this.identifierPositionStack[ptr],
3423 Keywords.THROWS);
3424 method.thrownExceptions = new TypeReference[]{completionOnKeyword};
3425 recoveredMethod.foundOpeningBrace = true;
3426 this.assistNode = completionOnKeyword;
3427 this.lastCheckPoint = completionOnKeyword.sourceEnd + 1;
3428 }
3429 }
3430 }
3431 }
3432 }
3433 @Override
consumeAnnotationAsModifier()3434 protected void consumeAnnotationAsModifier() {
3435 super.consumeAnnotationAsModifier();
3436
3437 if (isInsideMethod()) {
3438 this.hasUnusedModifiers = true;
3439 }
3440 }
3441 @Override
consumeAdditionalBound()3442 protected void consumeAdditionalBound() {
3443 super.consumeAdditionalBound();
3444 ASTNode node = this.genericsStack[this.genericsPtr];
3445 if (node instanceof CompletionOnSingleTypeReference) {
3446 ((CompletionOnSingleTypeReference) node).setKind(CompletionOnQualifiedTypeReference.K_INTERFACE);
3447 } else if (node instanceof CompletionOnQualifiedTypeReference) {
3448 ((CompletionOnQualifiedTypeReference) node).setKind(CompletionOnQualifiedTypeReference.K_INTERFACE);
3449 }
3450 }
3451 @Override
consumeAdditionalBound1()3452 protected void consumeAdditionalBound1() {
3453 super.consumeAdditionalBound1();
3454 ASTNode node = this.genericsStack[this.genericsPtr];
3455 if (node instanceof CompletionOnSingleTypeReference) {
3456 ((CompletionOnSingleTypeReference) node).setKind(CompletionOnQualifiedTypeReference.K_INTERFACE);
3457 } else if (node instanceof CompletionOnQualifiedTypeReference) {
3458 ((CompletionOnQualifiedTypeReference) node).setKind(CompletionOnQualifiedTypeReference.K_INTERFACE);
3459 }
3460 }
3461 @Override
consumeAnnotationName()3462 protected void consumeAnnotationName() {
3463 int index;
3464
3465 if ((index = this.indexOfAssistIdentifier()) < 0) {
3466 super.consumeAnnotationName();
3467 this.pushOnElementStack(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN, LPAREN_NOT_CONSUMED);
3468 return;
3469 }
3470
3471 if (isInImportStatement()) {
3472 return;
3473 }
3474 MarkerAnnotation markerAnnotation = null;
3475 int length = this.identifierLengthStack[this.identifierLengthPtr];
3476 TypeReference typeReference;
3477
3478 /* retrieve identifiers subset and whole positions, the assist node positions
3479 should include the entire replaced source. */
3480
3481 char[][] subset = identifierSubSet(index);
3482 this.identifierLengthPtr--;
3483 this.identifierPtr -= length;
3484 long[] positions = new long[length];
3485 System.arraycopy(
3486 this.identifierPositionStack,
3487 this.identifierPtr + 1,
3488 positions,
3489 0,
3490 length);
3491
3492 /* build specific assist on type reference */
3493
3494 if (index == 0) {
3495 /* assist inside first identifier */
3496 typeReference = createSingleAssistTypeReference(
3497 assistIdentifier(),
3498 positions[0]);
3499 } else {
3500 /* assist inside subsequent identifier */
3501 typeReference = createQualifiedAssistTypeReference(
3502 subset,
3503 assistIdentifier(),
3504 positions);
3505 }
3506
3507 markerAnnotation = new CompletionOnMarkerAnnotationName(typeReference, typeReference.sourceStart);
3508 this.intPtr--;
3509 markerAnnotation.declarationSourceEnd = markerAnnotation.sourceEnd;
3510 pushOnExpressionStack(markerAnnotation);
3511
3512 this.assistNode = markerAnnotation;
3513 this.isOrphanCompletionNode = true;
3514
3515 this.lastCheckPoint = markerAnnotation.sourceEnd + 1;
3516
3517 this.pushOnElementStack(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN, LPAREN_NOT_CONSUMED | ANNOTATION_NAME_COMPLETION);
3518 }
3519 @Override
consumeAnnotationTypeDeclarationHeaderName()3520 protected void consumeAnnotationTypeDeclarationHeaderName() {
3521 super.consumeAnnotationTypeDeclarationHeaderName();
3522 this.hasUnusedModifiers = false;
3523 if (this.pendingAnnotation != null) {
3524 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
3525 this.pendingAnnotation = null;
3526 }
3527 }
3528 @Override
consumeAnnotationTypeDeclarationHeaderNameWithTypeParameters()3529 protected void consumeAnnotationTypeDeclarationHeaderNameWithTypeParameters() {
3530 super.consumeAnnotationTypeDeclarationHeaderNameWithTypeParameters();
3531 this.hasUnusedModifiers = false;
3532 if (this.pendingAnnotation != null) {
3533 this.pendingAnnotation.potentialAnnotatedNode = this.astStack[this.astPtr];
3534 this.pendingAnnotation = null;
3535 }
3536 }
3537 @Override
consumeLabel()3538 protected void consumeLabel() {
3539 super.consumeLabel();
3540 pushOnLabelStack(this.identifierStack[this.identifierPtr]);
3541 this.pushOnElementStack(K_LABEL, this.labelPtr);
3542 }
3543 @Override
consumeLambdaExpression()3544 protected void consumeLambdaExpression() {
3545 super.consumeLambdaExpression();
3546 Expression expression = this.expressionStack[this.expressionPtr];
3547 if (this.assistNode == null || !(this.assistNode.sourceStart >= expression.sourceStart && this.assistNode.sourceEnd <= expression.sourceEnd))
3548 popElement(K_LAMBDA_EXPRESSION_DELIMITER);
3549 }
3550 @Override
consumeMarkerAnnotation(boolean isTypeAnnotation)3551 protected void consumeMarkerAnnotation(boolean isTypeAnnotation) {
3552 if (this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_ANNOTATION_NAME_AND_RPAREN &&
3553 (this.topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) & ANNOTATION_NAME_COMPLETION) != 0 ) {
3554 popElement(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN);
3555 this.restartRecovery = true;
3556 } else {
3557 popElement(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN);
3558 super.consumeMarkerAnnotation(isTypeAnnotation);
3559 }
3560 }
3561 @Override
consumeMemberValuePair()3562 protected void consumeMemberValuePair() {
3563 /* check if current awaiting identifier is the completion identifier */
3564 if (this.indexOfAssistIdentifier() < 0){
3565 super.consumeMemberValuePair();
3566 MemberValuePair memberValuePair = (MemberValuePair) this.astStack[this.astPtr];
3567 if(this.assistNode != null && memberValuePair.value == this.assistNode) {
3568 this.assistNodeParent = memberValuePair;
3569 }
3570 return;
3571 }
3572
3573 char[] simpleName = this.identifierStack[this.identifierPtr];
3574 long position = this.identifierPositionStack[this.identifierPtr--];
3575 this.identifierLengthPtr--;
3576 int end = (int) position;
3577 int start = (int) (position >>> 32);
3578
3579 this.expressionPtr--;
3580 this.expressionLengthPtr--;
3581
3582 CompletionOnMemberValueName memberValueName = new CompletionOnMemberValueName(simpleName,start, end);
3583 pushOnAstStack(memberValueName);
3584 this.assistNode = memberValueName;
3585 this.lastCheckPoint = this.assistNode.sourceEnd + 1;
3586 this.isOrphanCompletionNode = true;
3587
3588 this.restartRecovery = true;
3589 }
3590 @Override
consumeMemberValueAsName()3591 protected void consumeMemberValueAsName() {
3592 if ((indexOfAssistIdentifier()) < 0) {
3593 super.consumeMemberValueAsName();
3594 } else {
3595 super.consumeMemberValueAsName();
3596 final int topKnownElementKind = this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
3597 if(topKnownElementKind == K_BETWEEN_ANNOTATION_NAME_AND_RPAREN || topKnownElementKind == K_MEMBER_VALUE_ARRAY_INITIALIZER) {
3598 this.restartRecovery = true;
3599 }
3600 }
3601 }
3602 @Override
consumeMethodBody()3603 protected void consumeMethodBody() {
3604 popElement(K_BLOCK_DELIMITER);
3605 super.consumeMethodBody();
3606 }
3607 @Override
consumeMethodHeader()3608 protected void consumeMethodHeader() {
3609 super.consumeMethodHeader();
3610 pushOnElementStack(K_BLOCK_DELIMITER);
3611 }
3612 @Override
consumeMethodDeclaration(boolean isNotAbstract, boolean isDefaultMethod)3613 protected void consumeMethodDeclaration(boolean isNotAbstract, boolean isDefaultMethod) {
3614 if (!isNotAbstract) {
3615 popElement(K_BLOCK_DELIMITER);
3616 }
3617 super.consumeMethodDeclaration(isNotAbstract, isDefaultMethod);
3618 }
3619 @Override
consumeModifiers()3620 protected void consumeModifiers() {
3621 super.consumeModifiers();
3622 // save from stack values
3623 this.lastModifiersStart = this.intStack[this.intPtr];
3624 this.lastModifiers = this.intStack[this.intPtr-1];
3625 }
3626 @Override
consumeModuleHeader()3627 protected void consumeModuleHeader() {
3628 super.consumeModuleHeader();
3629 }
3630 @Override
consumeProvidesInterface()3631 protected void consumeProvidesInterface() {
3632 super.consumeProvidesInterface();
3633 pushOnElementStack(K_AFTER_NAME_IN_PROVIDES_STATEMENT);
3634 }
3635 @Override
consumeProvidesStatement()3636 protected void consumeProvidesStatement() {
3637 super.consumeProvidesStatement();
3638 popElement(K_INSIDE_PROVIDES_STATEMENT);
3639 }
3640 @Override
consumeWithClause()3641 protected void consumeWithClause() {
3642 super.consumeWithClause();
3643 popElement(K_AFTER_WITH_IN_PROVIDES_STATEMENT);
3644 }
3645
3646 @Override
consumeReferenceType()3647 protected void consumeReferenceType() {
3648 if (this.identifierLengthStack[this.identifierLengthPtr] > 1) { // reducing a qualified name
3649 // potential receiver is being poped, so reset potential receiver
3650 this.invocationType = NO_RECEIVER;
3651 this.qualifier = -1;
3652 }
3653 super.consumeReferenceType();
3654 }
3655 @Override
consumeRequiresStatement()3656 protected void consumeRequiresStatement() {
3657 super.consumeRequiresStatement();
3658 popElement(K_INSIDE_REQUIRES_STATEMENT);
3659 }
3660 @Override
consumeRestoreDiet()3661 protected void consumeRestoreDiet() {
3662 super.consumeRestoreDiet();
3663 if (isInsideMethod()) {
3664 popElement(K_LOCAL_INITIALIZER_DELIMITER);
3665 }
3666 }
3667 @Override
consumeExportsStatement()3668 protected void consumeExportsStatement() {
3669 super.consumeExportsStatement();
3670 popElement(K_AFTER_PACKAGE_IN_PACKAGE_VISIBILITY_STATEMENT);
3671 popElement(K_INSIDE_EXPORTS_STATEMENT);
3672 }
3673 @Override
consumeSinglePkgName()3674 protected void consumeSinglePkgName() {
3675 super.consumeSinglePkgName();
3676 pushOnElementStack(K_AFTER_PACKAGE_IN_PACKAGE_VISIBILITY_STATEMENT);
3677 }
3678 @Override
consumeSingleMemberAnnotation(boolean isTypeAnnotation)3679 protected void consumeSingleMemberAnnotation(boolean isTypeAnnotation) {
3680 if (this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_ANNOTATION_NAME_AND_RPAREN &&
3681 (this.topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) & ANNOTATION_NAME_COMPLETION) != 0 ) {
3682 popElement(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN);
3683 this.restartRecovery = true;
3684 } else {
3685 popElement(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN);
3686 super.consumeSingleMemberAnnotation(isTypeAnnotation);
3687 }
3688 }
3689 @Override
consumeSingleStaticImportDeclarationName()3690 protected void consumeSingleStaticImportDeclarationName() {
3691 super.consumeSingleStaticImportDeclarationName();
3692 this.pendingAnnotation = null; // the pending annotation cannot be attached to next nodes
3693 }
3694 @Override
consumeSingleTypeImportDeclarationName()3695 protected void consumeSingleTypeImportDeclarationName() {
3696 super.consumeSingleTypeImportDeclarationName();
3697 this.pendingAnnotation = null; // the pending annotation cannot be attached to next nodes
3698 }
3699 @Override
consumeStatementBreakWithLabel()3700 protected void consumeStatementBreakWithLabel() {
3701 super.consumeStatementBreakWithLabel();
3702 if (this.record) {
3703 ASTNode breakStatement = this.astStack[this.astPtr];
3704 if (!isAlreadyPotentialName(breakStatement.sourceStart)) {
3705 addPotentialName(null, breakStatement.sourceStart, breakStatement.sourceEnd);
3706 }
3707 }
3708
3709 }
3710 @Override
consumeStatementLabel()3711 protected void consumeStatementLabel() {
3712 popElement(K_LABEL);
3713 super.consumeStatementLabel();
3714 }
3715 @Override
consumeStatementSwitch()3716 protected void consumeStatementSwitch() {
3717 super.consumeStatementSwitch();
3718 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SWITCH_LABEL) {
3719 popElement(K_SWITCH_LABEL);
3720 popElement(K_BLOCK_DELIMITER);
3721 }
3722 }
3723 @Override
consumeStatementWhile()3724 protected void consumeStatementWhile() {
3725 super.consumeStatementWhile();
3726 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_CONTROL_STATEMENT_DELIMITER) {
3727 popElement(K_CONTROL_STATEMENT_DELIMITER);
3728 }
3729 }
3730 @Override
consumeStaticImportOnDemandDeclarationName()3731 protected void consumeStaticImportOnDemandDeclarationName() {
3732 super.consumeStaticImportOnDemandDeclarationName();
3733 this.pendingAnnotation = null; // the pending annotation cannot be attached to next nodes
3734 }
3735 @Override
consumeStaticInitializer()3736 protected void consumeStaticInitializer() {
3737 super.consumeStaticInitializer();
3738 this.pendingAnnotation = null; // the pending annotation cannot be attached to next nodes
3739 }
3740 @Override
consumeNestedMethod()3741 protected void consumeNestedMethod() {
3742 super.consumeNestedMethod();
3743 if(!(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BLOCK_DELIMITER)) pushOnElementStack(K_BLOCK_DELIMITER);
3744 }
3745 @Override
consumeNormalAnnotation(boolean isTypeAnnotation)3746 protected void consumeNormalAnnotation(boolean isTypeAnnotation) {
3747 if (this.topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_ANNOTATION_NAME_AND_RPAREN &&
3748 (this.topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) & ANNOTATION_NAME_COMPLETION) != 0 ) {
3749 popElement(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN);
3750 this.restartRecovery = true;
3751 } else {
3752 popElement(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN);
3753 if (this.expressionPtr >= 0 && this.expressionStack[this.expressionPtr] instanceof CompletionOnMarkerAnnotationName) {
3754 Annotation annotation = (Annotation)this.expressionStack[this.expressionPtr];
3755 if(this.currentElement != null) {
3756 annotationRecoveryCheckPoint(annotation.sourceStart, annotation.declarationSourceEnd);
3757 if (this.currentElement instanceof RecoveredAnnotation) {
3758 this.currentElement = ((RecoveredAnnotation)this.currentElement).addAnnotation(annotation, this.identifierPtr);
3759 }
3760 }
3761
3762 if(!this.statementRecoveryActivated &&
3763 this.options.sourceLevel < ClassFileConstants.JDK1_5 &&
3764 this.lastErrorEndPositionBeforeRecovery < this.scanner.currentPosition) {
3765 problemReporter().invalidUsageOfAnnotation(annotation);
3766 }
3767 this.recordStringLiterals = true;
3768 return;
3769 }
3770 super.consumeNormalAnnotation(isTypeAnnotation);
3771 }
3772 }
3773 @Override
consumePackageDeclarationName()3774 protected void consumePackageDeclarationName() {
3775 super.consumePackageDeclarationName();
3776 if (this.pendingAnnotation != null) {
3777 this.pendingAnnotation.potentialAnnotatedNode = this.compilationUnit.currentPackage;
3778 this.pendingAnnotation = null;
3779 }
3780 }
3781 @Override
consumePackageDeclarationNameWithModifiers()3782 protected void consumePackageDeclarationNameWithModifiers() {
3783 super.consumePackageDeclarationNameWithModifiers();
3784 if (this.pendingAnnotation != null) {
3785 this.pendingAnnotation.potentialAnnotatedNode = this.compilationUnit.currentPackage;
3786 this.pendingAnnotation = null;
3787 }
3788 }
3789 @Override
consumePrimaryNoNewArrayName()3790 protected void consumePrimaryNoNewArrayName() {
3791 // this is class literal access, so reset potential receiver
3792 this.invocationType = NO_RECEIVER;
3793 this.qualifier = -1;
3794
3795 super.consumePrimaryNoNewArrayName();
3796 }
3797 @Override
consumeQualifiedSuperReceiver()3798 protected void consumeQualifiedSuperReceiver() {
3799 // this is class literal access, so reset potential receiver
3800 this.invocationType = NO_RECEIVER;
3801 this.qualifier = -1;
3802
3803 super.consumeQualifiedSuperReceiver();
3804 }
3805 @Override
consumePrimaryNoNewArrayNameThis()3806 protected void consumePrimaryNoNewArrayNameThis() {
3807 // this is class literal access, so reset potential receiver
3808 this.invocationType = NO_RECEIVER;
3809 this.qualifier = -1;
3810
3811 super.consumePrimaryNoNewArrayNameThis();
3812 }
3813 @Override
consumePushPosition()3814 protected void consumePushPosition() {
3815 super.consumePushPosition();
3816 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BINARY_OPERATOR) {
3817 int info = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER);
3818 popElement(K_BINARY_OPERATOR);
3819 pushOnElementStack(K_UNARY_OPERATOR, info);
3820 }
3821 }
3822 @Override
consumeSwitchLabeledBlock()3823 protected void consumeSwitchLabeledBlock() {
3824 popUntilElement(K_SWITCH_LABEL);
3825 popElement(K_SWITCH_LABEL);
3826 concatNodeLists();
3827 }
3828 @Override
consumeToken(int token)3829 protected void consumeToken(int token) {
3830 if(this.isFirst) {
3831 super.consumeToken(token);
3832 return;
3833 }
3834 if(this.canBeExplicitConstructor == NEXTTOKEN) {
3835 this.canBeExplicitConstructor = YES;
3836 } else {
3837 this.canBeExplicitConstructor = NO;
3838 }
3839
3840 int previous = this.previousToken;
3841 int prevIdentifierPtr = this.previousIdentifierPtr;
3842
3843 isInsideEnhancedForLoopWithoutBlock(token);
3844
3845 if (isInsideMethod() || isInsideFieldInitialization() || isInsideAnnotation() || isInsideEnumConstantnitialization()) {
3846 switch(token) {
3847 case TokenNameLPAREN:
3848 if(previous == TokenNameIdentifier &&
3849 topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_METHOD_INVOCATION) {
3850 popElement(K_PARAMETERIZED_METHOD_INVOCATION);
3851 } else {
3852 popElement(K_BETWEEN_NEW_AND_LEFT_BRACKET);
3853 }
3854 break;
3855 case TokenNameLBRACE:
3856 popElement(K_BETWEEN_NEW_AND_LEFT_BRACKET);
3857 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SWITCH_LABEL
3858 && previous == TokenNameARROW) {
3859 pushOnElementStack(K_SWITCH_EXPRESSION_DELIMITTER);
3860 }
3861 break;
3862 case TokenNameLBRACKET:
3863 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_NEW_AND_LEFT_BRACKET) {
3864 popElement(K_BETWEEN_NEW_AND_LEFT_BRACKET);
3865 pushOnElementStack(K_ARRAY_CREATION);
3866 }
3867 break;
3868 case TokenNameRBRACE:
3869 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
3870 switch (kind) {
3871 case K_BLOCK_DELIMITER:
3872 popElement(K_BLOCK_DELIMITER);
3873 break;
3874 case K_MEMBER_VALUE_ARRAY_INITIALIZER:
3875 popElement(K_MEMBER_VALUE_ARRAY_INITIALIZER);
3876 break;
3877 case K_LAMBDA_EXPRESSION_DELIMITER:
3878 break; // will be popped when the containing block statement is reduced.
3879 default:
3880 popElement(K_ARRAY_INITIALIZER);
3881 break;
3882 }
3883 break;
3884 case TokenNameRBRACKET:
3885 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BETWEEN_LEFT_AND_RIGHT_BRACKET) {
3886 popElement(K_BETWEEN_LEFT_AND_RIGHT_BRACKET);
3887 }
3888 break;
3889
3890 }
3891 }
3892 super.consumeToken(token);
3893
3894 // if in field initializer (directly or not), on the completion identifier and not in recovery mode yet
3895 // then position end of file at cursor location (so that we have the same behavior as
3896 // in method bodies)
3897 if (token == TokenNameIdentifier
3898 && this.identifierStack[this.identifierPtr] == assistIdentifier()
3899 && this.currentElement == null
3900 && (!isIndirectlyInsideLambdaExpression() || isIndirectlyInsideLambdaBlock())
3901 && (isIndirectlyInsideFieldInitialization() || isIndirectlyInsideEnumConstantnitialization())) {
3902 this.scanner.eofPosition = this.cursorLocation < Integer.MAX_VALUE ? this.cursorLocation+1 : this.cursorLocation;
3903 }
3904 if (token == TokenNameimport) {
3905 pushOnElementStack(K_INSIDE_IMPORT_STATEMENT);
3906 } else if (token == TokenNameexports) {
3907 pushOnElementStack(K_INSIDE_EXPORTS_STATEMENT);
3908 } else if (token == TokenNameopens) {
3909 pushOnElementStack(K_INSIDE_OPENS_STATEMENT);
3910 } else if (token == TokenNameto) {
3911 popElement(K_AFTER_PACKAGE_IN_PACKAGE_VISIBILITY_STATEMENT);
3912 } else if (token == TokenNamerequires) {
3913 pushOnElementStack(K_INSIDE_REQUIRES_STATEMENT);
3914 } else if (token == TokenNameprovides) {
3915 pushOnElementStack(K_INSIDE_PROVIDES_STATEMENT);
3916 } else if (token == TokenNameuses) {
3917 pushOnElementStack(K_INSIDE_USES_STATEMENT);
3918 } else if (token == TokenNamewith) {
3919 popElement(K_AFTER_NAME_IN_PROVIDES_STATEMENT);
3920 pushOnElementStack(K_AFTER_WITH_IN_PROVIDES_STATEMENT);
3921 }
3922
3923 // if in a method or if in a field initializer
3924 if (isInsideMethod() || isInsideFieldInitialization() || isInsideAttributeValue() || isInsideEnumConstantnitialization()) {
3925 switch (token) {
3926 case TokenNameDOT:
3927 switch (previous) {
3928 case TokenNamethis: // e.g. this[.]fred()
3929 this.invocationType = EXPLICIT_RECEIVER;
3930 break;
3931 case TokenNamesuper: // e.g. super[.]fred()
3932 this.invocationType = SUPER_RECEIVER;
3933 break;
3934 case TokenNameIdentifier: // e.g. bar[.]fred()
3935 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) != K_BETWEEN_NEW_AND_LEFT_BRACKET) {
3936 if (this.identifierPtr != prevIdentifierPtr) { // if identifier has been consumed, e.g. this.x[.]fred()
3937 this.invocationType = EXPLICIT_RECEIVER;
3938 } else {
3939 this.invocationType = NAME_RECEIVER;
3940 }
3941 }
3942 break;
3943 }
3944 break;
3945 case TokenNameCOLON_COLON:
3946 this.inReferenceExpression = true;
3947 break;
3948 case TokenNameIdentifier:
3949 if (this.inReferenceExpression)
3950 break;
3951 if (this.scanner.previewEnabled && isInsideSwitch() && checkYieldKeyword()) {
3952 pushOnElementStack(K_YIELD_KEYWORD);
3953 // Take the short cut here.
3954 // Instead of injecting the TokenNameRestrictedIdentifierYield, totally ignore it
3955 // and let completion take it course. We will not be constructing the
3956 // YieldStatement and thus not producing accurate completion, but completion doesn't have
3957 // enough information anyway about the LHS anyway.
3958 token = this.currentToken = this.getNextToken();
3959 super.consumeToken(this.currentToken);
3960 }
3961 if (previous == TokenNameDOT) { // e.g. foo().[fred]()
3962 if (this.invocationType != SUPER_RECEIVER // e.g. not super.[fred]()
3963 && this.invocationType != NAME_RECEIVER // e.g. not bar.[fred]()
3964 && this.invocationType != ALLOCATION // e.g. not new foo.[Bar]()
3965 && this.invocationType != QUALIFIED_ALLOCATION) { // e.g. not fred().new foo.[Bar]()
3966
3967 this.invocationType = EXPLICIT_RECEIVER;
3968 this.qualifier = this.expressionPtr;
3969 }
3970 }
3971 if (previous == TokenNameGREATER) { // e.g. foo().<X>[fred]()
3972 if (this.invocationType != SUPER_RECEIVER // e.g. not super.<X>[fred]()
3973 && this.invocationType != NAME_RECEIVER // e.g. not bar.<X>[fred]()
3974 && this.invocationType != ALLOCATION // e.g. not new foo.<X>[Bar]()
3975 && this.invocationType != QUALIFIED_ALLOCATION) { // e.g. not fred().new foo.<X>[Bar]()
3976
3977 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_METHOD_INVOCATION) {
3978 this.invocationType = EXPLICIT_RECEIVER;
3979 this.qualifier = this.expressionPtr;
3980 }
3981 }
3982 }
3983 break;
3984 case TokenNamenew:
3985 if (this.inReferenceExpression)
3986 break;
3987 pushOnElementStack(K_BETWEEN_NEW_AND_LEFT_BRACKET);
3988 this.qualifier = this.expressionPtr; // NB: even if there is no qualification, set it to the expression ptr so that the number of arguments are correctly computed
3989 if (previous == TokenNameDOT) { // e.g. fred().[new] X()
3990 this.invocationType = QUALIFIED_ALLOCATION;
3991 } else { // e.g. [new] X()
3992 this.invocationType = ALLOCATION;
3993 }
3994 break;
3995 case TokenNamethis:
3996 if (previous == TokenNameDOT) { // e.g. fred().[this]()
3997 this.invocationType = QUALIFIED_ALLOCATION;
3998 this.qualifier = this.expressionPtr;
3999 }
4000 break;
4001 case TokenNamesuper:
4002 if (previous == TokenNameDOT) { // e.g. fred().[super]()
4003 this.invocationType = QUALIFIED_ALLOCATION;
4004 this.qualifier = this.expressionPtr;
4005 }
4006 break;
4007 case TokenNamecatch:
4008 pushOnElementStack(K_BETWEEN_CATCH_AND_RIGHT_PAREN);
4009 break;
4010 case TokenNameLPAREN:
4011 if (this.invocationType == NO_RECEIVER || this.invocationType == NAME_RECEIVER || this.invocationType == SUPER_RECEIVER) {
4012 this.qualifier = this.expressionPtr; // remenber the last expression so that arguments are correctly computed
4013 }
4014 switch (previous) {
4015 case TokenNameIdentifier: // e.g. fred[(]) or foo.fred[(])
4016 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SELECTOR) {
4017 int info = 0;
4018 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER,1) == K_BETWEEN_ANNOTATION_NAME_AND_RPAREN &&
4019 (info=topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER,1) & LPAREN_NOT_CONSUMED) != 0) {
4020 popElement(K_SELECTOR);
4021 popElement(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN);
4022 if ((info & ANNOTATION_NAME_COMPLETION) != 0) {
4023 this.pushOnElementStack(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN, LPAREN_CONSUMED | ANNOTATION_NAME_COMPLETION);
4024 } else {
4025 this.pushOnElementStack(K_BETWEEN_ANNOTATION_NAME_AND_RPAREN, LPAREN_CONSUMED);
4026 }
4027 } else {
4028 this.pushOnElementStack(K_SELECTOR_INVOCATION_TYPE, this.invocationType);
4029 this.pushOnElementStack(K_SELECTOR_QUALIFIER, this.qualifier);
4030 }
4031 }
4032 this.qualifier = -1;
4033 this.invocationType = NO_RECEIVER;
4034 break;
4035 case TokenNamethis: // explicit constructor invocation, e.g. this[(]1, 2)
4036 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SELECTOR) {
4037 this.pushOnElementStack(K_SELECTOR_INVOCATION_TYPE, (this.invocationType == QUALIFIED_ALLOCATION) ? QUALIFIED_ALLOCATION : ALLOCATION);
4038 this.pushOnElementStack(K_SELECTOR_QUALIFIER, this.qualifier);
4039 }
4040 this.qualifier = -1;
4041 this.invocationType = NO_RECEIVER;
4042 break;
4043 case TokenNamesuper: // explicit constructor invocation, e.g. super[(]1, 2)
4044 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SELECTOR) {
4045 this.pushOnElementStack(K_SELECTOR_INVOCATION_TYPE, (this.invocationType == QUALIFIED_ALLOCATION) ? QUALIFIED_ALLOCATION : ALLOCATION);
4046 this.pushOnElementStack(K_SELECTOR_QUALIFIER, this.qualifier);
4047 }
4048 this.qualifier = -1;
4049 this.invocationType = NO_RECEIVER;
4050 break;
4051 case TokenNameGREATER: // explicit constructor invocation, e.g. Fred<X>[(]1, 2)
4052 case TokenNameRIGHT_SHIFT: // or fred<X<X>>[(]1, 2)
4053 case TokenNameUNSIGNED_RIGHT_SHIFT: //or Fred<X<X<X>>>[(]1, 2)
4054 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SELECTOR) {
4055 int info;
4056 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, 1) == K_BINARY_OPERATOR &&
4057 ((info = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER, 1)) == GREATER || info == RIGHT_SHIFT || info == UNSIGNED_RIGHT_SHIFT)) {
4058 // it's not a selector invocation
4059 popElement(K_SELECTOR);
4060 } else {
4061 this.pushOnElementStack(K_SELECTOR_INVOCATION_TYPE, (this.invocationType == QUALIFIED_ALLOCATION) ? QUALIFIED_ALLOCATION : ALLOCATION);
4062 this.pushOnElementStack(K_SELECTOR_QUALIFIER, this.qualifier);
4063 }
4064 }
4065 this.qualifier = -1;
4066 this.invocationType = NO_RECEIVER;
4067 break;
4068 }
4069 break;
4070 case TokenNameLBRACE:
4071 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
4072 if(kind == K_FIELD_INITIALIZER_DELIMITER
4073 || kind == K_LOCAL_INITIALIZER_DELIMITER
4074 || kind == K_ARRAY_CREATION) {
4075 pushOnElementStack(K_ARRAY_INITIALIZER, this.endPosition);
4076 } else if (kind == K_BETWEEN_ANNOTATION_NAME_AND_RPAREN || kind == K_ATTRIBUTE_VALUE_DELIMITER) {
4077 pushOnElementStack(K_MEMBER_VALUE_ARRAY_INITIALIZER, this.endPosition);
4078 } else {
4079 if (kind == K_CONTROL_STATEMENT_DELIMITER) {
4080 int info = topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER);
4081 popElement(K_CONTROL_STATEMENT_DELIMITER);
4082 if (info == IF) {
4083 pushOnElementStack(K_BLOCK_DELIMITER, IF, this.expressionStack[this.expressionPtr]);
4084 } else {
4085 pushOnElementStack(K_BLOCK_DELIMITER, info);
4086 }
4087 } else {
4088 switch(previous) {
4089 case TokenNameRPAREN :
4090 switch(this.previousKind) {
4091 case K_BETWEEN_CATCH_AND_RIGHT_PAREN :
4092 pushOnElementStack(K_BLOCK_DELIMITER, CATCH);
4093 break;
4094 case K_BETWEEN_SWITCH_AND_RIGHT_PAREN :
4095 pushOnElementStack(K_BLOCK_DELIMITER, SWITCH);
4096 break;
4097 case K_BETWEEN_SYNCHRONIZED_AND_RIGHT_PAREN :
4098 pushOnElementStack(K_BLOCK_DELIMITER, SYNCHRONIZED);
4099 break;
4100 default :
4101 pushOnElementStack(K_BLOCK_DELIMITER);
4102 break;
4103 }
4104 break;
4105 case TokenNametry :
4106 pushOnElementStack(K_BLOCK_DELIMITER, TRY);
4107 break;
4108 case TokenNamedo:
4109 pushOnElementStack(K_BLOCK_DELIMITER, DO);
4110 break;
4111 case TokenNameARROW:
4112 break;
4113 default :
4114 pushOnElementStack(K_BLOCK_DELIMITER);
4115 break;
4116 }
4117 }
4118 }
4119 break;
4120 case TokenNameLBRACKET:
4121 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) != K_ARRAY_CREATION) {
4122 pushOnElementStack(K_BETWEEN_LEFT_AND_RIGHT_BRACKET);
4123 } else {
4124 switch (previous) {
4125 case TokenNameIdentifier:
4126 case TokenNameboolean:
4127 case TokenNamebyte:
4128 case TokenNamechar:
4129 case TokenNamedouble:
4130 case TokenNamefloat:
4131 case TokenNameint:
4132 case TokenNamelong:
4133 case TokenNameshort:
4134 case TokenNameGREATER:
4135 case TokenNameRIGHT_SHIFT:
4136 case TokenNameUNSIGNED_RIGHT_SHIFT:
4137 this.invocationType = NO_RECEIVER;
4138 this.qualifier = -1;
4139 break;
4140 }
4141 }
4142 break;
4143 case TokenNameRPAREN:
4144 switch(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER)) {
4145 case K_BETWEEN_CATCH_AND_RIGHT_PAREN :
4146 popElement(K_BETWEEN_CATCH_AND_RIGHT_PAREN);
4147 break;
4148 case K_BETWEEN_INSTANCEOF_AND_RPAREN :
4149 popElement(K_BETWEEN_INSTANCEOF_AND_RPAREN);
4150 //$FALL-THROUGH$
4151 case K_BETWEEN_IF_AND_RIGHT_PAREN :
4152 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4153 popElement(K_BETWEEN_IF_AND_RIGHT_PAREN);
4154 pushOnElementStack(K_CONTROL_STATEMENT_DELIMITER, IF, this.expressionStack[this.expressionPtr]);
4155 }
4156 break;
4157 case K_BETWEEN_WHILE_AND_RIGHT_PAREN :
4158 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4159 popElement(K_BETWEEN_WHILE_AND_RIGHT_PAREN);
4160 pushOnElementStack(K_CONTROL_STATEMENT_DELIMITER, WHILE);
4161 }
4162 break;
4163 case K_BETWEEN_FOR_AND_RIGHT_PAREN :
4164 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4165 popElement(K_BETWEEN_FOR_AND_RIGHT_PAREN);
4166 pushOnElementStack(K_CONTROL_STATEMENT_DELIMITER, FOR);
4167 }
4168 break;
4169 case K_BETWEEN_SWITCH_AND_RIGHT_PAREN :
4170 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4171 popElement(K_BETWEEN_SWITCH_AND_RIGHT_PAREN);
4172 }
4173 break;
4174 case K_BETWEEN_SYNCHRONIZED_AND_RIGHT_PAREN :
4175 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4176 popElement(K_BETWEEN_SYNCHRONIZED_AND_RIGHT_PAREN);
4177 }
4178 break;
4179 }
4180 break;
4181 case TokenNamethrow:
4182 pushOnElementStack(K_INSIDE_THROW_STATEMENT, this.bracketDepth);
4183 break;
4184 case TokenNameSEMICOLON:
4185 switch(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER)) {
4186 case K_INSIDE_THROW_STATEMENT :
4187 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4188 popElement(K_INSIDE_THROW_STATEMENT);
4189 }
4190 break;
4191 case K_INSIDE_RETURN_STATEMENT :
4192 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4193 popElement(K_INSIDE_RETURN_STATEMENT);
4194 }
4195 break;
4196 case K_INSIDE_ASSERT_STATEMENT :
4197 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4198 popElement(K_INSIDE_ASSERT_STATEMENT);
4199 }
4200 break;
4201 case K_INSIDE_ASSERT_EXCEPTION :
4202 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4203 popElement(K_INSIDE_ASSERT_EXCEPTION);
4204 popElement(K_INSIDE_ASSERT_STATEMENT);
4205 }
4206 break;
4207 case K_INSIDE_BREAK_STATEMENT:
4208 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4209 popElement(K_INSIDE_BREAK_STATEMENT);
4210 }
4211 break;
4212 case K_INSIDE_CONTINUE_STATEMENT:
4213 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth) {
4214 popElement(K_INSIDE_CONTINUE_STATEMENT);
4215 }
4216 break;
4217 case K_BETWEEN_FOR_AND_RIGHT_PAREN:
4218 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth - 1) {
4219 popElement(K_BETWEEN_FOR_AND_RIGHT_PAREN);
4220 pushOnElementStack(K_INSIDE_FOR_CONDITIONAL, this.bracketDepth - 1);
4221 }
4222 break;
4223 case K_INSIDE_FOR_CONDITIONAL:
4224 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == this.bracketDepth - 1) {
4225 popElement(K_INSIDE_FOR_CONDITIONAL);
4226 pushOnElementStack(K_BETWEEN_FOR_AND_RIGHT_PAREN, this.bracketDepth - 1);
4227 }
4228 break;
4229 }
4230 break;
4231 case TokenNamereturn:
4232 pushOnElementStack(K_INSIDE_RETURN_STATEMENT, this.bracketDepth);
4233 break;
4234 case TokenNameMULTIPLY:
4235 pushOnElementStack(K_BINARY_OPERATOR, MULTIPLY);
4236 break;
4237 case TokenNameDIVIDE:
4238 pushOnElementStack(K_BINARY_OPERATOR, DIVIDE);
4239 break;
4240 case TokenNameREMAINDER:
4241 pushOnElementStack(K_BINARY_OPERATOR, REMAINDER);
4242 break;
4243 case TokenNamePLUS:
4244 pushOnElementStack(K_BINARY_OPERATOR, PLUS);
4245 break;
4246 case TokenNameMINUS:
4247 pushOnElementStack(K_BINARY_OPERATOR, MINUS);
4248 break;
4249 case TokenNameLEFT_SHIFT:
4250 pushOnElementStack(K_BINARY_OPERATOR, LEFT_SHIFT);
4251 break;
4252 case TokenNameRIGHT_SHIFT:
4253 pushOnElementStack(K_BINARY_OPERATOR, RIGHT_SHIFT);
4254 break;
4255 case TokenNameUNSIGNED_RIGHT_SHIFT:
4256 pushOnElementStack(K_BINARY_OPERATOR, UNSIGNED_RIGHT_SHIFT);
4257 break;
4258 case TokenNameLESS:
4259 switch(previous) {
4260 case TokenNameDOT :
4261 pushOnElementStack(K_PARAMETERIZED_METHOD_INVOCATION);
4262 break;
4263 case TokenNamenew :
4264 pushOnElementStack(K_PARAMETERIZED_ALLOCATION);
4265 break;
4266 }
4267 pushOnElementStack(K_BINARY_OPERATOR, LESS);
4268 break;
4269 case TokenNameGREATER:
4270 pushOnElementStack(K_BINARY_OPERATOR, GREATER);
4271 break;
4272 case TokenNameLESS_EQUAL:
4273 pushOnElementStack(K_BINARY_OPERATOR, LESS_EQUAL);
4274 break;
4275 case TokenNameGREATER_EQUAL:
4276 pushOnElementStack(K_BINARY_OPERATOR, GREATER_EQUAL);
4277 break;
4278 case TokenNameAND:
4279 pushOnElementStack(K_BINARY_OPERATOR, AND);
4280 break;
4281 case TokenNameXOR:
4282 pushOnElementStack(K_BINARY_OPERATOR, XOR);
4283 break;
4284 case TokenNameOR:
4285 // Don't push the OR operator used for union types in a catch declaration
4286 if (topKnownElementKind(COMPLETION_PARSER) != K_BETWEEN_CATCH_AND_RIGHT_PAREN)
4287 pushOnElementStack(K_BINARY_OPERATOR, OR);
4288 break;
4289 case TokenNameAND_AND:
4290 pushOnElementStack(K_BINARY_OPERATOR, AND_AND);
4291 break;
4292 case TokenNameOR_OR:
4293 pushOnElementStack(K_BINARY_OPERATOR, OR_OR);
4294 break;
4295 case TokenNamePLUS_PLUS:
4296 pushOnElementStack(K_UNARY_OPERATOR, PLUS_PLUS);
4297 break;
4298 case TokenNameMINUS_MINUS:
4299 pushOnElementStack(K_UNARY_OPERATOR, MINUS_MINUS);
4300 break;
4301 case TokenNameTWIDDLE:
4302 pushOnElementStack(K_UNARY_OPERATOR, TWIDDLE);
4303 break;
4304 case TokenNameNOT:
4305 pushOnElementStack(K_UNARY_OPERATOR, NOT);
4306 break;
4307 case TokenNameEQUAL_EQUAL:
4308 pushOnElementStack(K_BINARY_OPERATOR, EQUAL_EQUAL);
4309 break;
4310 case TokenNameNOT_EQUAL:
4311 pushOnElementStack(K_BINARY_OPERATOR, NOT_EQUAL);
4312 break;
4313 case TokenNameinstanceof:
4314 pushOnElementStack(K_BINARY_OPERATOR, INSTANCEOF);
4315 break;
4316 case TokenNameQUESTION:
4317 if(previous != TokenNameLESS && previous != TokenNameCOMMA) {
4318 pushOnElementStack(K_CONDITIONAL_OPERATOR, QUESTION);
4319 }
4320 break;
4321 case TokenNameARROW:
4322 switch (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER)) {
4323 case K_BETWEEN_CASE_AND_COLON:
4324 popElement(K_BETWEEN_CASE_AND_COLON);
4325 break;
4326 case K_BETWEEN_DEFAULT_AND_COLON:
4327 popElement(K_BETWEEN_DEFAULT_AND_COLON);
4328 break;
4329 }
4330 break;
4331 case TokenNameCOLON:
4332 switch (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER)) {
4333 case K_CONDITIONAL_OPERATOR:
4334 if (topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == QUESTION) {
4335 popElement(K_CONDITIONAL_OPERATOR);
4336 pushOnElementStack(K_CONDITIONAL_OPERATOR, COLON);
4337 }
4338 break;
4339 case K_BETWEEN_CASE_AND_COLON:
4340 popElement(K_BETWEEN_CASE_AND_COLON);
4341 break;
4342 case K_BETWEEN_DEFAULT_AND_COLON:
4343 popElement(K_BETWEEN_DEFAULT_AND_COLON);
4344 break;
4345 case K_INSIDE_ASSERT_STATEMENT:
4346 pushOnElementStack(K_INSIDE_ASSERT_EXCEPTION, this.bracketDepth);
4347 break;
4348 }
4349 break;
4350 case TokenNameif:
4351 pushOnElementStack(K_BETWEEN_IF_AND_RIGHT_PAREN, this.bracketDepth);
4352 break;
4353 case TokenNameelse:
4354 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_CONTROL_STATEMENT_DELIMITER) {
4355 popElement(K_CONTROL_STATEMENT_DELIMITER);
4356 }
4357 pushOnElementStack(K_CONTROL_STATEMENT_DELIMITER);
4358 break;
4359 case TokenNamewhile:
4360 pushOnElementStack(K_BETWEEN_WHILE_AND_RIGHT_PAREN, this.bracketDepth);
4361 break;
4362 case TokenNamefor:
4363 pushOnElementStack(K_BETWEEN_FOR_AND_RIGHT_PAREN, this.bracketDepth);
4364 break;
4365 case TokenNameswitch:
4366 popElement(K_LOCAL_INITIALIZER_DELIMITER);
4367 pushOnElementStack(K_BETWEEN_SWITCH_AND_RIGHT_PAREN, this.bracketDepth);
4368 break;
4369 case TokenNamesynchronized:
4370 pushOnElementStack(K_BETWEEN_SYNCHRONIZED_AND_RIGHT_PAREN, this.bracketDepth);
4371 break;
4372 case TokenNameassert:
4373 pushOnElementStack(K_INSIDE_ASSERT_STATEMENT, this.bracketDepth);
4374 break;
4375 case TokenNamecase :
4376 pushOnElementStack(K_BETWEEN_CASE_AND_COLON);
4377 break;
4378 case TokenNameCOMMA :
4379 switch (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER)) {
4380 // for multi constant case stmt
4381 // case MONDAY, FRI
4382 // if there's a comma, ignore the previous expression (constant)
4383 // Which doesn't matter for completing the next constant
4384 case K_BETWEEN_CASE_AND_COLON:
4385 this.expressionPtr--;
4386 this.expressionLengthStack[this.expressionLengthPtr]--;
4387 }
4388 break;
4389 case TokenNamedefault :
4390 pushOnElementStack(K_BETWEEN_DEFAULT_AND_COLON);
4391 break;
4392 case TokenNameextends:
4393 pushOnElementStack(K_EXTENDS_KEYWORD);
4394 break;
4395 case TokenNamebreak:
4396 pushOnElementStack(K_INSIDE_BREAK_STATEMENT, this.bracketDepth);
4397 break;
4398 case TokenNamecontinue:
4399 pushOnElementStack(K_INSIDE_CONTINUE_STATEMENT, this.bracketDepth);
4400 break;
4401 }
4402 } else if (isInsideAnnotation()){
4403 switch (token) {
4404 case TokenNameLBRACE:
4405 this.bracketDepth++;
4406 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
4407 if (kind == K_BETWEEN_ANNOTATION_NAME_AND_RPAREN) {
4408 pushOnElementStack(K_MEMBER_VALUE_ARRAY_INITIALIZER, this.endPosition);
4409 }
4410 break;
4411 }
4412 } else {
4413 switch(token) {
4414 case TokenNameextends:
4415 pushOnElementStack(K_EXTENDS_KEYWORD);
4416 break;
4417 case TokenNameLESS:
4418 pushOnElementStack(K_BINARY_OPERATOR, LESS);
4419 break;
4420 case TokenNameGREATER:
4421 pushOnElementStack(K_BINARY_OPERATOR, GREATER);
4422 break;
4423 case TokenNameRIGHT_SHIFT:
4424 pushOnElementStack(K_BINARY_OPERATOR, RIGHT_SHIFT);
4425 break;
4426 case TokenNameUNSIGNED_RIGHT_SHIFT:
4427 pushOnElementStack(K_BINARY_OPERATOR, UNSIGNED_RIGHT_SHIFT);
4428 break;
4429
4430 }
4431 }
4432 }
4433 private void isInsideEnhancedForLoopWithoutBlock(int token) {
4434 if( this.consumedEnhancedFor == true && token != TokenNameLBRACE) {
4435 consumeOpenFakeBlock();
4436 }
4437 this.consumedEnhancedFor = false;
4438
4439 }
4440 @Override
4441 protected void consumeInvocationExpression() { // on error, a message send's error reductions will take the expression path rather than the statement path since that is a dead end.
4442 super.consumeInvocationExpression();
4443 triggerRecoveryUponLambdaClosure(this.expressionStack[this.expressionPtr], false);
4444 }
4445 @Override
4446 protected void consumeReferenceExpression(ReferenceExpression referenceExpression) {
4447 this.inReferenceExpression = false;
4448 super.consumeReferenceExpression(referenceExpression);
4449 }
4450 @Override
4451 protected void consumeOnlySynchronized() {
4452 super.consumeOnlySynchronized();
4453 this.hasUnusedModifiers = false;
4454 }
4455 @Override
4456 protected void consumeOnlyTypeArguments() {
4457 super.consumeOnlyTypeArguments();
4458 popElement(K_BINARY_OPERATOR);
4459 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_PARAMETERIZED_METHOD_INVOCATION) {
4460 popElement(K_PARAMETERIZED_METHOD_INVOCATION);
4461 pushOnElementStack(K_PARAMETERIZED_METHOD_INVOCATION, INSIDE_NAME);
4462 } else {
4463 popElement(K_PARAMETERIZED_ALLOCATION);
4464 }
4465 }
4466 @Override
4467 protected void consumeOnlyTypeArgumentsForCastExpression() {
4468 super.consumeOnlyTypeArgumentsForCastExpression();
4469 pushOnElementStack(K_PARAMETERIZED_CAST);
4470 }
4471 @Override
4472 protected void consumeOpenFakeBlock() {
4473 super.consumeOpenFakeBlock();
4474 pushOnElementStack(K_BLOCK_DELIMITER);
4475 }
4476 @Override
4477 protected void consumeOpensStatement() {
4478 super.consumeOpensStatement();
4479 popElement(K_AFTER_PACKAGE_IN_PACKAGE_VISIBILITY_STATEMENT);
4480 popElement(K_INSIDE_OPENS_STATEMENT);
4481 }
4482 @Override
4483 protected void consumeRightParen() {
4484 super.consumeRightParen();
4485 }
4486 @Override
4487 protected void consumeReferenceType1() {
4488 super.consumeReferenceType1();
4489 popElement(K_BINARY_OPERATOR);
4490 }
4491 @Override
4492 protected void consumeReferenceType2() {
4493 super.consumeReferenceType2();
4494 popElement(K_BINARY_OPERATOR);
4495 }
4496 @Override
4497 protected void consumeReferenceType3() {
4498 super.consumeReferenceType3();
4499 popElement(K_BINARY_OPERATOR);
4500 }
4501 @Override
4502 protected void consumeTypeArgumentReferenceType1() {
4503 super.consumeTypeArgumentReferenceType1();
4504 popElement(K_BINARY_OPERATOR);
4505 }
4506 @Override
4507 protected void consumeTypeArgumentReferenceType2() {
4508 super.consumeTypeArgumentReferenceType2();
4509 popElement(K_BINARY_OPERATOR);
4510 }
4511 @Override
4512 protected void consumeTypeArguments() {
4513 super.consumeTypeArguments();
4514 popElement(K_BINARY_OPERATOR);
4515 }
4516 @Override
4517 protected void consumeTypeHeaderNameWithTypeParameters() {
4518 super.consumeTypeHeaderNameWithTypeParameters();
4519
4520 TypeDeclaration typeDecl = (TypeDeclaration)this.astStack[this.astPtr];
4521 classHeaderExtendsOrImplements((typeDecl.modifiers & ClassFileConstants.AccInterface) != 0, false);
4522 }
4523 @Override
4524 protected void consumeTypeImportOnDemandDeclarationName() {
4525 super.consumeTypeImportOnDemandDeclarationName();
4526 this.pendingAnnotation = null; // the pending annotation cannot be attached to next nodes
4527 }
4528 @Override
4529 protected void consumeImportDeclaration() {
4530 super.consumeImportDeclaration();
4531 popElement(K_INSIDE_IMPORT_STATEMENT);
4532 }
4533 @Override
4534 protected void consumeTypeParameters() {
4535 super.consumeTypeParameters();
4536 popElement(K_BINARY_OPERATOR);
4537 }
4538 @Override
4539 protected void consumeTypeParameterHeader() {
4540 super.consumeTypeParameterHeader();
4541 TypeParameter typeParameter = (TypeParameter) this.genericsStack[this.genericsPtr];
4542 if(typeParameter.type != null || (typeParameter.bounds != null && typeParameter.bounds.length > 0)) return;
4543
4544 if (assistIdentifier() == null && this.currentToken == TokenNameIdentifier) { // Test below copied from CompletionScanner.getCurrentIdentifierSource()
4545 if (this.cursorLocation < this.scanner.startPosition && this.scanner.currentPosition == this.scanner.startPosition){ // fake empty identifier got issued
4546 this.pushIdentifier();
4547 } else if (this.cursorLocation+1 >= this.scanner.startPosition && this.cursorLocation < this.scanner.currentPosition){
4548 this.pushIdentifier();
4549 } else {
4550 return;
4551 }
4552 } else {
4553 return;
4554 }
4555
4556 CompletionOnKeyword1 keyword = new CompletionOnKeyword1(
4557 this.identifierStack[this.identifierPtr],
4558 this.identifierPositionStack[this.identifierPtr],
4559 Keywords.EXTENDS);
4560 typeParameter.type = keyword;
4561
4562 this.identifierPtr--;
4563 this.identifierLengthPtr--;
4564
4565 this.assistNode = typeParameter.type;
4566 this.lastCheckPoint = typeParameter.type.sourceEnd + 1;
4567 }
4568 @Override
consumeTypeParameter1()4569 protected void consumeTypeParameter1() {
4570 super.consumeTypeParameter1();
4571 popElement(K_BINARY_OPERATOR);
4572 }
4573 @Override
consumeTypeParameterWithExtends()4574 protected void consumeTypeParameterWithExtends() {
4575 super.consumeTypeParameterWithExtends();
4576 if (this.assistNode != null && this.assistNodeParent == null) {
4577 TypeParameter typeParameter = (TypeParameter) this.genericsStack[this.genericsPtr];
4578 if (typeParameter != null && typeParameter.type == this.assistNode)
4579 this.assistNodeParent = typeParameter;
4580 }
4581 popElement(K_EXTENDS_KEYWORD);
4582 }
4583 @Override
consumeTypeParameterWithExtendsAndBounds()4584 protected void consumeTypeParameterWithExtendsAndBounds() {
4585 super.consumeTypeParameterWithExtendsAndBounds();
4586 if (this.assistNode != null && this.assistNodeParent == null) {
4587 TypeParameter typeParameter = (TypeParameter) this.genericsStack[this.genericsPtr];
4588 if (typeParameter != null && typeParameter.type == this.assistNode)
4589 this.assistNodeParent = typeParameter;
4590 }
4591 popElement(K_EXTENDS_KEYWORD);
4592 }
4593 @Override
consumeTypeParameter1WithExtends()4594 protected void consumeTypeParameter1WithExtends() {
4595 super.consumeTypeParameter1WithExtends();
4596 if (this.assistNode != null && this.assistNodeParent == null) {
4597 TypeParameter typeParameter = (TypeParameter) this.genericsStack[this.genericsPtr];
4598 if (typeParameter != null && typeParameter.type == this.assistNode)
4599 this.assistNodeParent = typeParameter;
4600 }
4601 popElement(K_EXTENDS_KEYWORD);
4602 }
4603 @Override
consumeTypeParameter1WithExtendsAndBounds()4604 protected void consumeTypeParameter1WithExtendsAndBounds() {
4605 super.consumeTypeParameter1WithExtendsAndBounds();
4606 if (this.assistNode != null && this.assistNodeParent == null) {
4607 TypeParameter typeParameter = (TypeParameter) this.genericsStack[this.genericsPtr];
4608 if (typeParameter != null && typeParameter.type == this.assistNode)
4609 this.assistNodeParent = typeParameter;
4610 }
4611 popElement(K_EXTENDS_KEYWORD);
4612 }
4613 @Override
consumeUnionType()4614 protected void consumeUnionType() {
4615 pushOnElementStack(K_NEXT_TYPEREF_IS_EXCEPTION);
4616 super.consumeUnionType();
4617 popElement(K_NEXT_TYPEREF_IS_EXCEPTION);
4618 }
4619 @Override
consumeUnionTypeAsClassType()4620 protected void consumeUnionTypeAsClassType() {
4621 pushOnElementStack(K_NEXT_TYPEREF_IS_EXCEPTION);
4622 super.consumeUnionTypeAsClassType();
4623 popElement(K_NEXT_TYPEREF_IS_EXCEPTION);
4624 }
4625 @Override
consumeUsesStatement()4626 protected void consumeUsesStatement() {
4627 super.consumeUsesStatement();
4628 popElement(K_INSIDE_USES_STATEMENT);
4629 }
4630
4631 @Override
consumeWildcard()4632 protected void consumeWildcard() {
4633 super.consumeWildcard();
4634 if (assistIdentifier() == null && this.currentToken == TokenNameIdentifier) { // Test below copied from CompletionScanner.getCurrentIdentifierSource()
4635 if (this.cursorLocation < this.scanner.startPosition && this.scanner.currentPosition == this.scanner.startPosition){ // fake empty identifier got issued
4636 this.pushIdentifier();
4637 } else if (this.cursorLocation+1 >= this.scanner.startPosition && this.cursorLocation < this.scanner.currentPosition){
4638 this.pushIdentifier();
4639 } else {
4640 return;
4641 }
4642 } else {
4643 return;
4644 }
4645 Wildcard wildcard = (Wildcard) this.genericsStack[this.genericsPtr];
4646 CompletionOnKeyword1 keyword = new CompletionOnKeyword1(
4647 this.identifierStack[this.identifierPtr],
4648 this.identifierPositionStack[this.identifierPtr],
4649 new char[][]{Keywords.EXTENDS, Keywords.SUPER} );
4650 wildcard.kind = Wildcard.EXTENDS;
4651 wildcard.bound = keyword;
4652
4653 this.identifierPtr--;
4654 this.identifierLengthPtr--;
4655
4656 this.assistNode = wildcard.bound;
4657 this.lastCheckPoint = wildcard.bound.sourceEnd + 1;
4658 }
4659 @Override
consumeWildcard1()4660 protected void consumeWildcard1() {
4661 super.consumeWildcard1();
4662 popElement(K_BINARY_OPERATOR);
4663 }
4664 @Override
consumeWildcard2()4665 protected void consumeWildcard2() {
4666 super.consumeWildcard2();
4667 popElement(K_BINARY_OPERATOR);
4668 }
4669 @Override
consumeWildcard3()4670 protected void consumeWildcard3() {
4671 super.consumeWildcard3();
4672 popElement(K_BINARY_OPERATOR);
4673 }
4674 @Override
consumeWildcardBoundsExtends()4675 protected void consumeWildcardBoundsExtends() {
4676 super.consumeWildcardBoundsExtends();
4677 if (this.assistNode != null && this.assistNodeParent == null) {
4678 Wildcard wildcard = (Wildcard) this.genericsStack[this.genericsPtr];
4679 if (wildcard != null && wildcard.bound == this.assistNode)
4680 this.assistNodeParent = wildcard;
4681 }
4682 popElement(K_EXTENDS_KEYWORD);
4683 }
4684 @Override
consumeWildcardBounds1Extends()4685 protected void consumeWildcardBounds1Extends() {
4686 super.consumeWildcardBounds1Extends();
4687 if (this.assistNode != null && this.assistNodeParent == null) {
4688 Wildcard wildcard = (Wildcard) this.genericsStack[this.genericsPtr];
4689 if (wildcard != null && wildcard.bound == this.assistNode)
4690 this.assistNodeParent = wildcard;
4691 }
4692 popElement(K_EXTENDS_KEYWORD);
4693 }
4694 @Override
consumeWildcardBounds2Extends()4695 protected void consumeWildcardBounds2Extends() {
4696 super.consumeWildcardBounds2Extends();
4697 if (this.assistNode != null && this.assistNodeParent == null) {
4698 Wildcard wildcard = (Wildcard) this.genericsStack[this.genericsPtr];
4699 if (wildcard != null && wildcard.bound == this.assistNode)
4700 this.assistNodeParent = wildcard;
4701 }
4702 popElement(K_EXTENDS_KEYWORD);
4703 }
4704 @Override
consumeWildcardBounds3Extends()4705 protected void consumeWildcardBounds3Extends() {
4706 super.consumeWildcardBounds3Extends();
4707 if (this.assistNode != null && this.assistNodeParent == null) {
4708 Wildcard wildcard = (Wildcard) this.genericsStack[this.genericsPtr];
4709 if (wildcard != null && wildcard.bound == this.assistNode)
4710 this.assistNodeParent = wildcard;
4711 }
4712 popElement(K_EXTENDS_KEYWORD);
4713 }
4714 @Override
consumeUnaryExpression(int op)4715 protected void consumeUnaryExpression(int op) {
4716 super.consumeUnaryExpression(op);
4717 popElement(K_UNARY_OPERATOR);
4718
4719 if(this.expressionStack[this.expressionPtr] instanceof UnaryExpression) {
4720 UnaryExpression exp = (UnaryExpression) this.expressionStack[this.expressionPtr];
4721 if(this.assistNode != null && exp.expression == this.assistNode) {
4722 this.assistNodeParent = exp;
4723 }
4724 }
4725 }
4726 @Override
consumeUnaryExpression(int op, boolean post)4727 protected void consumeUnaryExpression(int op, boolean post) {
4728 super.consumeUnaryExpression(op, post);
4729 popElement(K_UNARY_OPERATOR);
4730
4731 if(this.expressionStack[this.expressionPtr] instanceof UnaryExpression) {
4732 UnaryExpression exp = (UnaryExpression) this.expressionStack[this.expressionPtr];
4733 if(this.assistNode != null && exp.expression == this.assistNode) {
4734 this.assistNodeParent = exp;
4735 }
4736 }
4737 }
4738 @Override
convertToMethodDeclaration(ConstructorDeclaration c, CompilationResult compilationResult)4739 public MethodDeclaration convertToMethodDeclaration(ConstructorDeclaration c, CompilationResult compilationResult) {
4740 MethodDeclaration methodDeclaration = super.convertToMethodDeclaration(c, compilationResult);
4741 if (this.sourceEnds != null) {
4742 int selectorSourceEnd = this.sourceEnds.removeKey(c);
4743 if (selectorSourceEnd != -1)
4744 this.sourceEnds.put(methodDeclaration, selectorSourceEnd);
4745 }
4746 return methodDeclaration;
4747 }
4748 @Override
createAssistPackageVisibilityReference(char[][] tokens, long[] positions)4749 public ImportReference createAssistPackageVisibilityReference(char[][] tokens, long[] positions){
4750 return new CompletionOnPackageVisibilityReference(tokens, positions);
4751 }
4752 @Override
createAssistImportReference(char[][] tokens, long[] positions, int mod)4753 public ImportReference createAssistImportReference(char[][] tokens, long[] positions, int mod){
4754 return new CompletionOnImportReference(tokens, positions, mod);
4755 }
4756 @Override
createAssistModuleReference(int index)4757 public ModuleReference createAssistModuleReference(int index) {
4758 /* retrieve identifiers subset and whole positions, the assist node positions
4759 should include the entire replaced source. */
4760 int length = this.identifierLengthStack[this.identifierLengthPtr];
4761 char[][] subset = identifierSubSet(index+1); // include the assistIdentifier
4762 this.identifierLengthPtr--;
4763 this.identifierPtr -= length;
4764 long[] positions = new long[length];
4765 System.arraycopy(
4766 this.identifierPositionStack,
4767 this.identifierPtr + 1,
4768 positions,
4769 0,
4770 length);
4771 return new CompletionOnModuleReference(subset, positions);
4772 }
4773 @Override
createAssistModuleDeclaration(CompilationResult compilationResult, char[][] tokens, long[] positions)4774 public ModuleDeclaration createAssistModuleDeclaration(CompilationResult compilationResult, char[][] tokens,
4775 long[] positions) {
4776 return new CompletionOnModuleDeclaration(compilationResult, tokens, positions);
4777 }
4778 @Override
createAssistPackageReference(char[][] tokens, long[] positions)4779 public ImportReference createAssistPackageReference(char[][] tokens, long[] positions){
4780 return new CompletionOnPackageReference(tokens, positions);
4781 }
4782 @Override
createQualifiedAssistNameReference(char[][] previousIdentifiers, char[] assistName, long[] positions)4783 public NameReference createQualifiedAssistNameReference(char[][] previousIdentifiers, char[] assistName, long[] positions){
4784 return new CompletionOnQualifiedNameReference(
4785 previousIdentifiers,
4786 assistName,
4787 positions,
4788 isInsideAttributeValue());
4789 }
checkAndCreateModuleQualifiedAssistTypeReference(char[][] previousIdentifiers, char[] assistName, long[] positions)4790 private TypeReference checkAndCreateModuleQualifiedAssistTypeReference(char[][] previousIdentifiers, char[] assistName, long[] positions) {
4791 if (isInUsesStatement()) return new CompletionOnUsesQualifiedTypeReference(previousIdentifiers, assistName, positions);
4792 if (isInProvidesStatement()) {
4793 if (isAfterWithClause()) return new CompletionOnProvidesImplementationsQualifiedTypeReference(previousIdentifiers, assistName, positions);
4794 return new CompletionOnProvidesInterfacesQualifiedTypeReference(previousIdentifiers, assistName, positions);
4795 }
4796 return new CompletionOnQualifiedTypeReference(previousIdentifiers, assistName, positions);
4797 }
4798 @Override
createQualifiedAssistTypeReference(char[][] previousIdentifiers, char[] assistName, long[] positions)4799 public TypeReference createQualifiedAssistTypeReference(char[][] previousIdentifiers, char[] assistName, long[] positions){
4800 switch (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER)) {
4801 case K_NEXT_TYPEREF_IS_EXCEPTION :
4802 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, 1) == K_BETWEEN_CATCH_AND_RIGHT_PAREN)
4803 this.isOrphanCompletionNode = true;
4804 return new CompletionOnQualifiedTypeReference(
4805 previousIdentifiers,
4806 assistName,
4807 positions,
4808 CompletionOnQualifiedTypeReference.K_EXCEPTION);
4809 case K_NEXT_TYPEREF_IS_CLASS :
4810 return new CompletionOnQualifiedTypeReference(
4811 previousIdentifiers,
4812 assistName,
4813 positions,
4814 CompletionOnQualifiedTypeReference.K_CLASS);
4815 case K_NEXT_TYPEREF_IS_INTERFACE :
4816 return new CompletionOnQualifiedTypeReference(
4817 previousIdentifiers,
4818 assistName,
4819 positions,
4820 CompletionOnQualifiedTypeReference.K_INTERFACE);
4821 default :
4822 return checkAndCreateModuleQualifiedAssistTypeReference(
4823 previousIdentifiers,
4824 assistName,
4825 positions);
4826 }
4827 }
4828 @Override
createParameterizedQualifiedAssistTypeReference(char[][] previousIdentifiers, TypeReference[][] typeArguments, char[] assistName, TypeReference[] assistTypeArguments, long[] positions)4829 public TypeReference createParameterizedQualifiedAssistTypeReference(char[][] previousIdentifiers, TypeReference[][] typeArguments, char[] assistName, TypeReference[] assistTypeArguments, long[] positions) {
4830 boolean isParameterized = false;
4831 for (int i = 0; i < typeArguments.length; i++) {
4832 if(typeArguments[i] != null) {
4833 isParameterized = true;
4834 }
4835 }
4836 if(!isParameterized) {
4837 return createQualifiedAssistTypeReference(previousIdentifiers, assistName, positions);
4838 } else {
4839 switch (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER)) {
4840 case K_NEXT_TYPEREF_IS_EXCEPTION :
4841 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, 1) == K_BETWEEN_CATCH_AND_RIGHT_PAREN)
4842 this.isOrphanCompletionNode = true;
4843 return new CompletionOnParameterizedQualifiedTypeReference(
4844 previousIdentifiers,
4845 typeArguments,
4846 assistName,
4847 positions,
4848 CompletionOnParameterizedQualifiedTypeReference.K_EXCEPTION);
4849 case K_NEXT_TYPEREF_IS_CLASS :
4850 return new CompletionOnParameterizedQualifiedTypeReference(
4851 previousIdentifiers,
4852 typeArguments,
4853 assistName,
4854 positions,
4855 CompletionOnParameterizedQualifiedTypeReference.K_CLASS);
4856 case K_NEXT_TYPEREF_IS_INTERFACE :
4857 return new CompletionOnParameterizedQualifiedTypeReference(
4858 previousIdentifiers,
4859 typeArguments,
4860 assistName,
4861 positions,
4862 CompletionOnParameterizedQualifiedTypeReference.K_INTERFACE);
4863 default :
4864 return new CompletionOnParameterizedQualifiedTypeReference(
4865 previousIdentifiers,
4866 typeArguments,
4867 assistName,
4868 positions);
4869 }
4870 }
4871 }
4872 @Override
createSingleAssistNameReference(char[] assistName, long position)4873 public NameReference createSingleAssistNameReference(char[] assistName, long position) {
4874 int kind = topKnownElementKind(COMPLETION_OR_ASSIST_PARSER);
4875 if(!isInsideMethod()) {
4876 if (isInsideFieldInitialization()) {
4877 return new CompletionOnSingleNameReference(
4878 assistName,
4879 position,
4880 new char[][]{Keywords.FALSE, Keywords.TRUE},
4881 false,
4882 isInsideAttributeValue());
4883 }
4884 return new CompletionOnSingleNameReference(assistName, position, isInsideAttributeValue());
4885 } else {
4886 boolean canBeExplicitConstructorCall = false;
4887 if((kind == K_BLOCK_DELIMITER || kind == K_LAMBDA_EXPRESSION_DELIMITER)
4888 && this.previousKind == K_BLOCK_DELIMITER
4889 && this.previousInfo == DO) {
4890 return new CompletionOnKeyword3(assistName, position, Keywords.WHILE);
4891 } else if((kind == K_BLOCK_DELIMITER || kind == K_LAMBDA_EXPRESSION_DELIMITER)
4892 && this.previousKind == K_BLOCK_DELIMITER
4893 && this.previousInfo == TRY) {
4894 return new CompletionOnKeyword3(assistName, position, new char[][]{Keywords.CATCH, Keywords.FINALLY}, true);
4895 } else if(kind == K_BLOCK_DELIMITER
4896 && topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == SWITCH) {
4897 return new CompletionOnKeyword3(assistName, position, new char[][]{Keywords.CASE, Keywords.DEFAULT}, false);
4898 } else {
4899 char[][] keywords = new char[Keywords.COUNT][];
4900 int count = 0;
4901
4902 if((this.lastModifiers & ClassFileConstants.AccStatic) == 0) {
4903 keywords[count++]= Keywords.SUPER;
4904 keywords[count++]= Keywords.THIS;
4905 }
4906 keywords[count++]= Keywords.NEW;
4907 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=269493: Keywords are not proposed in a for
4908 // loop without block. Completion while at K_CONTROL_STATEMENT_DELIMITER case needs to handled
4909 // similar to the K_BLOCK_DELIMITER with minor differences.
4910 if(kind == K_BLOCK_DELIMITER || kind == K_CONTROL_STATEMENT_DELIMITER || kind == K_LAMBDA_EXPRESSION_DELIMITER
4911 || kind == K_SWITCH_EXPRESSION_DELIMITTER) {
4912 if(this.canBeExplicitConstructor == YES) {
4913 canBeExplicitConstructorCall = true;
4914 }
4915 if (this.options.complianceLevel >= ClassFileConstants.JDK1_4) {
4916 keywords[count++]= Keywords.ASSERT;
4917 }
4918 keywords[count++]= Keywords.DO;
4919 keywords[count++]= Keywords.FOR;
4920 keywords[count++]= Keywords.IF;
4921 keywords[count++]= Keywords.RETURN;
4922 keywords[count++]= Keywords.SWITCH;
4923 keywords[count++]= Keywords.SYNCHRONIZED;
4924 keywords[count++]= Keywords.THROW;
4925 keywords[count++]= Keywords.TRY;
4926 keywords[count++]= Keywords.WHILE;
4927
4928 keywords[count++]= Keywords.FINAL;
4929 keywords[count++]= Keywords.CLASS;
4930 if (this.options.complianceLevel >= ClassFileConstants.JDK10) {
4931 keywords[count++]= Keywords.VAR;
4932 }
4933
4934 if(this.previousKind == K_BLOCK_DELIMITER) {
4935 switch (this.previousInfo) {
4936 case IF :
4937 keywords[count++]= Keywords.ELSE;
4938 break;
4939 case CATCH :
4940 keywords[count++]= Keywords.CATCH;
4941 keywords[count++]= Keywords.FINALLY;
4942 break;
4943 }
4944 } else if(this.previousKind == K_CONTROL_STATEMENT_DELIMITER && this.previousInfo == IF) {
4945 keywords[count++]= Keywords.ELSE;
4946 }
4947 if(isInsideLoop()) {
4948 keywords[count++]= Keywords.CONTINUE;
4949 }
4950 if(isInsideBreakable()) {
4951 keywords[count++]= Keywords.BREAK;
4952 }
4953 if(isInsideSwitch()) {
4954 keywords[count++]= Keywords.YIELD;
4955 }
4956 } else if (kind == K_BETWEEN_FOR_AND_RIGHT_PAREN) {
4957 if (this.options.complianceLevel >= ClassFileConstants.JDK10) {
4958 keywords[count++]= Keywords.VAR;
4959 }
4960 } else if(kind != K_BETWEEN_CASE_AND_COLON && kind != K_BETWEEN_DEFAULT_AND_COLON) {
4961 if (kind == K_LOCAL_INITIALIZER_DELIMITER && this.options.complianceLevel >= ClassFileConstants.JDK11) {
4962 keywords[count++]= Keywords.VAR;
4963 }
4964 if (kind == K_SELECTOR_QUALIFIER && this.options.complianceLevel >= ClassFileConstants.JDK12) {
4965 keywords[count++] = Keywords.SWITCH;
4966 }
4967 keywords[count++]= Keywords.TRUE;
4968 keywords[count++]= Keywords.FALSE;
4969 keywords[count++]= Keywords.NULL;
4970 if (kind == K_YIELD_KEYWORD) {
4971 keywords[count++]= Keywords.YIELD;
4972 }
4973 if(kind == K_SWITCH_LABEL) {
4974 if(topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) != DEFAULT) {
4975 keywords[count++]= Keywords.DEFAULT;
4976 }
4977 keywords[count++]= Keywords.BREAK;
4978 keywords[count++]= Keywords.CASE;
4979 keywords[count++]= Keywords.YIELD;
4980 if (this.options.complianceLevel >= ClassFileConstants.JDK1_4) {
4981 keywords[count++]= Keywords.ASSERT;
4982 }
4983 keywords[count++]= Keywords.DO;
4984 keywords[count++]= Keywords.FOR;
4985 keywords[count++]= Keywords.IF;
4986 keywords[count++]= Keywords.RETURN;
4987 keywords[count++]= Keywords.SWITCH;
4988 keywords[count++]= Keywords.SYNCHRONIZED;
4989 keywords[count++]= Keywords.THROW;
4990 keywords[count++]= Keywords.TRY;
4991 keywords[count++]= Keywords.WHILE;
4992
4993 keywords[count++]= Keywords.FINAL;
4994 keywords[count++]= Keywords.CLASS;
4995
4996 if (this.options.complianceLevel >= ClassFileConstants.JDK10) {
4997 keywords[count++]= Keywords.VAR;
4998 }
4999 if(isInsideLoop()) {
5000 keywords[count++]= Keywords.CONTINUE;
5001 }
5002 }
5003 }
5004 System.arraycopy(keywords, 0 , keywords = new char[count][], 0, count);
5005
5006 return new CompletionOnSingleNameReference(assistName, position, keywords, canBeExplicitConstructorCall, isInsideAttributeValue());
5007 }
5008 }
5009 }
checkAndCreateModuleSingleAssistTypeReference(char[] assistName, long position)5010 private TypeReference checkAndCreateModuleSingleAssistTypeReference(char[] assistName, long position) {
5011 if (isInUsesStatement()) return new CompletionOnUsesSingleTypeReference(assistName, position);
5012 if (isInProvidesStatement()) {
5013 if (isAfterWithClause()) return new CompletionOnProvidesImplementationsSingleTypeReference(assistName, position);
5014 return new CompletionOnProvidesInterfacesSingleTypeReference(assistName, position);
5015 }
5016 return new CompletionOnSingleTypeReference(assistName,position);
5017 }
5018 @Override
createSingleAssistTypeReference(char[] assistName, long position)5019 public TypeReference createSingleAssistTypeReference(char[] assistName, long position) {
5020 switch (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER)) {
5021 case K_NEXT_TYPEREF_IS_EXCEPTION :
5022 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER, 1) == K_BETWEEN_CATCH_AND_RIGHT_PAREN)
5023 this.isOrphanCompletionNode = true;
5024 return new CompletionOnSingleTypeReference(assistName, position, CompletionOnSingleTypeReference.K_EXCEPTION) ;
5025 case K_NEXT_TYPEREF_IS_CLASS :
5026 return new CompletionOnSingleTypeReference(assistName, position, CompletionOnSingleTypeReference.K_CLASS);
5027 case K_NEXT_TYPEREF_IS_INTERFACE :
5028 return new CompletionOnSingleTypeReference(assistName, position, CompletionOnSingleTypeReference.K_INTERFACE);
5029 default :
5030 return checkAndCreateModuleSingleAssistTypeReference(assistName, position);
5031 }
5032 }
5033 @Override
createParameterizedSingleAssistTypeReference(TypeReference[] typeArguments, char[] assistName, long position)5034 public TypeReference createParameterizedSingleAssistTypeReference(TypeReference[] typeArguments, char[] assistName, long position) {
5035 return createSingleAssistTypeReference(assistName, position);
5036 }
5037 @Override
createStringLiteral(char[] token, int start, int end, int lineNumber)5038 protected StringLiteral createStringLiteral(char[] token, int start, int end, int lineNumber) {
5039 if (start <= this.cursorLocation && this.cursorLocation <= end){
5040 char[] source = this.scanner.source;
5041
5042 int contentStart = start;
5043 int contentEnd = end;
5044
5045 // " could be as unicode \u0022
5046 int pos = contentStart;
5047 if(source[pos] == '\"') {
5048 contentStart = pos + 1;
5049 } else if(source[pos] == '\\' && source[pos+1] == 'u') {
5050 pos += 2;
5051 while (source[pos] == 'u') {
5052 pos++;
5053 }
5054 if(source[pos] == 0 && source[pos + 1] == 0 && source[pos + 2] == 2 && source[pos + 3] == 2) {
5055 contentStart = pos + 4;
5056 }
5057 }
5058
5059 pos = contentEnd;
5060 if(source[pos] == '\"') {
5061 contentEnd = pos - 1;
5062 } else if(source.length > 5 && source[pos-4] == 'u') {
5063 if(source[pos - 3] == 0 && source[pos - 2] == 0 && source[pos - 1] == 2 && source[pos] == 2) {
5064 pos -= 5;
5065 while (pos > -1 && source[pos] == 'u') {
5066 pos--;
5067 }
5068 if(pos > -1 && source[pos] == '\\') {
5069 contentEnd = pos - 1;
5070 }
5071 }
5072 }
5073
5074 if(contentEnd < start) {
5075 contentEnd = end;
5076 }
5077
5078 if(this.cursorLocation != end || end == contentEnd) {
5079 CompletionOnStringLiteral stringLiteral = new CompletionOnStringLiteral(
5080 token,
5081 start,
5082 end,
5083 contentStart,
5084 contentEnd,
5085 lineNumber);
5086
5087 this.assistNode = stringLiteral;
5088 this.restartRecovery = true;
5089 this.lastCheckPoint = end;
5090
5091 return stringLiteral;
5092 }
5093 }
5094 return super.createStringLiteral(token, start, end, lineNumber);
5095 }
5096 @Override
augmentTypeWithAdditionalDimensions(TypeReference typeRef, int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs)5097 protected TypeReference augmentTypeWithAdditionalDimensions(TypeReference typeRef, int additionalDimensions, Annotation[][] additionalAnnotations, boolean isVarargs) {
5098 if (this.assistNode == typeRef) {
5099 return typeRef;
5100 }
5101 TypeReference result = super.augmentTypeWithAdditionalDimensions(typeRef, additionalDimensions, additionalAnnotations, isVarargs);
5102 if (this.assistNodeParent == typeRef) {
5103 this.assistNodeParent = result;
5104 }
5105 return result;
5106 }
dietParse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int cursorLoc)5107 public CompilationUnitDeclaration dietParse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int cursorLoc) {
5108
5109 this.cursorLocation = cursorLoc;
5110 CompletionScanner completionScanner = (CompletionScanner)this.scanner;
5111 completionScanner.completionIdentifier = null;
5112 completionScanner.cursorLocation = cursorLoc;
5113 return this.dietParse(sourceUnit, compilationResult);
5114 }
5115 /*
5116 * Flush parser/scanner state regarding to code assist
5117 */
5118 @Override
flushAssistState()5119 public void flushAssistState() {
5120
5121 super.flushAssistState();
5122 this.isOrphanCompletionNode = false;
5123 this.isAlreadyAttached = false;
5124 this.assistNodeParent = null;
5125 CompletionScanner completionScanner = (CompletionScanner)this.scanner;
5126 completionScanner.completedIdentifierStart = 0;
5127 completionScanner.completedIdentifierEnd = -1;
5128 }
5129
5130 @Override
getTypeReferenceForGenericType(int dim, int identifierLength, int numberOfIdentifiers)5131 protected TypeReference getTypeReferenceForGenericType(int dim, int identifierLength, int numberOfIdentifiers) {
5132 TypeReference ref = super.getTypeReferenceForGenericType(dim, identifierLength, numberOfIdentifiers);
5133 // in completion case we might have encountered the assist node before really parsing
5134 // the complete class instance creation, and so a separate check for diamond is needed here.
5135 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=346454
5136 checkForDiamond(ref);
5137 if(this.assistNode != null) {
5138 if (identifierLength == 1 && numberOfIdentifiers == 1) {
5139 ParameterizedSingleTypeReference singleRef = (ParameterizedSingleTypeReference) ref;
5140 TypeReference[] typeArguments = singleRef.typeArguments;
5141 for (int i = 0; i < typeArguments.length; i++) {
5142 if(typeArguments[i] == this.assistNode) {
5143 this.assistNodeParent = ref;
5144 return ref;
5145 }
5146 }
5147 } else {
5148 ParameterizedQualifiedTypeReference qualifiedRef = (ParameterizedQualifiedTypeReference) ref;
5149 TypeReference[][] typeArguments = qualifiedRef.typeArguments;
5150 for (int i = 0; i < typeArguments.length; i++) {
5151 if(typeArguments[i] != null) {
5152 for (int j = 0; j < typeArguments[i].length; j++) {
5153 if(typeArguments[i][j] == this.assistNode) {
5154 this.assistNodeParent = ref;
5155 return ref;
5156 }
5157 }
5158 }
5159 }
5160
5161 }
5162 }
5163
5164 return ref;
5165 }
5166 @Override
getUnspecifiedReference(boolean rejectTypeAnnotations)5167 protected NameReference getUnspecifiedReference(boolean rejectTypeAnnotations) {
5168 NameReference nameReference = super.getUnspecifiedReference(rejectTypeAnnotations);
5169 if (this.record) {
5170 recordReference(nameReference);
5171 }
5172 return nameReference;
5173 }
5174 @Override
consumePostfixExpression()5175 protected void consumePostfixExpression() {
5176 // PostfixExpression ::= Name
5177 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) != K_YIELD_KEYWORD) {
5178 super.consumePostfixExpression();
5179 }
5180 }
5181 @Override
getUnspecifiedReferenceOptimized()5182 protected NameReference getUnspecifiedReferenceOptimized() {
5183 if (this.identifierLengthStack[this.identifierLengthPtr] > 1) { // reducing a qualified name
5184 // potential receiver is being poped, so reset potential receiver
5185 this.invocationType = NO_RECEIVER;
5186 this.qualifier = -1;
5187 }
5188 NameReference nameReference = super.getUnspecifiedReferenceOptimized();
5189 if (this.record) {
5190 recordReference(nameReference);
5191 }
5192 return nameReference;
5193 }
isAlreadyPotentialName(int identifierStart)5194 private boolean isAlreadyPotentialName(int identifierStart) {
5195 if (this.potentialVariableNamesPtr < 0) return false;
5196
5197 return identifierStart <= this.potentialVariableNameEnds[this.potentialVariableNamesPtr];
5198 }
5199 @Override
indexOfAssistIdentifier(boolean useGenericsStack)5200 protected int indexOfAssistIdentifier(boolean useGenericsStack) {
5201 if (this.record) return -1; // when names are recorded there is no assist identifier
5202 return super.indexOfAssistIdentifier(useGenericsStack);
5203 }
5204 @Override
initialize()5205 public void initialize() {
5206 super.initialize();
5207 this.labelPtr = -1;
5208 initializeForBlockStatements();
5209 }
5210 @Override
initialize(boolean parsingCompilationUnit)5211 public void initialize(boolean parsingCompilationUnit) {
5212 super.initialize(parsingCompilationUnit);
5213 this.labelPtr = -1;
5214 initializeForBlockStatements();
5215 }
5216 @Override
copyState(Parser from)5217 public void copyState(Parser from) {
5218
5219 super.copyState(from);
5220
5221 CompletionParser parser = (CompletionParser) from;
5222
5223 this.invocationType = parser.invocationType;
5224 this.qualifier = parser.qualifier;
5225 this.inReferenceExpression = parser.inReferenceExpression;
5226 this.hasUnusedModifiers = parser.hasUnusedModifiers;
5227 this.canBeExplicitConstructor = parser.canBeExplicitConstructor;
5228 }
5229 /*
5230 * Initializes the state of the parser that is about to go for BlockStatements.
5231 */
initializeForBlockStatements()5232 private void initializeForBlockStatements() {
5233 this.previousToken = -1;
5234 this.previousIdentifierPtr = -1;
5235 this.invocationType = NO_RECEIVER;
5236 this.qualifier = -1;
5237 popUntilElement(K_SWITCH_LABEL);
5238 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) != K_SWITCH_LABEL) {
5239 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_ARRAY_INITIALIZER) {
5240 // if recovery is taking place in an array initializer, we should prevent popping
5241 // up to the enclosing block until the array initializer is properly closed
5242 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=249704
5243 popUntilElement(K_ARRAY_INITIALIZER);
5244 } else {
5245 popUntilElement(K_BLOCK_DELIMITER);
5246 }
5247 }
5248 }
5249 @Override
initializeScanner()5250 public void initializeScanner(){
5251 this.scanner = new CompletionScanner(this.options.sourceLevel, this.options.enablePreviewFeatures);
5252 }
5253 /**
5254 * Returns whether the completion is just after an array type
5255 * e.g. String[].[cursor]
5256 */
isAfterArrayType()5257 private boolean isAfterArrayType() {
5258 // TBD: The following relies on the fact that array dimensions are small: it says that if the
5259 // top of the intStack is less than 11, then it must be a dimension
5260 // (smallest position of array type in a compilation unit is 11 as in "class X{Y[]")
5261 if ((this.intPtr > -1) && (this.intStack[this.intPtr] < 11)) {
5262 return true;
5263 }
5264 return false;
5265 }
isEmptyNameCompletion()5266 private boolean isEmptyNameCompletion() {
5267 return
5268 this.assistNode != null &&
5269 this.assistNode instanceof CompletionOnSingleNameReference &&
5270 (((CompletionOnSingleNameReference)this.assistNode).token.length == 0);
5271 }
isInsideAnnotation()5272 protected boolean isInsideAnnotation() {
5273 int i = this.elementPtr;
5274 while(i > -1) {
5275 if(this.elementKindStack[i] == K_BETWEEN_ANNOTATION_NAME_AND_RPAREN)
5276 return true;
5277 i--;
5278 }
5279 return false;
5280 }
5281
isInsideSwitch()5282 protected boolean isInsideSwitch(){
5283 int i = this.elementPtr;
5284 while(i > -1) {
5285 switch (this.elementKindStack[i]) {
5286 case K_SWITCH_LABEL : return true;
5287 }
5288 i--;
5289 }
5290 return false;
5291 }
isInsideBreakable()5292 protected boolean isInsideBreakable(){
5293 int i = this.elementPtr;
5294 while(i > -1) {
5295 switch (this.elementKindStack[i]) {
5296 case K_TYPE_DELIMITER : return false;
5297 case K_METHOD_DELIMITER : return false;
5298 case K_FIELD_INITIALIZER_DELIMITER : return false;
5299 case K_SWITCH_LABEL : return true;
5300 case K_BLOCK_DELIMITER :
5301 case K_CONTROL_STATEMENT_DELIMITER:
5302 switch(this.elementInfoStack[i]) {
5303 case FOR :
5304 case DO :
5305 case WHILE :
5306 return true;
5307 }
5308 }
5309 i--;
5310 }
5311 return false;
5312 }
isInsideLoop()5313 protected boolean isInsideLoop(){
5314 int i = this.elementPtr;
5315 while(i > -1) {
5316 switch (this.elementKindStack[i]) {
5317 case K_TYPE_DELIMITER : return false;
5318 case K_METHOD_DELIMITER : return false;
5319 case K_FIELD_INITIALIZER_DELIMITER : return false;
5320 case K_BLOCK_DELIMITER :
5321 case K_CONTROL_STATEMENT_DELIMITER:
5322 switch(this.elementInfoStack[i]) {
5323 case FOR :
5324 case DO :
5325 case WHILE :
5326 return true;
5327 }
5328 }
5329 i--;
5330 }
5331 return false;
5332 }
isInsideReturn()5333 protected boolean isInsideReturn(){
5334 int i = this.elementPtr;
5335 while(i > -1) {
5336 switch (this.elementKindStack[i]) {
5337 case K_TYPE_DELIMITER : return false;
5338 case K_METHOD_DELIMITER : return false;
5339 case K_FIELD_INITIALIZER_DELIMITER : return false;
5340 case K_BLOCK_DELIMITER : return false;
5341 case K_CONTROL_STATEMENT_DELIMITER: return false; // FWIW
5342 case K_INSIDE_RETURN_STATEMENT : return true;
5343 }
5344 i--;
5345 }
5346 return false;
5347 }
5348 @Override
newReferenceExpression()5349 public ReferenceExpression newReferenceExpression() {
5350 char[] selector = this.identifierStack[this.identifierPtr];
5351 if (selector != assistIdentifier()){
5352 return super.newReferenceExpression();
5353 }
5354 ReferenceExpression referenceExpression = new CompletionOnReferenceExpressionName(this.scanner);
5355 this.assistNode = referenceExpression;
5356 return referenceExpression;
5357 }
parse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int cursorLoc)5358 public CompilationUnitDeclaration parse(ICompilationUnit sourceUnit, CompilationResult compilationResult, int cursorLoc) {
5359
5360 this.cursorLocation = cursorLoc;
5361 CompletionScanner completionScanner = (CompletionScanner)this.scanner;
5362 completionScanner.completionIdentifier = null;
5363 completionScanner.cursorLocation = cursorLoc;
5364 return this.parse(sourceUnit, compilationResult);
5365 }
5366 @Override
parseBlockStatements( ConstructorDeclaration cd, CompilationUnitDeclaration unit)5367 public void parseBlockStatements(
5368 ConstructorDeclaration cd,
5369 CompilationUnitDeclaration unit) {
5370 this.canBeExplicitConstructor = 1;
5371 super.parseBlockStatements(cd, unit);
5372 }
parseSomeStatements(int start, int end, int fakeBlocksCount, CompilationUnitDeclaration unit)5373 public MethodDeclaration parseSomeStatements(int start, int end, int fakeBlocksCount, CompilationUnitDeclaration unit) {
5374 this.methodRecoveryActivated = true;
5375
5376 initialize();
5377
5378 // simulate goForMethodBody except that we don't want to balance brackets because they are not going to be balanced
5379 goForBlockStatementsopt();
5380
5381 MethodDeclaration fakeMethod = new MethodDeclaration(unit.compilationResult());
5382 fakeMethod.selector = FAKE_METHOD_NAME;
5383 fakeMethod.bodyStart = start;
5384 fakeMethod.bodyEnd = end;
5385 fakeMethod.declarationSourceStart = start;
5386 fakeMethod.declarationSourceEnd = end;
5387 fakeMethod.sourceStart = start;
5388 fakeMethod.sourceEnd = start; //fake method must ignore the method header
5389
5390 this.referenceContext = fakeMethod;
5391 this.compilationUnit = unit;
5392
5393 this.diet = false;
5394 this.restartRecovery = true;
5395
5396 this.scanner.resetTo(start, end);
5397 consumeNestedMethod();
5398 for (int i = 0; i < fakeBlocksCount; i++) {
5399 consumeOpenFakeBlock();
5400 }
5401 try {
5402 parse();
5403 } catch (AbortCompilation ex) {
5404 this.lastAct = ERROR_ACTION;
5405 } finally {
5406 this.nestedMethod[this.nestedType]--;
5407 }
5408 if (!this.hasError) {
5409 int length;
5410 if (this.astLengthPtr > -1 && (length = this.astLengthStack[this.astLengthPtr--]) != 0) {
5411 System.arraycopy(
5412 this.astStack,
5413 (this.astPtr -= length) + 1,
5414 fakeMethod.statements = new Statement[length],
5415 0,
5416 length);
5417 }
5418 }
5419
5420 return fakeMethod;
5421 }
popUntilCompletedAnnotationIfNecessary()5422 protected void popUntilCompletedAnnotationIfNecessary() {
5423 if(this.elementPtr < 0) return;
5424
5425 int i = this.elementPtr;
5426 while(i > -1 &&
5427 (this.elementKindStack[i] != K_BETWEEN_ANNOTATION_NAME_AND_RPAREN ||
5428 (this.elementInfoStack[i] & ANNOTATION_NAME_COMPLETION) == 0)) {
5429 i--;
5430 }
5431
5432 if(i >= 0) {
5433 this.previousKind = this.elementKindStack[i];
5434 this.previousInfo = this.elementInfoStack[i];
5435 this.previousObjectInfo = this.elementObjectInfoStack[i];
5436
5437 for (int j = i; j <= this.elementPtr; j++) {
5438 this.elementObjectInfoStack[j] = null;
5439 }
5440
5441 this.elementPtr = i - 1;
5442 }
5443 }
5444 /*
5445 * Prepares the state of the parser to go for BlockStatements.
5446 */
5447 @Override
prepareForBlockStatements()5448 protected void prepareForBlockStatements() {
5449 this.nestedMethod[this.nestedType = 0] = 1;
5450 this.variablesCounter[this.nestedType] = 0;
5451 this.realBlockStack[this.realBlockPtr = 1] = 0;
5452
5453 initializeForBlockStatements();
5454 }
pushOnLabelStack(char[] label)5455 protected void pushOnLabelStack(char[] label){
5456 if (this.labelPtr < -1) return;
5457
5458 int stackLength = this.labelStack.length;
5459 if (++this.labelPtr >= stackLength) {
5460 System.arraycopy(
5461 this.labelStack, 0,
5462 this.labelStack = new char[stackLength + LabelStackIncrement][], 0,
5463 stackLength);
5464 }
5465 this.labelStack[this.labelPtr] = label;
5466 }
5467 /**
5468 * Creates a completion on member access node and push it
5469 * on the expression stack.
5470 */
pushCompletionOnMemberAccessOnExpressionStack(boolean isSuperAccess)5471 private void pushCompletionOnMemberAccessOnExpressionStack(boolean isSuperAccess) {
5472 char[] source = this.identifierStack[this.identifierPtr];
5473 long pos = this.identifierPositionStack[this.identifierPtr--];
5474 CompletionOnMemberAccess fr = new CompletionOnMemberAccess(source, pos, isInsideAnnotation());
5475 this.assistNode = fr;
5476 this.lastCheckPoint = fr.sourceEnd + 1;
5477 this.identifierLengthPtr--;
5478 if (isSuperAccess) { //considerates the fieldReference beginning at the 'super' ....
5479 fr.sourceStart = this.intStack[this.intPtr--];
5480 fr.receiver = new SuperReference(fr.sourceStart, this.endPosition);
5481 pushOnExpressionStack(fr);
5482 } else { //optimize push/pop
5483 if ((fr.receiver = this.expressionStack[this.expressionPtr]).isThis()) { //fieldreference begins at the this
5484 fr.sourceStart = fr.receiver.sourceStart;
5485 }
5486 this.expressionStack[this.expressionPtr] = fr;
5487 }
5488 }
recordReference(NameReference nameReference)5489 private void recordReference(NameReference nameReference) {
5490 if (!this.skipRecord &&
5491 this.recordFrom <= nameReference.sourceStart &&
5492 nameReference.sourceEnd <= this.recordTo &&
5493 !isAlreadyPotentialName(nameReference.sourceStart)) {
5494 char[] token;
5495 if (nameReference instanceof SingleNameReference) {
5496 token = ((SingleNameReference) nameReference).token;
5497 } else {
5498 token = ((QualifiedNameReference) nameReference).tokens[0];
5499 }
5500
5501 // Most of the time a name which start with an uppercase is a type name.
5502 // As we don't want to resolve names to avoid to slow down performances then this name will be ignored
5503 if (Character.isUpperCase(token[0])) return;
5504
5505 addPotentialName(token, nameReference.sourceStart, nameReference.sourceEnd);
5506 }
5507 }
5508 @Override
recoveryExitFromVariable()5509 public void recoveryExitFromVariable() {
5510 if(this.currentElement != null && this.currentElement instanceof RecoveredLocalVariable) {
5511 RecoveredElement oldElement = this.currentElement;
5512 super.recoveryExitFromVariable();
5513 if(oldElement != this.currentElement) {
5514 popElement(K_LOCAL_INITIALIZER_DELIMITER);
5515 }
5516 } else if(this.currentElement != null && this.currentElement instanceof RecoveredField) {
5517 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=292087
5518 // To make sure the array initializer is popped when the focus is shifted to the parent
5519 // in case we're restarting recovery inside an array initializer
5520 RecoveredElement oldElement = this.currentElement;
5521 super.recoveryExitFromVariable();
5522 if(oldElement != this.currentElement) {
5523 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_ARRAY_INITIALIZER) {
5524 popElement(K_ARRAY_INITIALIZER);
5525 popElement(K_FIELD_INITIALIZER_DELIMITER);
5526 }
5527 }
5528 } else {
5529 super.recoveryExitFromVariable();
5530 }
5531 }
5532 @Override
recoveryTokenCheck()5533 public void recoveryTokenCheck() {
5534 RecoveredElement oldElement = this.currentElement;
5535 switch (this.currentToken) {
5536 case TokenNameLBRACE :
5537 if(!this.ignoreNextOpeningBrace) {
5538 this.pendingAnnotation = null; // the pending annotation cannot be attached to next nodes
5539 }
5540 super.recoveryTokenCheck();
5541 break;
5542 case TokenNameRBRACE :
5543 super.recoveryTokenCheck();
5544 if(this.currentElement != oldElement && oldElement instanceof RecoveredBlock) {
5545 if (topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_ARRAY_INITIALIZER) {
5546 // When inside an array initializer, we should not prematurely pop the enclosing block
5547 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=249704
5548 popElement(K_ARRAY_INITIALIZER);
5549 } else {
5550 popElement(K_BLOCK_DELIMITER);
5551 }
5552 }
5553 break;
5554 case TokenNamecase :
5555 super.recoveryTokenCheck();
5556 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BLOCK_DELIMITER
5557 && topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == SWITCH) {
5558 pushOnElementStack(K_SWITCH_LABEL);
5559 }
5560 break;
5561 case TokenNamedefault :
5562 super.recoveryTokenCheck();
5563 if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_BLOCK_DELIMITER
5564 && topKnownElementInfo(COMPLETION_OR_ASSIST_PARSER) == SWITCH) {
5565 pushOnElementStack(K_SWITCH_LABEL, DEFAULT);
5566 } else if(topKnownElementKind(COMPLETION_OR_ASSIST_PARSER) == K_SWITCH_LABEL) {
5567 popElement(K_SWITCH_LABEL);
5568 pushOnElementStack(K_SWITCH_LABEL, DEFAULT);
5569 }
5570 break;
5571 default :
5572 super.recoveryTokenCheck();
5573 break;
5574 }
5575 }
5576
5577 @Override
createSnapShotParser()5578 protected CompletionParser createSnapShotParser() {
5579 return new CompletionParser(this.problemReporter, this.storeSourceEnds);
5580 }
5581 /*
5582 * Reset internal state after completion is over
5583 */
5584
5585 @Override
reset()5586 public void reset() {
5587 super.reset();
5588 this.cursorLocation = 0;
5589 if (this.storeSourceEnds) {
5590 this.sourceEnds = new HashtableOfObjectToInt();
5591 }
5592 }
5593 /*
5594 * Reset internal state after completion is over
5595 */
5596
resetAfterCompletion()5597 public void resetAfterCompletion() {
5598 this.cursorLocation = 0;
5599 flushAssistState();
5600 }
5601 @Override
restoreAssistParser(Object parserState)5602 public void restoreAssistParser(Object parserState) {
5603 SavedState state = (SavedState) parserState;
5604
5605 CompletionScanner completionScanner = (CompletionScanner)this.scanner;
5606
5607 this.cursorLocation = state.parserCursorLocation;
5608 completionScanner.cursorLocation = state.scannerCursorLocation;
5609 this.assistNodeParent = state.assistNodeParent;
5610 }
5611 @Override
resumeOnSyntaxError()5612 protected int resumeOnSyntaxError() {
5613 if (this.monitor != null) {
5614 if (++this.resumeOnSyntaxError > 100) {
5615 this.resumeOnSyntaxError = 0;
5616 if (this.monitor.isCanceled())
5617 return HALT;
5618 }
5619 }
5620 return super.resumeOnSyntaxError();
5621 }
5622 /*
5623 * Reset context so as to resume to regular parse loop
5624 * If unable to reset for resuming, answers false.
5625 *
5626 * Move checkpoint location, reset internal stacks and
5627 * decide which grammar goal is activated.
5628 */
5629 @Override
resumeAfterRecovery()5630 protected int resumeAfterRecovery() {
5631 this.hasUnusedModifiers = false;
5632 if (this.assistNode != null) {
5633
5634 if (requireExtendedRecovery()) {
5635 if (this.unstackedAct != ERROR_ACTION) {
5636 return RESUME;
5637 }
5638 return super.resumeAfterRecovery();
5639 }
5640
5641 /* if reached [eof] inside method body, but still inside nested type,
5642 or inside a field initializer, should continue in diet mode until
5643 the end of the method body or compilation unit */
5644 if ((this.scanner.eofPosition >= this.cursorLocation+1)
5645 && (!(this.referenceContext instanceof CompilationUnitDeclaration)
5646 || isIndirectlyInsideFieldInitialization()
5647 || this.assistNodeParent instanceof FieldDeclaration && !(this.assistNodeParent instanceof Initializer))) {
5648
5649 /* disabled since does not handle possible field/message refs, that is, Obj[ASSIST HERE]ect.registerNatives()
5650 // consume extra tokens which were part of the qualified reference
5651 // so that the replaced source comprises them as well
5652 if (this.assistNode instanceof NameReference){
5653 int oldEof = scanner.eofPosition;
5654 scanner.eofPosition = currentElement.topElement().sourceEnd()+1;
5655 scanner.currentPosition = this.cursorLocation+1;
5656 int token = -1;
5657 try {
5658 do {
5659 // first token might not have to be a dot
5660 if (token >= 0 || !this.completionBehindDot){
5661 if ((token = scanner.getNextToken()) != TokenNameDOT) break;
5662 }
5663 if ((token = scanner.getNextToken()) != TokenNameIdentifier) break;
5664 this.assistNode.sourceEnd = scanner.currentPosition - 1;
5665 } while (token != TokenNameEOF);
5666 } catch (InvalidInputException e){
5667 } finally {
5668 scanner.eofPosition = oldEof;
5669 }
5670 }
5671 */
5672
5673 /* restart in diet mode for finding sibling constructs */
5674 if (this.currentElement instanceof RecoveredType
5675 || this.currentElement.enclosingType() != null){
5676
5677 this.pendingAnnotation = null;
5678
5679 if(this.lastCheckPoint <= this.assistNode.sourceEnd) {
5680 this.lastCheckPoint = this.assistNode.sourceEnd+1;
5681 }
5682 int end = this.currentElement.topElement().sourceEnd();
5683 this.scanner.eofPosition = end < Integer.MAX_VALUE ? end + 1 : end;
5684 } else {
5685 resetStacks();
5686 return HALT;
5687 }
5688 }
5689 }
5690 return super.resumeAfterRecovery();
5691 }
5692 @Override
5693 public void setAssistIdentifier(char[] assistIdent){
5694 ((CompletionScanner)this.scanner).completionIdentifier = assistIdent;
5695 }
5696
5697 @Override
5698 protected void shouldStackAssistNode() {
5699 this.shouldStackAssistNode = true;
5700 }
5701
5702 @Override
5703 protected boolean assistNodeNeedsStacking() {
5704 return this.shouldStackAssistNode;
5705 }
5706
5707 @Override
5708 public String toString() {
5709 StringBuffer buffer = new StringBuffer();
5710 buffer.append("elementKindStack : int[] = {"); //$NON-NLS-1$
5711 for (int i = 0; i <= this.elementPtr; i++) {
5712 buffer.append(String.valueOf(this.elementKindStack[i])).append(',');
5713 }
5714 buffer.append("}\n"); //$NON-NLS-1$
5715 buffer.append("elementInfoStack : int[] = {"); //$NON-NLS-1$
5716 for (int i = 0; i <= this.elementPtr; i++) {
5717 buffer.append(String.valueOf(this.elementInfoStack[i])).append(',');
5718 }
5719 buffer.append("}\n"); //$NON-NLS-1$
5720 buffer.append(super.toString());
5721 return String.valueOf(buffer);
5722 }
5723
5724 /*
5725 * Update recovery state based on current parser/scanner state
5726 */
5727 @Override
5728 protected void updateRecoveryState() {
5729
5730 /* expose parser state to recovery state */
5731 this.currentElement.updateFromParserState();
5732
5733 // completionIdentifierCheck && attachOrphanCompletionNode pops various stacks to construct astNodeParent and enclosingNode. This does not gel well with extended recovery.
5734 AssistParser parser = null;
5735 if (lastIndexOfElement(K_LAMBDA_EXPRESSION_DELIMITER) >= 0) {
5736 parser = createSnapShotParser();
5737 parser.copyState(this);
5738 }
5739
5740 /* may be able to retrieve completionNode as an orphan, and then attach it */
5741 completionIdentifierCheck();
5742 attachOrphanCompletionNode();
5743 if (parser != null)
5744 this.copyState(parser);
5745
5746 // if an assist node has been found and a recovered element exists,
5747 // mark enclosing blocks as to be preserved
5748 if (this.assistNode != null && this.currentElement != null) {
5749 this.currentElement.preserveEnclosingBlocks();
5750 }
5751
5752 /* check and update recovered state based on current token,
5753 this action is also performed when shifting token after recovery
5754 got activated once.
5755 */
5756 recoveryTokenCheck();
5757
5758 recoveryExitFromVariable();
5759 }
5760
5761 @Override
5762 protected LocalDeclaration createLocalDeclaration(char[] assistName, int sourceStart, int sourceEnd) {
5763 if (this.indexOfAssistIdentifier() < 0) {
5764 return super.createLocalDeclaration(assistName, sourceStart, sourceEnd);
5765 } else {
5766 CompletionOnLocalName local = new CompletionOnLocalName(assistName, sourceStart, sourceEnd);
5767 this.assistNode = local;
5768 this.lastCheckPoint = sourceEnd + 1;
5769 return local;
5770 }
5771 }
5772
5773 @Override
5774 protected JavadocParser createJavadocParser() {
5775 return new CompletionJavadocParser(this);
5776 }
5777
5778 @Override
5779 protected FieldDeclaration createFieldDeclaration(char[] assistName, int sourceStart, int sourceEnd) {
5780 if (this.indexOfAssistIdentifier() < 0 || (this.currentElement instanceof RecoveredUnit && ((RecoveredUnit)this.currentElement).typeCount == 0)) {
5781 return super.createFieldDeclaration(assistName, sourceStart, sourceEnd);
5782 } else {
5783 CompletionOnFieldName field = new CompletionOnFieldName(assistName, sourceStart, sourceEnd);
5784 this.assistNode = field;
5785 this.lastCheckPoint = sourceEnd + 1;
5786 return field;
5787 }
5788 }
5789
5790 /*
5791 * To find out if the given stack has an instanceof expression
5792 * at the given startIndex or at one prior to that
5793 */
5794 private boolean stackHasInstanceOfExpression(Object[] stackToSearch, int startIndex) {
5795 int indexInstanceOf = startIndex;
5796 while (indexInstanceOf >= 0) {
5797 if (stackToSearch[indexInstanceOf] instanceof InstanceOfExpression) {
5798 return true;
5799 }
5800 indexInstanceOf--;
5801 }
5802 return false;
5803 }
5804
5805 // https://bugs.eclipse.org/bugs/show_bug.cgi?id=292087
5806 @Override
5807 protected boolean isInsideArrayInitializer(){
5808 int i = this.elementPtr;
5809 if (i > -1 && this.elementKindStack[i] == K_ARRAY_INITIALIZER) {
5810 return true;
5811 }
5812 return false;
5813 }
5814 private boolean foundToken(int token) {
5815 int i = this.elementPtr;
5816 while (i > -1) {
5817 if (this.elementKindStack[i] == token) {
5818 return true;
5819 }
5820 i--;
5821 }
5822 return false;
5823 }
5824 @Override
5825 protected int actFromTokenOrSynthetic(int previousAct) {
5826 int newAct = tAction(previousAct, this.currentToken);
5827 if (this.hasError && !this.diet && newAct == ERROR_ACTION && this.currentToken == TerminalTokens.TokenNameEOF) {
5828 if (requireExtendedRecovery()) {
5829 // during extended recovery, if EOF would be wrong, try a few things to reduce our stacks:
5830 for (int tok : RECOVERY_TOKENS) {
5831 newAct = tAction(previousAct, tok);
5832 if (newAct != ERROR_ACTION) {
5833 this.currentToken = tok; // this worked, pretend we really got this from the Scanner
5834 return newAct;
5835 }
5836 }
5837 }
5838 }
5839 return newAct;
5840 }
5841
5842 protected boolean isInImportStatement() {
5843 return foundToken(K_INSIDE_IMPORT_STATEMENT);
5844 }
5845 protected boolean isInExportsStatement() {
5846 return foundToken(K_INSIDE_EXPORTS_STATEMENT);
5847 }
5848 protected boolean isInOpensStatement() {
5849 return foundToken(K_INSIDE_OPENS_STATEMENT);
5850 }
5851 protected boolean isInRequiresStatement() {
5852 return foundToken(K_INSIDE_REQUIRES_STATEMENT);
5853 }
5854 protected boolean isInUsesStatement() {
5855 return foundToken(K_INSIDE_USES_STATEMENT);
5856 }
5857 protected boolean isInProvidesStatement() {
5858 return foundToken(K_INSIDE_PROVIDES_STATEMENT);
5859 }
5860 protected boolean isAfterWithClause() {
5861 return foundToken(K_AFTER_WITH_IN_PROVIDES_STATEMENT);
5862 }
5863 protected boolean isInModuleStatements() {
5864 return isInExportsStatement() ||
5865 isInOpensStatement() ||
5866 isInRequiresStatement() ||
5867 isInProvidesStatement() ||
5868 isInUsesStatement();
5869 }
5870 }
5871