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