Added default preferences for outline options
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / SourceElementParser.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler;
12
13 /**
14  * A source element parser extracts structural and reference information
15  * from a piece of source.
16  *
17  * also see @ISourceElementRequestor
18  *
19  * The structural investigation includes:
20  * - the package statement
21  * - import statements
22  * - top-level types: package member, member types (member types of member types...)
23  * - fields
24  * - methods
25  *
26  * If reference information is requested, then all source constructs are
27  * investigated and type, field & method references are provided as well.
28  *
29  * Any (parsing) problem encountered is also provided.
30  */
31
32 import net.sourceforge.phpdt.internal.compiler.env.*;
33 import net.sourceforge.phpdt.internal.compiler.impl.*;
34 import net.sourceforge.phpdt.core.compiler.*;
35 import net.sourceforge.phpdt.internal.compiler.ast.*;
36 import net.sourceforge.phpdt.internal.compiler.lookup.*;
37 import net.sourceforge.phpdt.internal.compiler.parser.*;
38 import net.sourceforge.phpdt.internal.compiler.problem.*;
39 import net.sourceforge.phpdt.internal.compiler.util.*;
40
41 public class SourceElementParser extends Parser {
42         
43         ISourceElementRequestor requestor;
44         private int fieldCount;
45         private int localIntPtr;
46         private int lastFieldEndPosition;
47         private ISourceType sourceType;
48         private boolean reportReferenceInfo;
49         private char[][] typeNames;
50         private char[][] superTypeNames;
51         private int nestedTypeIndex;
52         private static final char[] JAVA_LANG_OBJECT = "java.lang.Object".toCharArray(); //$NON-NLS-1$
53         private NameReference[] unknownRefs;
54         private int unknownRefsCounter;
55         private LocalDeclarationVisitor localDeclarationVisitor = null;
56         private CompilerOptions options;
57         
58 /**
59  * An ast visitor that visits local type declarations.
60  */
61 public class LocalDeclarationVisitor extends AbstractSyntaxTreeVisitorAdapter {
62         public boolean visit(
63                         AnonymousLocalTypeDeclaration anonymousTypeDeclaration,
64                         BlockScope scope) {
65                 notifySourceElementRequestor(anonymousTypeDeclaration, sourceType == null);
66                 return false; // don't visit members as this was done during notifySourceElementRequestor(...)
67         }
68         public boolean visit(LocalTypeDeclaration typeDeclaration, BlockScope scope) {
69                 notifySourceElementRequestor(typeDeclaration, sourceType == null);
70                 return false; // don't visit members as this was done during notifySourceElementRequestor(...)
71         }
72         public boolean visit(MemberTypeDeclaration typeDeclaration, ClassScope scope) {
73                 notifySourceElementRequestor(typeDeclaration, sourceType == null);
74                 return false; // don't visit members as this was done during notifySourceElementRequestor(...)
75         }
76         
77 }
78
79 public SourceElementParser(
80         final ISourceElementRequestor requestor, 
81         IProblemFactory problemFactory,
82         CompilerOptions options) {
83         // we want to notify all syntax error with the acceptProblem API
84         // To do so, we define the record method of the ProblemReporter
85         super(new ProblemReporter(
86                 DefaultErrorHandlingPolicies.exitAfterAllProblems(),
87                 options, 
88                 problemFactory) {
89                 public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) {
90                         unitResult.record(problem, referenceContext);
91                         requestor.acceptProblem(problem);
92                 }
93         },
94         true,
95         options.assertMode);
96         this.requestor = requestor;
97         typeNames = new char[4][];
98         superTypeNames = new char[4][];
99         nestedTypeIndex = 0;
100         this.options = options;
101 }
102
103 /** @deprecated use SourceElementParser(ISourceElementRequestor, IProblemFactory, CompilerOptions) */
104 public SourceElementParser(
105         final ISourceElementRequestor requestor, 
106         IProblemFactory problemFactory) {
107                 this(requestor, problemFactory, new CompilerOptions());
108 }
109
110 public SourceElementParser(
111         final ISourceElementRequestor requestor, 
112         IProblemFactory problemFactory,
113         CompilerOptions options,
114         boolean reportLocalDeclarations) {
115                 this(requestor, problemFactory, options);
116                 if (reportLocalDeclarations) {
117                         this.localDeclarationVisitor = new LocalDeclarationVisitor();
118                 }
119 }
120
121 public void checkAnnotation() {
122         int firstCommentIndex = scanner.commentPtr;
123
124         super.checkAnnotation();
125
126         // modify the modifier source start to point at the first comment
127         if (firstCommentIndex >= 0) {
128                 modifiersSourceStart = scanner.commentStarts[0]; 
129         }
130 }
131
132 protected void classInstanceCreation(boolean alwaysQualified) {
133
134         boolean previousFlag = reportReferenceInfo;
135         reportReferenceInfo = false; // not to see the type reference reported in super call to getTypeReference(...)
136         super.classInstanceCreation(alwaysQualified);
137         reportReferenceInfo = previousFlag;
138         if (reportReferenceInfo){
139                 AllocationExpression alloc = (AllocationExpression)expressionStack[expressionPtr];
140                 TypeReference typeRef = alloc.type;
141                 requestor.acceptConstructorReference(
142                         typeRef instanceof SingleTypeReference 
143                                 ? ((SingleTypeReference) typeRef).token
144                                 : CharOperation.concatWith(alloc.type.getTypeName(), '.'),
145                         alloc.arguments == null ? 0 : alloc.arguments.length, 
146                         alloc.sourceStart);
147         }
148 }
149 protected void consumeConstructorHeaderName() {
150         // ConstructorHeaderName ::=  Modifiersopt 'Identifier' '('
151
152         /* recovering - might be an empty message send */
153         if (currentElement != null){
154                 if (lastIgnoredToken == TokenNamenew){ // was an allocation expression
155                         lastCheckPoint = scanner.startPosition; // force to restart at this exact position                              
156                         restartRecovery = true;
157                         return;
158                 }
159         }
160         SourceConstructorDeclaration cd = new SourceConstructorDeclaration(this.compilationUnit.compilationResult);
161
162         //name -- this is not really revelant but we do .....
163         cd.selector = identifierStack[identifierPtr];
164         long selectorSourcePositions = identifierPositionStack[identifierPtr--];
165         identifierLengthPtr--;
166
167         //modifiers
168         cd.declarationSourceStart = intStack[intPtr--];
169         cd.modifiers = intStack[intPtr--];
170
171         //highlight starts at the selector starts
172         cd.sourceStart = (int) (selectorSourcePositions >>> 32);
173         cd.selectorSourceEnd = (int) selectorSourcePositions;
174         pushOnAstStack(cd);
175
176         cd.sourceEnd = lParenPos;
177         cd.bodyStart = lParenPos+1;
178         listLength = 0; // initialize listLength before reading parameters/throws
179
180         // recovery
181         if (currentElement != null){
182                 lastCheckPoint = cd.bodyStart;
183                 if ((currentElement instanceof RecoveredType && lastIgnoredToken != TokenNameDOT)
184                         || cd.modifiers != 0){
185                         currentElement = currentElement.add(cd, 0);
186                         lastIgnoredToken = -1;
187                 }
188         }       
189 }
190 /**
191  *
192  * INTERNAL USE-ONLY
193  */
194 protected void consumeExitVariableWithInitialization() {
195         // ExitVariableWithInitialization ::= $empty
196         // the scanner is located after the comma or the semi-colon.
197         // we want to include the comma or the semi-colon
198         super.consumeExitVariableWithInitialization();
199         if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON)))
200                 return;
201         ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1;
202 }
203 protected void consumeExitVariableWithoutInitialization() {
204         // ExitVariableWithoutInitialization ::= $empty
205         // do nothing by default
206         if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON)))
207                 return;
208         ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1;
209 }
210 /**
211  *
212  * INTERNAL USE-ONLY
213  */
214 protected void consumeFieldAccess(boolean isSuperAccess) {
215         // FieldAccess ::= Primary '.' 'Identifier'
216         // FieldAccess ::= 'super' '.' 'Identifier'
217         super.consumeFieldAccess(isSuperAccess);
218         FieldReference fr = (FieldReference) expressionStack[expressionPtr];
219         if (reportReferenceInfo) {
220                 requestor.acceptFieldReference(fr.token, fr.sourceStart);
221         }
222 }
223 protected void consumeMethodHeaderName() {
224         // MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
225         SourceMethodDeclaration md = new SourceMethodDeclaration(this.compilationUnit.compilationResult);
226
227         //name
228         md.selector = identifierStack[identifierPtr];
229         long selectorSourcePositions = identifierPositionStack[identifierPtr--];
230         identifierLengthPtr--;
231         //type
232         md.returnType = getTypeReference(intStack[intPtr--]);
233         //modifiers
234         md.declarationSourceStart = intStack[intPtr--];
235         md.modifiers = intStack[intPtr--];
236
237         //highlight starts at selector start
238         md.sourceStart = (int) (selectorSourcePositions >>> 32);
239         md.selectorSourceEnd = (int) selectorSourcePositions;
240         pushOnAstStack(md);
241         md.sourceEnd = lParenPos;
242         md.bodyStart = lParenPos+1;
243         listLength = 0; // initialize listLength before reading parameters/throws
244         
245         // recovery
246         if (currentElement != null){
247                 if (currentElement instanceof RecoveredType 
248                         //|| md.modifiers != 0
249                         || (scanner.getLineNumber(md.returnType.sourceStart)
250                                         == scanner.getLineNumber(md.sourceStart))){
251                         lastCheckPoint = md.bodyStart;
252                         currentElement = currentElement.add(md, 0);
253                         lastIgnoredToken = -1;                  
254                 } else {
255                         lastCheckPoint = md.sourceStart;
256                         restartRecovery = true;
257                 }
258         }               
259 }
260 /**
261  *
262  * INTERNAL USE-ONLY
263  */
264 protected void consumeMethodInvocationName() {
265         // MethodInvocation ::= Name '(' ArgumentListopt ')'
266
267         // when the name is only an identifier...we have a message send to "this" (implicit)
268         super.consumeMethodInvocationName();
269         MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
270         Expression[] args = messageSend.arguments;
271         if (reportReferenceInfo) {
272                 requestor.acceptMethodReference(
273                         messageSend.selector, 
274                         args == null ? 0 : args.length, 
275                         (int)(messageSend.nameSourcePosition >>> 32));
276         }
277 }
278 /**
279  *
280  * INTERNAL USE-ONLY
281  */
282 protected void consumeMethodInvocationPrimary() {
283         super.consumeMethodInvocationPrimary();
284         MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
285         Expression[] args = messageSend.arguments;
286         if (reportReferenceInfo) {
287                 requestor.acceptMethodReference(
288                         messageSend.selector, 
289                         args == null ? 0 : args.length, 
290                         (int)(messageSend.nameSourcePosition >>> 32));
291         }
292 }
293 /**
294  *
295  * INTERNAL USE-ONLY
296  */
297 protected void consumeMethodInvocationSuper() {
298         // MethodInvocation ::= 'super' '.' 'Identifier' '(' ArgumentListopt ')'
299         super.consumeMethodInvocationSuper();
300         MessageSend messageSend = (MessageSend) expressionStack[expressionPtr];
301         Expression[] args = messageSend.arguments;
302         if (reportReferenceInfo) {
303                 requestor.acceptMethodReference(
304                         messageSend.selector, 
305                         args == null ? 0 : args.length, 
306                         (int)(messageSend.nameSourcePosition >>> 32));
307         }
308 }
309 protected void consumeSingleTypeImportDeclarationName() {
310         // SingleTypeImportDeclarationName ::= 'import' Name
311         /* push an ImportRef build from the last name 
312         stored in the identifier stack. */
313
314         super.consumeSingleTypeImportDeclarationName();
315         ImportReference impt = (ImportReference)astStack[astPtr];
316         if (reportReferenceInfo) {
317                 requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
318         }
319 }
320 protected void consumeTypeImportOnDemandDeclarationName() {
321         // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
322         /* push an ImportRef build from the last name 
323         stored in the identifier stack. */
324
325         super.consumeTypeImportOnDemandDeclarationName();
326         ImportReference impt = (ImportReference)astStack[astPtr];
327         if (reportReferenceInfo) {
328                 requestor.acceptUnknownReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
329         }
330 }
331 protected FieldDeclaration createFieldDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) {
332         return new SourceFieldDeclaration(null, name, sourceStart, sourceEnd);
333 }
334 protected CompilationUnitDeclaration endParse(int act) {
335         if (sourceType != null) {
336                 if (sourceType.isInterface()) {
337                         consumeInterfaceDeclaration();
338                 } else {
339                         consumeClassDeclaration();
340                 }
341         }
342         if (compilationUnit != null) {
343                 CompilationUnitDeclaration result = super.endParse(act);
344                 return result;
345         } else {
346                 return null;
347         }               
348 }
349 /*
350  * Flush annotations defined prior to a given positions.
351  *
352  * Note: annotations are stacked in syntactical order
353  *
354  * Either answer given <position>, or the end position of a comment line 
355  * immediately following the <position> (same line)
356  *
357  * e.g.
358  * void foo(){
359  * } // end of method foo
360  */
361  
362 public int flushAnnotationsDefinedPriorTo(int position) {
363
364         return lastFieldEndPosition = super.flushAnnotationsDefinedPriorTo(position);
365 }
366 public TypeReference getTypeReference(int dim) {
367         /* build a Reference on a variable that may be qualified or not
368          * This variable is a type reference and dim will be its dimensions
369          */
370         int length;
371         if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
372                 // single variable reference
373                 if (dim == 0) {
374                         SingleTypeReference ref = 
375                                 new SingleTypeReference(
376                                         identifierStack[identifierPtr], 
377                                         identifierPositionStack[identifierPtr--]);
378                         if (reportReferenceInfo) {
379                                 requestor.acceptTypeReference(ref.token, ref.sourceStart);
380                         }
381                         return ref;
382                 } else {
383                         ArrayTypeReference ref = 
384                                 new ArrayTypeReference(
385                                         identifierStack[identifierPtr], 
386                                         dim, 
387                                         identifierPositionStack[identifierPtr--]); 
388                         ref.sourceEnd = endPosition;
389                         if (reportReferenceInfo) {
390                                 requestor.acceptTypeReference(ref.token, ref.sourceStart);
391                         }
392                         return ref;
393                 }
394         } else {
395                 if (length < 0) { //flag for precompiled type reference on base types
396                         TypeReference ref = TypeReference.baseTypeReference(-length, dim);
397                         ref.sourceStart = intStack[intPtr--];
398                         if (dim == 0) {
399                                 ref.sourceEnd = intStack[intPtr--];
400                         } else {
401                                 intPtr--; // no need to use this position as it is an array
402                                 ref.sourceEnd = endPosition;
403                         }
404                         if (reportReferenceInfo){
405                                         requestor.acceptTypeReference(ref.getTypeName(), ref.sourceStart, ref.sourceEnd);
406                         }
407                         return ref;
408                 } else { //Qualified variable reference
409                         char[][] tokens = new char[length][];
410                         identifierPtr -= length;
411                         long[] positions = new long[length];
412                         System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
413                         System.arraycopy(
414                                 identifierPositionStack, 
415                                 identifierPtr + 1, 
416                                 positions, 
417                                 0, 
418                                 length); 
419                         if (dim == 0) {
420                                 QualifiedTypeReference ref = new QualifiedTypeReference(tokens, positions);
421                                 if (reportReferenceInfo) {
422                                         requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd);
423                                 }
424                                 return ref;
425                         } else {
426                                 ArrayQualifiedTypeReference ref = 
427                                         new ArrayQualifiedTypeReference(tokens, dim, positions); 
428                                 ref.sourceEnd = endPosition;                                    
429                                 if (reportReferenceInfo) {
430                                         requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd);
431                                 }
432                                 return ref;
433                         }
434                 }
435         }
436 }
437 public NameReference getUnspecifiedReference() {
438         /* build a (unspecified) NameReference which may be qualified*/
439
440         int length;
441         if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
442                 // single variable reference
443                 SingleNameReference ref = 
444                         new SingleNameReference(
445                                 identifierStack[identifierPtr], 
446                                 identifierPositionStack[identifierPtr--]); 
447                 if (reportReferenceInfo) {
448                         this.addUnknownRef(ref);
449                 }
450                 return ref;
451         } else {
452                 //Qualified variable reference
453                 char[][] tokens = new char[length][];
454                 identifierPtr -= length;
455                 System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
456                 QualifiedNameReference ref = 
457                         new QualifiedNameReference(
458                                 tokens, 
459                                 (int) (identifierPositionStack[identifierPtr + 1] >> 32), // sourceStart
460                                 (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
461                 if (reportReferenceInfo) {
462                         this.addUnknownRef(ref);
463                 }
464                 return ref;
465         }
466 }
467 public NameReference getUnspecifiedReferenceOptimized() {
468         /* build a (unspecified) NameReference which may be qualified
469         The optimization occurs for qualified reference while we are
470         certain in this case the last item of the qualified name is
471         a field access. This optimization is IMPORTANT while it results
472         that when a NameReference is build, the type checker should always
473         look for that it is not a type reference */
474
475         int length;
476         if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
477                 // single variable reference
478                 SingleNameReference ref = 
479                         new SingleNameReference(
480                                 identifierStack[identifierPtr], 
481                                 identifierPositionStack[identifierPtr--]); 
482                 ref.bits &= ~AstNode.RestrictiveFlagMASK;
483                 ref.bits |= LOCAL | FIELD;
484                 if (reportReferenceInfo) {
485                         this.addUnknownRef(ref);
486                 }
487                 return ref;
488         }
489
490         //Qualified-variable-reference
491         //In fact it is variable-reference DOT field-ref , but it would result in a type
492         //conflict tha can be only reduce by making a superclass (or inetrface ) between
493         //nameReference and FiledReference or putting FieldReference under NameReference
494         //or else..........This optimisation is not really relevant so just leave as it is
495
496         char[][] tokens = new char[length][];
497         identifierPtr -= length;
498         System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
499         QualifiedNameReference ref = 
500                 new QualifiedNameReference(
501                         tokens, 
502                         (int) (identifierPositionStack[identifierPtr + 1] >> 32), 
503         // sourceStart
504          (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
505         ref.bits &= ~AstNode.RestrictiveFlagMASK;
506         ref.bits |= LOCAL | FIELD;
507         if (reportReferenceInfo) {
508                 this.addUnknownRef(ref);
509         }
510         return ref;
511 }
512 /**
513  *
514  * INTERNAL USE-ONLY
515  */
516 private boolean isLocalDeclaration() {
517         int nestedDepth = nestedType;
518         while (nestedDepth >= 0) {
519                 if (nestedMethod[nestedDepth] != 0) {
520                         return true;
521                 }
522                 nestedDepth--;
523         }
524         return false;
525 }
526 /*
527  * Update the bodyStart of the corresponding parse node
528  */
529 public void notifySourceElementRequestor(CompilationUnitDeclaration parsedUnit) {
530         if (parsedUnit == null) {
531                 // when we parse a single type member declaration the compilation unit is null, but we still
532                 // want to be able to notify the requestor on the created ast node
533                 if (astStack[0] instanceof AbstractMethodDeclaration) {
534                         notifySourceElementRequestor((AbstractMethodDeclaration) astStack[0]);
535                         return;
536                 }
537                 return;
538         }
539         // range check
540         boolean isInRange = 
541                                 scanner.initialPosition <= parsedUnit.sourceStart
542                                 && scanner.eofPosition >= parsedUnit.sourceEnd;
543         
544         if (reportReferenceInfo) {
545                 notifyAllUnknownReferences();
546         }
547         // collect the top level ast nodes
548         int length = 0;
549         AstNode[] nodes = null;
550         if (sourceType == null){
551                 if (isInRange) {
552                         requestor.enterCompilationUnit();
553                 }
554                 ImportReference currentPackage = parsedUnit.currentPackage;
555                 ImportReference[] imports = parsedUnit.imports;
556                 TypeDeclaration[] types = parsedUnit.types;
557                 length = 
558                         (currentPackage == null ? 0 : 1) 
559                         + (imports == null ? 0 : imports.length)
560                         + (types == null ? 0 : types.length);
561                 nodes = new AstNode[length];
562                 int index = 0;
563                 if (currentPackage != null) {
564                         nodes[index++] = currentPackage;
565                 }
566                 if (imports != null) {
567                         for (int i = 0, max = imports.length; i < max; i++) {
568                                 nodes[index++] = imports[i];
569                         }
570                 }
571                 if (types != null) {
572                         for (int i = 0, max = types.length; i < max; i++) {
573                                 nodes[index++] = types[i];
574                         }
575                 }
576         } else {
577                 TypeDeclaration[] types = parsedUnit.types;
578                 if (types != null) {
579                         length = types.length;
580                         nodes = new AstNode[length];
581                         for (int i = 0, max = types.length; i < max; i++) {
582                                 nodes[i] = types[i];
583                         }
584                 }
585         }
586         
587         // notify the nodes in the syntactical order
588         if (nodes != null && length > 0) {
589                 quickSort(nodes, 0, length-1);
590                 for (int i=0;i<length;i++) {
591                         AstNode node = nodes[i];
592                         if (node instanceof ImportReference) {
593                                 ImportReference importRef = (ImportReference)node;
594                                 if (node == parsedUnit.currentPackage) {
595                                         notifySourceElementRequestor(importRef, true);
596                                 } else {
597                                         notifySourceElementRequestor(importRef, false);
598                                 }
599                         } else { // instanceof TypeDeclaration
600                                 notifySourceElementRequestor((TypeDeclaration)node, sourceType == null);
601                         }
602                 }
603         }
604         
605         if (sourceType == null){
606                 if (isInRange) {
607                         requestor.exitCompilationUnit(parsedUnit.sourceEnd);
608                 }
609         }
610 }
611
612 private void notifyAllUnknownReferences() {
613         for (int i = 0, max = this.unknownRefsCounter; i < max; i++) {
614                 NameReference nameRef = this.unknownRefs[i];
615                 if ((nameRef.bits & BindingIds.VARIABLE) != 0) {
616                         if ((nameRef.bits & BindingIds.TYPE) == 0) { 
617                                 // variable but not type
618                                 if (nameRef instanceof SingleNameReference) { 
619                                         // local var or field
620                                         requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
621                                 } else {
622                                         // QualifiedNameReference
623                                         // The last token is a field reference and the previous tokens are a type/variable references
624                                         char[][] tokens = ((QualifiedNameReference) nameRef).tokens;
625                                         int tokensLength = tokens.length;
626                                         requestor.acceptFieldReference(tokens[tokensLength - 1], nameRef.sourceEnd - tokens[tokensLength - 1].length + 1);
627                                         char[][] typeRef = new char[tokensLength - 1][];
628                                         System.arraycopy(tokens, 0, typeRef, 0, tokensLength - 1);
629                                         requestor.acceptUnknownReference(typeRef, nameRef.sourceStart, nameRef.sourceEnd - tokens[tokensLength - 1].length);
630                                 }
631                         } else {
632                                 // variable or type
633                                 if (nameRef instanceof SingleNameReference) {
634                                         requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
635                                 } else {
636                                         //QualifiedNameReference
637                                         requestor.acceptUnknownReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
638                                 }
639                         }
640                 } else if ((nameRef.bits & BindingIds.TYPE) != 0) {
641                         if (nameRef instanceof SingleNameReference) {
642                                 requestor.acceptTypeReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
643                         } else {
644                                 // it is a QualifiedNameReference
645                                 requestor.acceptTypeReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
646                         }
647                 }
648         }
649 }
650 /*
651  * Update the bodyStart of the corresponding parse node
652  */
653 public void notifySourceElementRequestor(AbstractMethodDeclaration methodDeclaration) {
654
655         // range check
656         boolean isInRange = 
657                                 scanner.initialPosition <= methodDeclaration.declarationSourceStart
658                                 && scanner.eofPosition >= methodDeclaration.declarationSourceEnd;
659
660         if (methodDeclaration.isClinit()) {
661                 this.visitIfNeeded(methodDeclaration);
662                 return;
663         }
664
665         if (methodDeclaration.isDefaultConstructor()) {
666                 if (reportReferenceInfo) {
667                         ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration;
668                         ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall;
669                         if (constructorCall != null) {
670                                 switch(constructorCall.accessMode) {
671                                         case ExplicitConstructorCall.This :
672                                                 requestor.acceptConstructorReference(
673                                                         typeNames[nestedTypeIndex-1],
674                                                         constructorCall.arguments == null ? 0 : constructorCall.arguments.length, 
675                                                         constructorCall.sourceStart);
676                                                 break;
677                                         case ExplicitConstructorCall.Super :
678                                         case ExplicitConstructorCall.ImplicitSuper :                                    
679                                                 requestor.acceptConstructorReference(
680                                                         superTypeNames[nestedTypeIndex-1],
681                                                         constructorCall.arguments == null ? 0 : constructorCall.arguments.length, 
682                                                         constructorCall.sourceStart);
683                                                 break;
684                                 }
685                         }
686                 }       
687                 return; 
688         }       
689         char[][] argumentTypes = null;
690         char[][] argumentNames = null;
691         Argument[] arguments = methodDeclaration.arguments;
692         if (arguments != null) {
693                 int argumentLength = arguments.length;
694                 argumentTypes = new char[argumentLength][];
695                 argumentNames = new char[argumentLength][];
696                 for (int i = 0; i < argumentLength; i++) {
697                         argumentTypes[i] = returnTypeName(arguments[i].type);
698                         argumentNames[i] = arguments[i].name;
699                 }
700         }
701         char[][] thrownExceptionTypes = null;
702         TypeReference[] thrownExceptions = methodDeclaration.thrownExceptions;
703         if (thrownExceptions != null) {
704                 int thrownExceptionLength = thrownExceptions.length;
705                 thrownExceptionTypes = new char[thrownExceptionLength][];
706                 for (int i = 0; i < thrownExceptionLength; i++) {
707                         thrownExceptionTypes[i] = 
708                                 CharOperation.concatWith(thrownExceptions[i].getTypeName(), '.'); 
709                 }
710         }
711         // by default no selector end position
712         int selectorSourceEnd = -1;
713         if (methodDeclaration.isConstructor()) {
714                 if (methodDeclaration instanceof SourceConstructorDeclaration) {
715                         selectorSourceEnd = 
716                                 ((SourceConstructorDeclaration) methodDeclaration).selectorSourceEnd; 
717                 }
718                 if (isInRange){
719                         requestor.enterConstructor(
720                                 methodDeclaration.declarationSourceStart, 
721                                 methodDeclaration.modifiers, 
722                                 methodDeclaration.selector, 
723                                 methodDeclaration.sourceStart, 
724                                 selectorSourceEnd, 
725                                 argumentTypes, 
726                                 argumentNames, 
727                                 thrownExceptionTypes);
728                 }
729                 if (reportReferenceInfo) {
730                         ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration) methodDeclaration;
731                         ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall;
732                         if (constructorCall != null) {
733                                 switch(constructorCall.accessMode) {
734                                         case ExplicitConstructorCall.This :
735                                                 requestor.acceptConstructorReference(
736                                                         typeNames[nestedTypeIndex-1],
737                                                         constructorCall.arguments == null ? 0 : constructorCall.arguments.length, 
738                                                         constructorCall.sourceStart);
739                                                 break;
740                                         case ExplicitConstructorCall.Super :
741                                         case ExplicitConstructorCall.ImplicitSuper :
742                                                 requestor.acceptConstructorReference(
743                                                         superTypeNames[nestedTypeIndex-1],
744                                                         constructorCall.arguments == null ? 0 : constructorCall.arguments.length, 
745                                                         constructorCall.sourceStart);
746                                                 break;
747                                 }
748                         }
749                 }
750                 this.visitIfNeeded(methodDeclaration);
751                 if (isInRange){
752                         requestor.exitConstructor(methodDeclaration.declarationSourceEnd);
753                 }
754                 return;
755         }
756         if (methodDeclaration instanceof SourceMethodDeclaration) {
757                 selectorSourceEnd = 
758                         ((SourceMethodDeclaration) methodDeclaration).selectorSourceEnd; 
759         }
760         if (isInRange){
761                 requestor.enterMethod(
762                         methodDeclaration.declarationSourceStart, 
763                         methodDeclaration.modifiers & AccJustFlag, 
764                         returnTypeName(((MethodDeclaration) methodDeclaration).returnType), 
765                         methodDeclaration.selector, 
766                         methodDeclaration.sourceStart, 
767                         selectorSourceEnd, 
768                         argumentTypes, 
769                         argumentNames, 
770                         thrownExceptionTypes); 
771         }               
772         this.visitIfNeeded(methodDeclaration);
773
774         if (isInRange){ 
775                 requestor.exitMethod(methodDeclaration.declarationSourceEnd);
776         }
777 }
778 /*
779 * Update the bodyStart of the corresponding parse node
780 */
781 public void notifySourceElementRequestor(FieldDeclaration fieldDeclaration) {
782         
783         // range check
784         boolean isInRange = 
785                                 scanner.initialPosition <= fieldDeclaration.declarationSourceStart
786                                 && scanner.eofPosition >= fieldDeclaration.declarationSourceEnd;
787
788         if (fieldDeclaration.isField()) {
789                 int fieldEndPosition = fieldDeclaration.declarationSourceEnd;
790                 if (fieldDeclaration instanceof SourceFieldDeclaration) {
791                         fieldEndPosition = ((SourceFieldDeclaration) fieldDeclaration).fieldEndPosition;
792                         if (fieldEndPosition == 0) {
793                                 // use the declaration source end by default
794                                 fieldEndPosition = fieldDeclaration.declarationSourceEnd;
795                         }
796                 }
797                 if (isInRange) {
798                         requestor.enterField(
799                                 fieldDeclaration.declarationSourceStart, 
800                                 fieldDeclaration.modifiers & AccJustFlag, 
801                                 returnTypeName(fieldDeclaration.type), 
802                                 fieldDeclaration.name, 
803                                 fieldDeclaration.sourceStart, 
804                                 fieldDeclaration.sourceEnd); 
805                 }
806                 this.visitIfNeeded(fieldDeclaration);
807                 if (isInRange){
808                         requestor.exitField(fieldEndPosition);
809                 }
810
811         } else {
812                 if (isInRange){
813                         requestor.enterInitializer(
814                                 fieldDeclaration.declarationSourceStart,
815                                 fieldDeclaration.modifiers); 
816                 }
817                 this.visitIfNeeded((Initializer)fieldDeclaration);
818                 if (isInRange){
819                         requestor.exitInitializer(fieldDeclaration.declarationSourceEnd);
820                 }
821         }
822 }
823 public void notifySourceElementRequestor(
824         ImportReference importReference, 
825         boolean isPackage) {
826         if (isPackage) {
827                 requestor.acceptPackage(
828                         importReference.declarationSourceStart, 
829                         importReference.declarationSourceEnd, 
830                         CharOperation.concatWith(importReference.getImportName(), '.')); 
831         } else {
832                 requestor.acceptImport(
833                         importReference.declarationSourceStart, 
834                         importReference.declarationSourceEnd, 
835                         CharOperation.concatWith(importReference.getImportName(), '.'), 
836                         importReference.onDemand); 
837         }
838 }
839 public void notifySourceElementRequestor(TypeDeclaration typeDeclaration, boolean notifyTypePresence) {
840         
841         // range check
842         boolean isInRange = 
843                                 scanner.initialPosition <= typeDeclaration.declarationSourceStart
844                                 && scanner.eofPosition >= typeDeclaration.declarationSourceEnd;
845         
846         FieldDeclaration[] fields = typeDeclaration.fields;
847         AbstractMethodDeclaration[] methods = typeDeclaration.methods;
848         MemberTypeDeclaration[] memberTypes = typeDeclaration.memberTypes;
849         int fieldCount = fields == null ? 0 : fields.length;
850         int methodCount = methods == null ? 0 : methods.length;
851         int memberTypeCount = memberTypes == null ? 0 : memberTypes.length;
852         int fieldIndex = 0;
853         int methodIndex = 0;
854         int memberTypeIndex = 0;
855         boolean isInterface = typeDeclaration.isInterface();
856
857         if (notifyTypePresence){
858                 char[][] interfaceNames = null;
859                 int superInterfacesLength = 0;
860                 TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
861                 if (superInterfaces != null) {
862                         superInterfacesLength = superInterfaces.length;
863                         interfaceNames = new char[superInterfacesLength][];
864                 } else {
865                         if (typeDeclaration instanceof AnonymousLocalTypeDeclaration) {
866                                 // see PR 3442
867                                 QualifiedAllocationExpression alloc = ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation;
868                                 if (alloc != null && alloc.type != null) {
869                                         superInterfaces = new TypeReference[] { ((AnonymousLocalTypeDeclaration)typeDeclaration).allocation.type};
870                                         superInterfacesLength = 1;
871                                         interfaceNames = new char[1][];
872                                 }
873                         }
874                 }
875                 if (superInterfaces != null) {
876                         for (int i = 0; i < superInterfacesLength; i++) {
877                                 interfaceNames[i] = 
878                                         CharOperation.concatWith(superInterfaces[i].getTypeName(), '.'); 
879                         }
880                 }
881                 if (isInterface) {
882                         if (isInRange){
883                                 requestor.enterInterface(
884                                         typeDeclaration.declarationSourceStart, 
885                                         typeDeclaration.modifiers & AccJustFlag, 
886                                         typeDeclaration.name, 
887                                         typeDeclaration.sourceStart, 
888                                         typeDeclaration.sourceEnd, 
889                                         interfaceNames);
890                         }
891                         if (nestedTypeIndex == typeNames.length) {
892                                 // need a resize
893                                 System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
894                                 System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
895                         }
896                         typeNames[nestedTypeIndex] = typeDeclaration.name;
897                         superTypeNames[nestedTypeIndex++] = JAVA_LANG_OBJECT;
898                 } else {
899                         TypeReference superclass = typeDeclaration.superclass;
900                         if (superclass == null) {
901                                 if (isInRange){
902                                         requestor.enterClass(
903                                                 typeDeclaration.declarationSourceStart, 
904                                                 typeDeclaration.modifiers, 
905                                                 typeDeclaration.name, 
906                                                 typeDeclaration.sourceStart, 
907                                                 typeDeclaration.sourceEnd, 
908                                                 null, 
909                                                 interfaceNames); 
910                                 }
911                         } else {
912                                 if (isInRange){
913                                         requestor.enterClass(
914                                                 typeDeclaration.declarationSourceStart, 
915                                                 typeDeclaration.modifiers, 
916                                                 typeDeclaration.name, 
917                                                 typeDeclaration.sourceStart, 
918                                                 typeDeclaration.sourceEnd, 
919                                                 CharOperation.concatWith(superclass.getTypeName(), '.'), 
920                                                 interfaceNames); 
921                                 }
922                         }
923                         if (nestedTypeIndex == typeNames.length) {
924                                 // need a resize
925                                 System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
926                                 System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
927                         }
928                         typeNames[nestedTypeIndex] = typeDeclaration.name;
929                         superTypeNames[nestedTypeIndex++] = superclass == null ? JAVA_LANG_OBJECT : CharOperation.concatWith(superclass.getTypeName(), '.');
930                 }
931         }
932         while ((fieldIndex < fieldCount)
933                 || (memberTypeIndex < memberTypeCount)
934                 || (methodIndex < methodCount)) {
935                 FieldDeclaration nextFieldDeclaration = null;
936                 AbstractMethodDeclaration nextMethodDeclaration = null;
937                 TypeDeclaration nextMemberDeclaration = null;
938
939                 int position = Integer.MAX_VALUE;
940                 int nextDeclarationType = -1;
941                 if (fieldIndex < fieldCount) {
942                         nextFieldDeclaration = fields[fieldIndex];
943                         if (nextFieldDeclaration.declarationSourceStart < position) {
944                                 position = nextFieldDeclaration.declarationSourceStart;
945                                 nextDeclarationType = 0; // FIELD
946                         }
947                 }
948                 if (methodIndex < methodCount) {
949                         nextMethodDeclaration = methods[methodIndex];
950                         if (nextMethodDeclaration.declarationSourceStart < position) {
951                                 position = nextMethodDeclaration.declarationSourceStart;
952                                 nextDeclarationType = 1; // METHOD
953                         }
954                 }
955                 if (memberTypeIndex < memberTypeCount) {
956                         nextMemberDeclaration = memberTypes[memberTypeIndex];
957                         if (nextMemberDeclaration.declarationSourceStart < position) {
958                                 position = nextMemberDeclaration.declarationSourceStart;
959                                 nextDeclarationType = 2; // MEMBER
960                         }
961                 }
962                 switch (nextDeclarationType) {
963                         case 0 :
964                                 fieldIndex++;
965                                 notifySourceElementRequestor(nextFieldDeclaration);
966                                 break;
967                         case 1 :
968                                 methodIndex++;
969                                 notifySourceElementRequestor(nextMethodDeclaration);
970                                 break;
971                         case 2 :
972                                 memberTypeIndex++;
973                                 notifySourceElementRequestor(nextMemberDeclaration, true);
974                 }
975         }
976         if (notifyTypePresence){
977                 if (isInRange){
978                         if (isInterface) {
979                                 requestor.exitInterface(typeDeclaration.declarationSourceEnd);
980                         } else {
981                                 requestor.exitClass(typeDeclaration.declarationSourceEnd);
982                         }
983                 }
984                 nestedTypeIndex--;
985         }
986 }
987 public void parseCompilationUnit(
988         ICompilationUnit unit, 
989         int start, 
990         int end, 
991         boolean needReferenceInfo) {
992
993         reportReferenceInfo = needReferenceInfo;
994         boolean old = diet;
995         if (needReferenceInfo) {
996                 unknownRefs = new NameReference[10];
997                 unknownRefsCounter = 0;
998         }
999         try {
1000                 diet = true;
1001                 CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit);
1002                 CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, start, end);
1003                 if (needReferenceInfo){
1004                         diet = false;
1005                         this.getMethodBodies(parsedUnit);
1006                 }               
1007                 this.scanner.resetTo(start, end);
1008                 notifySourceElementRequestor(parsedUnit);
1009         } catch (AbortCompilation e) {
1010         } finally {
1011                 if (scanner.recordLineSeparator) {
1012                         requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
1013                 }
1014                 diet = old;
1015         }
1016 }
1017 public void parseCompilationUnit(
1018         ICompilationUnit unit, 
1019         boolean needReferenceInfo) {
1020         boolean old = diet;
1021         if (needReferenceInfo) {
1022                 unknownRefs = new NameReference[10];
1023                 unknownRefsCounter = 0;
1024         }
1025                 
1026         try {
1027 /*              diet = !needReferenceInfo;
1028                 reportReferenceInfo = needReferenceInfo;
1029                 CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0);
1030                 parse(unit, compilationUnitResult);             
1031 */              diet = true;
1032                 reportReferenceInfo = needReferenceInfo;
1033                 CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit);
1034                 CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult);
1035                 int initialStart = this.scanner.initialPosition;
1036                 int initialEnd = this.scanner.eofPosition;
1037                 if (needReferenceInfo){
1038                         diet = false;
1039                         this.getMethodBodies(parsedUnit);
1040                 }
1041                 this.scanner.resetTo(initialStart, initialEnd);
1042                 notifySourceElementRequestor(parsedUnit);
1043         } catch (AbortCompilation e) {
1044         } finally {
1045                 if (scanner.recordLineSeparator) {
1046                         requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
1047                 }
1048                 diet = old;
1049         }
1050 }
1051 public void parseTypeMemberDeclarations(
1052         ISourceType sourceType, 
1053         ICompilationUnit sourceUnit, 
1054         int start, 
1055         int end, 
1056         boolean needReferenceInfo) {
1057         boolean old = diet;
1058         if (needReferenceInfo) {
1059                 unknownRefs = new NameReference[10];
1060                 unknownRefsCounter = 0;
1061         }
1062         
1063         try {
1064                 diet = !needReferenceInfo;
1065                 reportReferenceInfo = needReferenceInfo;
1066                 CompilationResult compilationUnitResult = 
1067                         new CompilationResult(sourceUnit, 0, 0, this.options.maxProblemsPerUnit); 
1068                 CompilationUnitDeclaration unit = 
1069                         SourceTypeConverter.buildCompilationUnit(
1070                                 new ISourceType[]{sourceType}, 
1071                                 false,
1072                                 false, 
1073                                 problemReporter(), 
1074                                 compilationUnitResult); 
1075                 if ((unit == null) || (unit.types == null) || (unit.types.length != 1))
1076                         return;
1077                 this.sourceType = sourceType;
1078                 try {
1079                         /* automaton initialization */
1080                         initialize();
1081                         goForClassBodyDeclarations();
1082                         /* scanner initialization */
1083                         scanner.setSource(sourceUnit.getContents());
1084                         scanner.resetTo(start, end);
1085                         /* unit creation */
1086                         referenceContext = compilationUnit = unit;
1087                         /* initialize the astStacl */
1088                         // the compilationUnitDeclaration should contain exactly one type
1089                         pushOnAstStack(unit.types[0]);
1090                         /* run automaton */
1091                         parse();
1092                         notifySourceElementRequestor(unit);
1093                 } finally {
1094                         unit = compilationUnit;
1095                         compilationUnit = null; // reset parser
1096                 }
1097         } catch (AbortCompilation e) {
1098         } finally {
1099                 if (scanner.recordLineSeparator) {
1100                         requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
1101                 }
1102                 diet = old;
1103         }
1104 }
1105
1106 public void parseTypeMemberDeclarations(
1107         char[] contents, 
1108         int start, 
1109         int end) {
1110
1111         boolean old = diet;
1112         
1113         try {
1114                 diet = true;
1115
1116                 /* automaton initialization */
1117                 initialize();
1118                 goForClassBodyDeclarations();
1119                 /* scanner initialization */
1120                 scanner.setSource(contents);
1121                 scanner.recordLineSeparator = false;
1122                 scanner.resetTo(start, end);
1123
1124                 /* unit creation */
1125                 referenceContext = null;
1126
1127                 /* initialize the astStacl */
1128                 // the compilationUnitDeclaration should contain exactly one type
1129                 /* run automaton */
1130                 parse();
1131                 notifySourceElementRequestor((CompilationUnitDeclaration)null);
1132         } catch (AbortCompilation e) {
1133         } finally {
1134                 diet = old;
1135         }
1136 }
1137 /**
1138  * Sort the given ast nodes by their positions.
1139  */
1140 private static void quickSort(AstNode[] sortedCollection, int left, int right) {
1141         int original_left = left;
1142         int original_right = right;
1143         AstNode mid = sortedCollection[ (left + right) / 2];
1144         do {
1145                 while (sortedCollection[left].sourceStart < mid.sourceStart) {
1146                         left++;
1147                 }
1148                 while (mid.sourceStart < sortedCollection[right].sourceStart) {
1149                         right--;
1150                 }
1151                 if (left <= right) {
1152                         AstNode tmp = sortedCollection[left];
1153                         sortedCollection[left] = sortedCollection[right];
1154                         sortedCollection[right] = tmp;
1155                         left++;
1156                         right--;
1157                 }
1158         } while (left <= right);
1159         if (original_left < right) {
1160                 quickSort(sortedCollection, original_left, right);
1161         }
1162         if (left < original_right) {
1163                 quickSort(sortedCollection, left, original_right);
1164         }
1165 }
1166 /*
1167  * Answer a char array representation of the type name formatted like:
1168  * - type name + dimensions
1169  * Example:
1170  * "A[][]".toCharArray()
1171  * "java.lang.String".toCharArray()
1172  */
1173 private char[] returnTypeName(TypeReference type) {
1174         if (type == null)
1175                 return null;
1176         int dimension = type.dimensions();
1177         if (dimension != 0) {
1178                 char[] dimensionsArray = new char[dimension * 2];
1179                 for (int i = 0; i < dimension; i++) {
1180                         dimensionsArray[i * 2] = '[';
1181                         dimensionsArray[(i * 2) + 1] = ']';
1182                 }
1183                 return CharOperation.concat(
1184                         CharOperation.concatWith(type.getTypeName(), '.'), 
1185                         dimensionsArray); 
1186         }
1187         return CharOperation.concatWith(type.getTypeName(), '.');
1188 }
1189
1190 public void addUnknownRef(NameReference nameRef) {
1191         if (this.unknownRefs.length == this.unknownRefsCounter) {
1192                 // resize
1193                 System.arraycopy(
1194                         this.unknownRefs,
1195                         0,
1196                         (this.unknownRefs = new NameReference[this.unknownRefsCounter * 2]),
1197                         0,
1198                         this.unknownRefsCounter);
1199         }
1200         this.unknownRefs[this.unknownRefsCounter++] = nameRef;
1201 }
1202 private TypeReference typeReference(
1203         int dim, 
1204         int localIdentifierPtr, 
1205         int localIdentifierLengthPtr) {
1206         /* build a Reference on a variable that may be qualified or not
1207          * This variable is a type reference and dim will be its dimensions.
1208          * We don't have any side effect on the stacks' pointers.
1209          */
1210
1211         int length;
1212         TypeReference ref;
1213         if ((length = identifierLengthStack[localIdentifierLengthPtr]) == 1) {
1214                 // single variable reference
1215                 if (dim == 0) {
1216                         ref = 
1217                                 new SingleTypeReference(
1218                                         identifierStack[localIdentifierPtr], 
1219                                         identifierPositionStack[localIdentifierPtr--]); 
1220                 } else {
1221                         ref = 
1222                                 new ArrayTypeReference(
1223                                         identifierStack[localIdentifierPtr], 
1224                                         dim, 
1225                                         identifierPositionStack[localIdentifierPtr--]);
1226                         ref.sourceEnd = endPosition;                     
1227                 }
1228         } else {
1229                 if (length < 0) { //flag for precompiled type reference on base types
1230                         ref = TypeReference.baseTypeReference(-length, dim);
1231                         ref.sourceStart = intStack[localIntPtr--];
1232                         if (dim == 0) {
1233                                 ref.sourceEnd = intStack[localIntPtr--];
1234                         } else {
1235                                 localIntPtr--;
1236                                 ref.sourceEnd = endPosition;
1237                         }       
1238                 } else { //Qualified variable reference
1239                         char[][] tokens = new char[length][];
1240                         localIdentifierPtr -= length;
1241                         long[] positions = new long[length];
1242                         System.arraycopy(identifierStack, localIdentifierPtr + 1, tokens, 0, length);
1243                         System.arraycopy(
1244                                 identifierPositionStack, 
1245                                 localIdentifierPtr + 1, 
1246                                 positions, 
1247                                 0, 
1248                                 length); 
1249                         if (dim == 0)  {
1250                                 ref = new QualifiedTypeReference(tokens, positions);
1251                         } else {
1252                                 ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
1253                                 ref.sourceEnd = endPosition;
1254                         }
1255                 }
1256         };
1257         return ref;
1258 }
1259
1260 private void visitIfNeeded(AbstractMethodDeclaration method) {
1261         if (this.localDeclarationVisitor != null 
1262                 && (method.bits & AstNode.HasLocalTypeMASK) != 0) {
1263                         if (method.statements != null) {
1264                                 int statementsLength = method.statements.length;
1265                                 for (int i = 0; i < statementsLength; i++)
1266                                         method.statements[i].traverse(this.localDeclarationVisitor, method.scope);
1267                         }
1268         }
1269 }
1270
1271 private void visitIfNeeded(FieldDeclaration field) {
1272         if (this.localDeclarationVisitor != null 
1273                 && (field.bits & AstNode.HasLocalTypeMASK) != 0) {
1274                         if (field.initialization != null) {
1275                                 field.initialization.traverse(this.localDeclarationVisitor, null);
1276                         }
1277         }
1278 }
1279
1280 private void visitIfNeeded(Initializer initializer) {
1281         if (this.localDeclarationVisitor != null 
1282                 && (initializer.bits & AstNode.HasLocalTypeMASK) != 0) {
1283                         if (initializer.block != null) {
1284                                 initializer.block.traverse(this.localDeclarationVisitor, null);
1285                         }
1286         }
1287 }
1288
1289 protected void reportSyntaxError(int act, int currentKind, int stateStackTop) {
1290         if (compilationUnit == null) return;
1291         super.reportSyntaxError(act, currentKind,stateStackTop);
1292 }
1293
1294 }