1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler;
14 * A source element parser extracts structural and reference information
15 * from a piece of source.
17 * also see @ISourceElementRequestor
19 * The structural investigation includes:
20 * - the package statement
22 * - top-level types: package member, member types (member types of member types...)
26 * If reference information is requested, then all source constructs are
27 * investigated and type, field & method references are provided as well.
29 * Any (parsing) problem encountered is also provided.
32 import net.sourceforge.phpdt.core.compiler.IProblem;
33 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
34 import net.sourceforge.phpdt.internal.compiler.ast.AllocationExpression;
35 import net.sourceforge.phpdt.internal.compiler.ast.AnonymousLocalTypeDeclaration;
36 import net.sourceforge.phpdt.internal.compiler.ast.Argument;
37 import net.sourceforge.phpdt.internal.compiler.ast.ArrayQualifiedTypeReference;
38 import net.sourceforge.phpdt.internal.compiler.ast.ArrayTypeReference;
39 import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
40 import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration;
41 import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration;
42 import net.sourceforge.phpdt.internal.compiler.ast.ExplicitConstructorCall;
43 import net.sourceforge.phpdt.internal.compiler.ast.Expression;
44 import net.sourceforge.phpdt.internal.compiler.ast.FieldDeclaration;
45 import net.sourceforge.phpdt.internal.compiler.ast.FieldReference;
46 import net.sourceforge.phpdt.internal.compiler.ast.ImportReference;
47 import net.sourceforge.phpdt.internal.compiler.ast.Initializer;
48 import net.sourceforge.phpdt.internal.compiler.ast.LocalTypeDeclaration;
49 import net.sourceforge.phpdt.internal.compiler.ast.MemberTypeDeclaration;
50 import net.sourceforge.phpdt.internal.compiler.ast.MessageSend;
51 import net.sourceforge.phpdt.internal.compiler.ast.MethodDeclaration;
52 import net.sourceforge.phpdt.internal.compiler.ast.NameReference;
53 import net.sourceforge.phpdt.internal.compiler.ast.QualifiedAllocationExpression;
54 import net.sourceforge.phpdt.internal.compiler.ast.QualifiedNameReference;
55 import net.sourceforge.phpdt.internal.compiler.ast.QualifiedTypeReference;
56 import net.sourceforge.phpdt.internal.compiler.ast.SingleNameReference;
57 import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference;
58 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
59 import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
60 import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
61 import net.sourceforge.phpdt.internal.compiler.env.ISourceType;
62 import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
63 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
64 import net.sourceforge.phpdt.internal.compiler.lookup.BindingIds;
65 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
66 import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
67 import net.sourceforge.phpdt.internal.compiler.parser.Parser;
68 import net.sourceforge.phpdt.internal.compiler.parser.RecoveredType;
69 import net.sourceforge.phpdt.internal.compiler.parser.SourceConstructorDeclaration;
70 import net.sourceforge.phpdt.internal.compiler.parser.SourceFieldDeclaration;
71 import net.sourceforge.phpdt.internal.compiler.parser.SourceMethodDeclaration;
72 import net.sourceforge.phpdt.internal.compiler.parser.SourceTypeConverter;
73 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
74 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
75 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
77 public class SourceElementParser extends Parser {
79 ISourceElementRequestor requestor;
80 private int fieldCount;
81 private int localIntPtr;
82 private int lastFieldEndPosition;
83 private ISourceType sourceType;
84 private boolean reportReferenceInfo;
85 private char[][] typeNames;
86 private char[][] superTypeNames;
87 private int nestedTypeIndex;
88 private static final char[] JAVA_LANG_OBJECT = "java.lang.Object".toCharArray(); //$NON-NLS-1$
89 private NameReference[] unknownRefs;
90 private int unknownRefsCounter;
91 private LocalDeclarationVisitor localDeclarationVisitor = null;
92 private CompilerOptions options;
95 * An ast visitor that visits local type declarations.
97 public class LocalDeclarationVisitor extends AbstractSyntaxTreeVisitorAdapter {
99 AnonymousLocalTypeDeclaration anonymousTypeDeclaration,
101 notifySourceElementRequestor(anonymousTypeDeclaration, sourceType == null);
102 return false; // don't visit members as this was done during notifySourceElementRequestor(...)
104 public boolean visit(LocalTypeDeclaration typeDeclaration, BlockScope scope) {
105 notifySourceElementRequestor(typeDeclaration, sourceType == null);
106 return false; // don't visit members as this was done during notifySourceElementRequestor(...)
108 public boolean visit(MemberTypeDeclaration typeDeclaration, ClassScope scope) {
109 notifySourceElementRequestor(typeDeclaration, sourceType == null);
110 return false; // don't visit members as this was done during notifySourceElementRequestor(...)
115 public SourceElementParser(
116 final ISourceElementRequestor requestor,
117 IProblemFactory problemFactory,
118 CompilerOptions options) {
119 // we want to notify all syntax error with the acceptProblem API
120 // To do so, we define the record method of the ProblemReporter
121 super(new ProblemReporter(
122 DefaultErrorHandlingPolicies.exitAfterAllProblems(),
125 public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) {
126 unitResult.record(problem, referenceContext);
127 requestor.acceptProblem(problem);
132 this.requestor = requestor;
133 typeNames = new char[4][];
134 superTypeNames = new char[4][];
136 this.options = options;
139 /** @deprecated use SourceElementParser(ISourceElementRequestor, IProblemFactory, CompilerOptions) */
140 public SourceElementParser(
141 final ISourceElementRequestor requestor,
142 IProblemFactory problemFactory) {
143 this(requestor, problemFactory, new CompilerOptions());
146 public SourceElementParser(
147 final ISourceElementRequestor requestor,
148 IProblemFactory problemFactory,
149 CompilerOptions options,
150 boolean reportLocalDeclarations) {
151 this(requestor, problemFactory, options);
152 if (reportLocalDeclarations) {
153 this.localDeclarationVisitor = new LocalDeclarationVisitor();
157 public void checkAnnotation() {
158 int firstCommentIndex = scanner.commentPtr;
160 super.checkAnnotation();
162 // modify the modifier source start to point at the first comment
163 if (firstCommentIndex >= 0) {
164 modifiersSourceStart = scanner.commentStarts[0];
168 protected void classInstanceCreation(boolean alwaysQualified) {
170 boolean previousFlag = reportReferenceInfo;
171 reportReferenceInfo = false; // not to see the type reference reported in super call to getTypeReference(...)
172 super.classInstanceCreation(alwaysQualified);
173 reportReferenceInfo = previousFlag;
174 if (reportReferenceInfo){
175 AllocationExpression alloc = (AllocationExpression)expressionStack[expressionPtr];
176 TypeReference typeRef = alloc.type;
177 requestor.acceptConstructorReference(
178 typeRef instanceof SingleTypeReference
179 ? ((SingleTypeReference) typeRef).token
180 : CharOperation.concatWith(alloc.type.getTypeName(), '.'),
181 alloc.arguments == null ? 0 : alloc.arguments.length,
185 protected void consumeConstructorHeaderName() {
186 // ConstructorHeaderName ::= Modifiersopt 'Identifier' '('
188 /* recovering - might be an empty message send */
189 if (currentElement != null){
190 if (lastIgnoredToken == TokenNamenew){ // was an allocation expression
191 lastCheckPoint = scanner.startPosition; // force to restart at this exact position
192 restartRecovery = true;
196 SourceConstructorDeclaration cd = new SourceConstructorDeclaration(this.compilationUnit.compilationResult);
198 //name -- this is not really revelant but we do .....
199 cd.selector = identifierStack[identifierPtr];
200 long selectorSourcePositions = identifierPositionStack[identifierPtr--];
201 identifierLengthPtr--;
204 cd.declarationSourceStart = intStack[intPtr--];
205 cd.modifiers = intStack[intPtr--];
207 //highlight starts at the selector starts
208 cd.sourceStart = (int) (selectorSourcePositions >>> 32);
209 cd.selectorSourceEnd = (int) selectorSourcePositions;
212 cd.sourceEnd = lParenPos;
213 cd.bodyStart = lParenPos+1;
214 listLength = 0; // initialize listLength before reading parameters/throws
217 if (currentElement != null){
218 lastCheckPoint = cd.bodyStart;
219 if ((currentElement instanceof RecoveredType && lastIgnoredToken != TokenNameDOT)
220 || cd.modifiers != 0){
221 currentElement = currentElement.add(cd, 0);
222 lastIgnoredToken = -1;
230 protected void consumeExitVariableWithInitialization() {
231 // ExitVariableWithInitialization ::= $empty
232 // the scanner is located after the comma or the semi-colon.
233 // we want to include the comma or the semi-colon
234 super.consumeExitVariableWithInitialization();
235 if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON)))
237 ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1;
239 protected void consumeExitVariableWithoutInitialization() {
240 // ExitVariableWithoutInitialization ::= $empty
241 // do nothing by default
242 if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON)))
244 ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1;
250 protected void consumeFieldAccess(boolean isSuperAccess) {
251 // FieldAccess ::= Primary '.' 'Identifier'
252 // FieldAccess ::= 'super' '.' 'Identifier'
253 super.consumeFieldAccess(isSuperAccess);
254 FieldReference fr = (FieldReference) expressionStack[expressionPtr];
255 if (reportReferenceInfo) {
256 requestor.acceptFieldReference(fr.token, fr.sourceStart);
259 protected void consumeMethodHeaderName() {
260 // MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
261 SourceMethodDeclaration md = new SourceMethodDeclaration(this.compilationUnit.compilationResult);
264 md.selector = identifierStack[identifierPtr];
265 long selectorSourcePositions = identifierPositionStack[identifierPtr--];
266 identifierLengthPtr--;
268 md.returnType = getTypeReference(intStack[intPtr--]);
270 md.declarationSourceStart = intStack[intPtr--];
271 md.modifiers = intStack[intPtr--];
273 //highlight starts at selector start
274 md.sourceStart = (int) (selectorSourcePositions >>> 32);
275 md.selectorSourceEnd = (int) selectorSourcePositions;
277 md.sourceEnd = lParenPos;
278 md.bodyStart = lParenPos+1;
279 listLength = 0; // initialize listLength before reading parameters/throws
282 if (currentElement != null){
283 if (currentElement instanceof RecoveredType
284 //|| md.modifiers != 0
285 || (scanner.getLineNumber(md.returnType.sourceStart)
286 == scanner.getLineNumber(md.sourceStart))){
287 lastCheckPoint = md.bodyStart;
288 currentElement = currentElement.add(md, 0);
289 lastIgnoredToken = -1;
291 lastCheckPoint = md.sourceStart;
292 restartRecovery = true;
300 protected void consumeMethodInvocationName() {
301 // MethodInvocation ::= Name '(' ArgumentListopt ')'
303 // when the name is only an identifier...we have a message send to "this" (implicit)
304 super.consumeMethodInvocationName();
305 MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
306 Expression[] args = messageSend.arguments;
307 if (reportReferenceInfo) {
308 requestor.acceptMethodReference(
309 messageSend.selector,
310 args == null ? 0 : args.length,
311 (int)(messageSend.nameSourcePosition >>> 32));
318 protected void consumeMethodInvocationPrimary() {
319 super.consumeMethodInvocationPrimary();
320 MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
321 Expression[] args = messageSend.arguments;
322 if (reportReferenceInfo) {
323 requestor.acceptMethodReference(
324 messageSend.selector,
325 args == null ? 0 : args.length,
326 (int)(messageSend.nameSourcePosition >>> 32));
333 protected void consumeMethodInvocationSuper() {
334 // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')'
335 super.consumeMethodInvocationSuper();
336 MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
337 Expression[] args = messageSend.arguments;
338 if (reportReferenceInfo) {
339 requestor.acceptMethodReference(
340 messageSend.selector,
341 args == null ? 0 : args.length,
342 (int)(messageSend.nameSourcePosition >>> 32));
345 protected void consumeSingleTypeImportDeclarationName() {
346 // SingleTypeImportDeclarationName ::= 'import' Name
347 /* push an ImportRef build from the last name
348 stored in the identifier stack. */
350 super.consumeSingleTypeImportDeclarationName();
351 ImportReference impt = (ImportReference)astStack[astPtr];
352 if (reportReferenceInfo) {
353 requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
356 protected void consumeTypeImportOnDemandDeclarationName() {
357 // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
358 /* push an ImportRef build from the last name
359 stored in the identifier stack. */
361 super.consumeTypeImportOnDemandDeclarationName();
362 ImportReference impt = (ImportReference)astStack[astPtr];
363 if (reportReferenceInfo) {
364 requestor.acceptUnknownReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
367 protected FieldDeclaration createFieldDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) {
368 return new SourceFieldDeclaration(null, name, sourceStart, sourceEnd);
370 protected CompilationUnitDeclaration endParse(int act) {
371 if (sourceType != null) {
372 if (sourceType.isInterface()) {
373 consumeInterfaceDeclaration();
375 consumeClassDeclaration();
378 if (compilationUnit != null) {
379 CompilationUnitDeclaration result = super.endParse(act);
386 * Flush annotations defined prior to a given positions.
388 * Note: annotations are stacked in syntactical order
390 * Either answer given <position>, or the end position of a comment line
391 * immediately following the <position> (same line)
395 * } // end of method foo
398 public int flushAnnotationsDefinedPriorTo(int position) {
400 return lastFieldEndPosition = super.flushAnnotationsDefinedPriorTo(position);
402 public TypeReference getTypeReference(int dim) {
403 /* build a Reference on a variable that may be qualified or not
404 * This variable is a type reference and dim will be its dimensions
407 if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
408 // single variable reference
410 SingleTypeReference ref =
411 new SingleTypeReference(
412 identifierStack[identifierPtr],
413 identifierPositionStack[identifierPtr--]);
414 if (reportReferenceInfo) {
415 requestor.acceptTypeReference(ref.token, ref.sourceStart);
419 ArrayTypeReference ref =
420 new ArrayTypeReference(
421 identifierStack[identifierPtr],
423 identifierPositionStack[identifierPtr--]);
424 ref.sourceEnd = endPosition;
425 if (reportReferenceInfo) {
426 requestor.acceptTypeReference(ref.token, ref.sourceStart);
431 if (length < 0) { //flag for precompiled type reference on base types
432 TypeReference ref = TypeReference.baseTypeReference(-length, dim);
433 ref.sourceStart = intStack[intPtr--];
435 ref.sourceEnd = intStack[intPtr--];
437 intPtr--; // no need to use this position as it is an array
438 ref.sourceEnd = endPosition;
440 if (reportReferenceInfo){
441 requestor.acceptTypeReference(ref.getTypeName(), ref.sourceStart, ref.sourceEnd);
444 } else { //Qualified variable reference
445 char[][] tokens = new char[length][];
446 identifierPtr -= length;
447 long[] positions = new long[length];
448 System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
450 identifierPositionStack,
456 QualifiedTypeReference ref = new QualifiedTypeReference(tokens, positions);
457 if (reportReferenceInfo) {
458 requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd);
462 ArrayQualifiedTypeReference ref =
463 new ArrayQualifiedTypeReference(tokens, dim, positions);
464 ref.sourceEnd = endPosition;
465 if (reportReferenceInfo) {
466 requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd);
473 public NameReference getUnspecifiedReference() {
474 /* build a (unspecified) NameReference which may be qualified*/
477 if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
478 // single variable reference
479 SingleNameReference ref =
480 new SingleNameReference(
481 identifierStack[identifierPtr],
482 identifierPositionStack[identifierPtr--]);
483 if (reportReferenceInfo) {
484 this.addUnknownRef(ref);
488 //Qualified variable reference
489 char[][] tokens = new char[length][];
490 identifierPtr -= length;
491 System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
492 QualifiedNameReference ref =
493 new QualifiedNameReference(
495 (int) (identifierPositionStack[identifierPtr + 1] >> 32), // sourceStart
496 (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
497 if (reportReferenceInfo) {
498 this.addUnknownRef(ref);
503 public NameReference getUnspecifiedReferenceOptimized() {
504 /* build a (unspecified) NameReference which may be qualified
505 The optimization occurs for qualified reference while we are
506 certain in this case the last item of the qualified name is
507 a field access. This optimization is IMPORTANT while it results
508 that when a NameReference is build, the type checker should always
509 look for that it is not a type reference */
512 if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
513 // single variable reference
514 SingleNameReference ref =
515 new SingleNameReference(
516 identifierStack[identifierPtr],
517 identifierPositionStack[identifierPtr--]);
518 ref.bits &= ~AstNode.RestrictiveFlagMASK;
519 ref.bits |= LOCAL | FIELD;
520 if (reportReferenceInfo) {
521 this.addUnknownRef(ref);
526 //Qualified-variable-reference
527 //In fact it is variable-reference DOT field-ref , but it would result in a type
528 //conflict tha can be only reduce by making a superclass (or inetrface ) between
529 //nameReference and FiledReference or putting FieldReference under NameReference
530 //or else..........This optimisation is not really relevant so just leave as it is
532 char[][] tokens = new char[length][];
533 identifierPtr -= length;
534 System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
535 QualifiedNameReference ref =
536 new QualifiedNameReference(
538 (int) (identifierPositionStack[identifierPtr + 1] >> 32),
540 (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
541 ref.bits &= ~AstNode.RestrictiveFlagMASK;
542 ref.bits |= LOCAL | FIELD;
543 if (reportReferenceInfo) {
544 this.addUnknownRef(ref);
552 private boolean isLocalDeclaration() {
553 int nestedDepth = nestedType;
554 while (nestedDepth >= 0) {
555 if (nestedMethod[nestedDepth] != 0) {
563 * Update the bodyStart of the corresponding parse node
565 public void notifySourceElementRequestor(CompilationUnitDeclaration parsedUnit) {
566 if (parsedUnit == null) {
567 // when we parse a single type member declaration the compilation unit is null, but we still
568 // want to be able to notify the requestor on the created ast node
569 if (astStack[0] instanceof AbstractMethodDeclaration) {
570 notifySourceElementRequestor((AbstractMethodDeclaration) astStack[0]);
577 scanner.initialPosition <= parsedUnit.sourceStart
578 && scanner.eofPosition >= parsedUnit.sourceEnd;
580 if (reportReferenceInfo) {
581 notifyAllUnknownReferences();
583 // collect the top level ast nodes
585 AstNode[] nodes = null;
586 if (sourceType == null){
588 requestor.enterCompilationUnit();
590 ImportReference currentPackage = parsedUnit.currentPackage;
591 ImportReference[] imports = parsedUnit.imports;
592 TypeDeclaration[] types = parsedUnit.types;
594 (currentPackage == null ? 0 : 1)
595 + (imports == null ? 0 : imports.length)
596 + (types == null ? 0 : types.length);
597 nodes = new AstNode[length];
599 if (currentPackage != null) {
600 nodes[index++] = currentPackage;
602 if (imports != null) {
603 for (int i = 0, max = imports.length; i < max; i++) {
604 nodes[index++] = imports[i];
608 for (int i = 0, max = types.length; i < max; i++) {
609 nodes[index++] = types[i];
613 TypeDeclaration[] types = parsedUnit.types;
615 length = types.length;
616 nodes = new AstNode[length];
617 for (int i = 0, max = types.length; i < max; i++) {
623 // notify the nodes in the syntactical order
624 if (nodes != null && length > 0) {
625 quickSort(nodes, 0, length-1);
626 for (int i=0;i<length;i++) {
627 AstNode node = nodes[i];
628 if (node instanceof ImportReference) {
629 ImportReference importRef = (ImportReference)node;
630 if (node == parsedUnit.currentPackage) {
631 notifySourceElementRequestor(importRef, true);
633 notifySourceElementRequestor(importRef, false);
635 } else { // instanceof TypeDeclaration
636 notifySourceElementRequestor((TypeDeclaration)node, sourceType == null);
641 if (sourceType == null){
643 requestor.exitCompilationUnit(parsedUnit.sourceEnd);
648 private void notifyAllUnknownReferences() {
649 for (int i = 0, max = this.unknownRefsCounter; i < max; i++) {
650 NameReference nameRef = this.unknownRefs[i];
651 if ((nameRef.bits & BindingIds.VARIABLE) != 0) {
652 if ((nameRef.bits & BindingIds.TYPE) == 0) {
653 // variable but not type
654 if (nameRef instanceof SingleNameReference) {
655 // local var or field
656 requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
658 // QualifiedNameReference
659 // The last token is a field reference and the previous tokens are a type/variable references
660 char[][] tokens = ((QualifiedNameReference) nameRef).tokens;
661 int tokensLength = tokens.length;
662 requestor.acceptFieldReference(tokens[tokensLength - 1], nameRef.sourceEnd - tokens[tokensLength - 1].length + 1);
663 char[][] typeRef = new char[tokensLength - 1][];
664 System.arraycopy(tokens, 0, typeRef, 0, tokensLength - 1);
665 requestor.acceptUnknownReference(typeRef, nameRef.sourceStart, nameRef.sourceEnd - tokens[tokensLength - 1].length);
669 if (nameRef instanceof SingleNameReference) {
670 requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
672 //QualifiedNameReference
673 requestor.acceptUnknownReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
676 } else if ((nameRef.bits & BindingIds.TYPE) != 0) {
677 if (nameRef instanceof SingleNameReference) {
678 requestor.acceptTypeReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
680 // it is a QualifiedNameReference
681 requestor.acceptTypeReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
687 * Update the bodyStart of the corresponding parse node
689 public void notifySourceElementRequestor(AbstractMethodDeclaration methodDeclaration) {
693 scanner.initialPosition <= methodDeclaration.declarationSourceStart
694 && scanner.eofPosition >= methodDeclaration.declarationSourceEnd;
696 if (methodDeclaration.isClinit()) {
697 this.visitIfNeeded(methodDeclaration);
701 if (methodDeclaration.isDefaultConstructor()) {
702 if (reportReferenceInfo) {
703 ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration;
704 ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall;
705 if (constructorCall != null) {
706 switch(constructorCall.accessMode) {
707 case ExplicitConstructorCall.This :
708 requestor.acceptConstructorReference(
709 typeNames[nestedTypeIndex-1],
710 constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
711 constructorCall.sourceStart);
713 case ExplicitConstructorCall.Super :
714 case ExplicitConstructorCall.ImplicitSuper :
715 requestor.acceptConstructorReference(
716 superTypeNames[nestedTypeIndex-1],
717 constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
718 constructorCall.sourceStart);
725 char[][] argumentTypes = null;
726 char[][] argumentNames = null;
727 Argument[] arguments = methodDeclaration.arguments;
728 if (arguments != null) {
729 int argumentLength = arguments.length;
730 argumentTypes = new char[argumentLength][];
731 argumentNames = new char[argumentLength][];
732 for (int i = 0; i < argumentLength; i++) {
733 argumentTypes[i] = returnTypeName(arguments[i].type);
734 argumentNames[i] = arguments[i].name;
737 char[][] thrownExceptionTypes = null;
738 TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions;
739 if (thrownExceptions != null) {
740 int thrownExceptionLength = thrownExceptions.length;
741 thrownExceptionTypes = new char[thrownExceptionLength][];
742 for (int i = 0; i < thrownExceptionLength; i++) {
743 thrownExceptionTypes[i] =
744 CharOperation.concatWith(thrownExceptions[i].getTypeName(), '.');
747 // by default no selector end position
748 int selectorSourceEnd = -1;
749 if (methodDeclaration.isConstructor()) {
750 if (methodDeclaration instanceof SourceConstructorDeclaration) {
752 ((SourceConstructorDeclaration) methodDeclaration).selectorSourceEnd;
755 requestor.enterConstructor(
756 methodDeclaration.declarationSourceStart,
757 methodDeclaration.modifiers,
758 methodDeclaration.selector,
759 methodDeclaration.sourceStart,
763 thrownExceptionTypes);
765 if (reportReferenceInfo) {
766 ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration;
767 ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall;
768 if (constructorCall != null) {
769 switch(constructorCall.accessMode) {
770 case ExplicitConstructorCall.This :
771 requestor.acceptConstructorReference(
772 typeNames[nestedTypeIndex-1],
773 constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
774 constructorCall.sourceStart);
776 case ExplicitConstructorCall.Super :
777 case ExplicitConstructorCall.ImplicitSuper :
778 requestor.acceptConstructorReference(
779 superTypeNames[nestedTypeIndex-1],
780 constructorCall.arguments == null ? 0 : constructorCall.arguments.length,
781 constructorCall.sourceStart);
786 this.visitIfNeeded(methodDeclaration);
788 requestor.exitConstructor(methodDeclaration.declarationSourceEnd);
792 if (methodDeclaration instanceof SourceMethodDeclaration) {
794 ((SourceMethodDeclaration) methodDeclaration).selectorSourceEnd;
797 requestor.enterMethod(
798 methodDeclaration.declarationSourceStart,
799 methodDeclaration.modifiers & AccJustFlag,
800 returnTypeName(((MethodDeclaration) methodDeclaration).returnType),
801 methodDeclaration.selector,
802 methodDeclaration.sourceStart,
806 thrownExceptionTypes);
808 this.visitIfNeeded(methodDeclaration);
811 requestor.exitMethod(methodDeclaration.declarationSourceEnd);
815 * Update the bodyStart of the corresponding parse node
817 public void notifySourceElementRequestor(FieldDeclaration fieldDeclaration) {
821 scanner.initialPosition <= fieldDeclaration.declarationSourceStart
822 && scanner.eofPosition >= fieldDeclaration.declarationSourceEnd;
824 if (fieldDeclaration.isField()) {
825 int fieldEndPosition = fieldDeclaration.declarationSourceEnd;
826 if (fieldDeclaration instanceof SourceFieldDeclaration) {
827 fieldEndPosition = ((SourceFieldDeclaration) fieldDeclaration).fieldEndPosition;
828 if (fieldEndPosition == 0) {
829 // use the declaration source end by default
830 fieldEndPosition = fieldDeclaration.declarationSourceEnd;
834 requestor.enterField(
835 fieldDeclaration.declarationSourceStart,
836 fieldDeclaration.modifiers & AccJustFlag,
837 returnTypeName(fieldDeclaration.type),
838 fieldDeclaration.name,
839 fieldDeclaration.sourceStart,
840 fieldDeclaration.sourceEnd);
842 this.visitIfNeeded(fieldDeclaration);
844 requestor.exitField(fieldEndPosition);
849 requestor.enterInitializer(
850 fieldDeclaration.declarationSourceStart,
851 fieldDeclaration.modifiers);
853 this.visitIfNeeded((Initializer)fieldDeclaration);
855 requestor.exitInitializer(fieldDeclaration.declarationSourceEnd);
859 public void notifySourceElementRequestor(
860 ImportReference importReference,
863 requestor.acceptPackage(
864 importReference.declarationSourceStart,
865 importReference.declarationSourceEnd,
866 CharOperation.concatWith(importReference.getImportName(), '.'));
868 requestor.acceptImport(
869 importReference.declarationSourceStart,
870 importReference.declarationSourceEnd,
871 CharOperation.concatWith(importReference.getImportName(), '.'),
872 importReference.onDemand);
875 public void notifySourceElementRequestor(TypeDeclaration typeDeclaration, boolean notifyTypePresence) {
879 scanner.initialPosition <= typeDeclaration.declarationSourceStart
880 && scanner.eofPosition >= typeDeclaration.declarationSourceEnd;
882 FieldDeclaration[] fields = typeDeclaration.fields;
883 AbstractMethodDeclaration[] methods = typeDeclaration.methods;
884 MemberTypeDeclaration[] memberTypes = typeDeclaration.memberTypes;
885 int fieldCount = fields == null ? 0 : fields.length;
886 int methodCount = methods == null ? 0 : methods.length;
887 int memberTypeCount = memberTypes == null ? 0 : memberTypes.length;
890 int memberTypeIndex = 0;
891 boolean isInterface = typeDeclaration.isInterface();
893 if (notifyTypePresence){
894 char[][] interfaceNames = null;
895 int superInterfacesLength = 0;
896 TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
897 if (superInterfaces != null) {
898 superInterfacesLength = superInterfaces.length;
899 interfaceNames = new char[superInterfacesLength][];
901 if (typeDeclaration instanceof AnonymousLocalTypeDeclaration) {
903 QualifiedAllocationExpression alloc = ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation;
904 if (alloc != null && alloc.type != null) {
905 superInterfaces = new TypeReference[] { ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation.type};
906 superInterfacesLength = 1;
907 interfaceNames = new char[1][];
911 if (superInterfaces != null) {
912 for (int i = 0; i < superInterfacesLength; i++) {
914 CharOperation.concatWith(superInterfaces[i].getTypeName(), '.');
919 requestor.enterInterface(
920 typeDeclaration.declarationSourceStart,
921 typeDeclaration.modifiers & AccJustFlag,
922 typeDeclaration.name,
923 typeDeclaration.sourceStart,
924 typeDeclaration.sourceEnd,
927 if (nestedTypeIndex == typeNames.length) {
929 System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
930 System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
932 typeNames[nestedTypeIndex] = typeDeclaration.name;
933 superTypeNames[nestedTypeIndex++] = JAVA_LANG_OBJECT;
935 TypeReference superclass = typeDeclaration.superclass;
936 if (superclass == null) {
938 requestor.enterClass(
939 typeDeclaration.declarationSourceStart,
940 typeDeclaration.modifiers,
941 typeDeclaration.name,
942 typeDeclaration.sourceStart,
943 typeDeclaration.sourceEnd,
949 requestor.enterClass(
950 typeDeclaration.declarationSourceStart,
951 typeDeclaration.modifiers,
952 typeDeclaration.name,
953 typeDeclaration.sourceStart,
954 typeDeclaration.sourceEnd,
955 CharOperation.concatWith(superclass.getTypeName(), '.'),
959 if (nestedTypeIndex == typeNames.length) {
961 System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
962 System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
964 typeNames[nestedTypeIndex] = typeDeclaration.name;
965 superTypeNames[nestedTypeIndex++] = superclass == null ? JAVA_LANG_OBJECT : CharOperation.concatWith(superclass.getTypeName(), '.');
968 while ((fieldIndex < fieldCount)
969 || (memberTypeIndex < memberTypeCount)
970 || (methodIndex < methodCount)) {
971 FieldDeclaration nextFieldDeclaration = null;
972 AbstractMethodDeclaration nextMethodDeclaration = null;
973 TypeDeclaration nextMemberDeclaration = null;
975 int position = Integer.MAX_VALUE;
976 int nextDeclarationType = -1;
977 if (fieldIndex < fieldCount) {
978 nextFieldDeclaration = fields[fieldIndex];
979 if (nextFieldDeclaration.declarationSourceStart < position) {
980 position = nextFieldDeclaration.declarationSourceStart;
981 nextDeclarationType = 0; // FIELD
984 if (methodIndex < methodCount) {
985 nextMethodDeclaration = methods[methodIndex];
986 if (nextMethodDeclaration.declarationSourceStart < position) {
987 position = nextMethodDeclaration.declarationSourceStart;
988 nextDeclarationType = 1; // METHOD
991 if (memberTypeIndex < memberTypeCount) {
992 nextMemberDeclaration = memberTypes[memberTypeIndex];
993 if (nextMemberDeclaration.declarationSourceStart < position) {
994 position = nextMemberDeclaration.declarationSourceStart;
995 nextDeclarationType = 2; // MEMBER
998 switch (nextDeclarationType) {
1001 notifySourceElementRequestor(nextFieldDeclaration);
1005 notifySourceElementRequestor(nextMethodDeclaration);
1009 notifySourceElementRequestor(nextMemberDeclaration, true);
1012 if (notifyTypePresence){
1015 requestor.exitInterface(typeDeclaration.declarationSourceEnd);
1017 requestor.exitClass(typeDeclaration.declarationSourceEnd);
1023 public void parseCompilationUnit(
1024 ICompilationUnit unit,
1027 boolean needReferenceInfo) {
1029 reportReferenceInfo = needReferenceInfo;
1031 if (needReferenceInfo) {
1032 unknownRefs = new NameReference[10];
1033 unknownRefsCounter = 0;
1037 CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit);
1038 CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, start, end);
1039 if (needReferenceInfo){
1041 this.getMethodBodies(parsedUnit);
1043 this.scanner.resetTo(start, end);
1044 notifySourceElementRequestor(parsedUnit);
1045 } catch (AbortCompilation e) {
1047 if (scanner.recordLineSeparator) {
1048 requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
1053 public void parseCompilationUnit(
1054 ICompilationUnit unit,
1055 boolean needReferenceInfo) {
1057 if (needReferenceInfo) {
1058 unknownRefs = new NameReference[10];
1059 unknownRefsCounter = 0;
1063 /* diet = !needReferenceInfo;
1064 reportReferenceInfo = needReferenceInfo;
1065 CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0);
1066 parse(unit, compilationUnitResult);
1068 reportReferenceInfo = needReferenceInfo;
1069 CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit);
1070 CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult);
1071 int initialStart = this.scanner.initialPosition;
1072 int initialEnd = this.scanner.eofPosition;
1073 if (needReferenceInfo){
1075 this.getMethodBodies(parsedUnit);
1077 this.scanner.resetTo(initialStart, initialEnd);
1078 notifySourceElementRequestor(parsedUnit);
1079 } catch (AbortCompilation e) {
1081 if (scanner.recordLineSeparator) {
1082 requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
1087 public void parseTypeMemberDeclarations(
1088 ISourceType sourceType,
1089 ICompilationUnit sourceUnit,
1092 boolean needReferenceInfo) {
1094 if (needReferenceInfo) {
1095 unknownRefs = new NameReference[10];
1096 unknownRefsCounter = 0;
1100 diet = !needReferenceInfo;
1101 reportReferenceInfo = needReferenceInfo;
1102 CompilationResult compilationUnitResult =
1103 new CompilationResult(sourceUnit, 0, 0, this.options.maxProblemsPerUnit);
1104 CompilationUnitDeclaration unit =
1105 SourceTypeConverter.buildCompilationUnit(
1106 new ISourceType[]{sourceType},
1110 compilationUnitResult);
1111 if ((unit == null) || (unit.types == null) || (unit.types.length != 1))
1113 this.sourceType = sourceType;
1115 /* automaton initialization */
1117 goForClassBodyDeclarations();
1118 /* scanner initialization */
1119 scanner.setSource(sourceUnit.getContents());
1120 scanner.resetTo(start, end);
1122 referenceContext = compilationUnit = unit;
1123 /* initialize the astStacl */
1124 // the compilationUnitDeclaration should contain exactly one type
1125 pushOnAstStack(unit.types[0]);
1128 notifySourceElementRequestor(unit);
1130 unit = compilationUnit;
1131 compilationUnit = null; // reset parser
1133 } catch (AbortCompilation e) {
1135 if (scanner.recordLineSeparator) {
1136 requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
1142 public void parseTypeMemberDeclarations(
1152 /* automaton initialization */
1154 goForClassBodyDeclarations();
1155 /* scanner initialization */
1156 scanner.setSource(contents);
1157 scanner.recordLineSeparator = false;
1158 scanner.resetTo(start, end);
1161 referenceContext = null;
1163 /* initialize the astStacl */
1164 // the compilationUnitDeclaration should contain exactly one type
1167 notifySourceElementRequestor((CompilationUnitDeclaration)null);
1168 } catch (AbortCompilation e) {
1174 * Sort the given ast nodes by their positions.
1176 private static void quickSort(AstNode[] sortedCollection, int left, int right) {
1177 int original_left = left;
1178 int original_right = right;
1179 AstNode mid = sortedCollection[ (left + right) / 2];
1181 while (sortedCollection[left].sourceStart < mid.sourceStart) {
1184 while (mid.sourceStart < sortedCollection[right].sourceStart) {
1187 if (left <= right) {
1188 AstNode tmp = sortedCollection[left];
1189 sortedCollection[left] = sortedCollection[right];
1190 sortedCollection[right] = tmp;
1194 } while (left <= right);
1195 if (original_left < right) {
1196 quickSort(sortedCollection, original_left, right);
1198 if (left < original_right) {
1199 quickSort(sortedCollection, left, original_right);
1203 * Answer a char array representation of the type name formatted like:
1204 * - type name + dimensions
1206 * "A[][]".toCharArray()
1207 * "java.lang.String".toCharArray()
1209 private char[] returnTypeName(TypeReference type) {
1212 int dimension = type.dimensions();
1213 if (dimension != 0) {
1214 char[] dimensionsArray = new char[dimension * 2];
1215 for (int i = 0; i < dimension; i++) {
1216 dimensionsArray[i * 2] = '[';
1217 dimensionsArray[(i * 2) + 1] = ']';
1219 return CharOperation.concat(
1220 CharOperation.concatWith(type.getTypeName(), '.'),
1223 return CharOperation.concatWith(type.getTypeName(), '.');
1226 public void addUnknownRef(NameReference nameRef) {
1227 if (this.unknownRefs.length == this.unknownRefsCounter) {
1232 (this.unknownRefs = new NameReference[this.unknownRefsCounter * 2]),
1234 this.unknownRefsCounter);
1236 this.unknownRefs[this.unknownRefsCounter++] = nameRef;
1238 private TypeReference typeReference(
1240 int localIdentifierPtr,
1241 int localIdentifierLengthPtr) {
1242 /* build a Reference on a variable that may be qualified or not
1243 * This variable is a type reference and dim will be its dimensions.
1244 * We don't have any side effect on the stacks' pointers.
1249 if ((length = identifierLengthStack[localIdentifierLengthPtr]) == 1) {
1250 // single variable reference
1253 new SingleTypeReference(
1254 identifierStack[localIdentifierPtr],
1255 identifierPositionStack[localIdentifierPtr--]);
1258 new ArrayTypeReference(
1259 identifierStack[localIdentifierPtr],
1261 identifierPositionStack[localIdentifierPtr--]);
1262 ref.sourceEnd = endPosition;
1265 if (length < 0) { //flag for precompiled type reference on base types
1266 ref = TypeReference.baseTypeReference(-length, dim);
1267 ref.sourceStart = intStack[localIntPtr--];
1269 ref.sourceEnd = intStack[localIntPtr--];
1272 ref.sourceEnd = endPosition;
1274 } else { //Qualified variable reference
1275 char[][] tokens = new char[length][];
1276 localIdentifierPtr -= length;
1277 long[] positions = new long[length];
1278 System.arraycopy(identifierStack, localIdentifierPtr + 1, tokens, 0, length);
1280 identifierPositionStack,
1281 localIdentifierPtr + 1,
1286 ref = new QualifiedTypeReference(tokens, positions);
1288 ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
1289 ref.sourceEnd = endPosition;
1296 private void visitIfNeeded(AbstractMethodDeclaration method) {
1297 if (this.localDeclarationVisitor != null
1298 && (method.bits & AstNode.HasLocalTypeMASK) != 0) {
1299 if (method.statements != null) {
1300 int statementsLength = method.statements.length;
1301 for (int i = 0; i < statementsLength; i++)
1302 method.statements[i].traverse(this.localDeclarationVisitor, method.scope);
1307 private void visitIfNeeded(FieldDeclaration field) {
1308 if (this.localDeclarationVisitor != null
1309 && (field.bits & AstNode.HasLocalTypeMASK) != 0) {
1310 if (field.initialization != null) {
1311 field.initialization.traverse(this.localDeclarationVisitor, null);
1316 private void visitIfNeeded(Initializer initializer) {
1317 if (this.localDeclarationVisitor != null
1318 && (initializer.bits & AstNode.HasLocalTypeMASK) != 0) {
1319 if (initializer.block != null) {
1320 initializer.block.traverse(this.localDeclarationVisitor, null);
1325 protected void reportSyntaxError(int act, int currentKind, int stateStackTop) {
1326 if (compilationUnit == null) return;
1327 super.reportSyntaxError(act, currentKind,stateStackTop);