7902369ed0adbba8b94bf146dad69313b8eb3d44
[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.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;
76
77 public class SourceElementParser extends Parser {
78         
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;
93         
94 /**
95  * An ast visitor that visits local type declarations.
96  */
97 public class LocalDeclarationVisitor extends AbstractSyntaxTreeVisitorAdapter {
98         public boolean visit(
99                         AnonymousLocalTypeDeclaration anonymousTypeDeclaration,
100                         BlockScope scope) {
101                 notifySourceElementRequestor(anonymousTypeDeclaration, sourceType == null);
102                 return false; // don't visit members as this was done during notifySourceElementRequestor(...)
103         }
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(...)
107         }
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(...)
111         }
112         
113 }
114
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(),
123                 options, 
124                 problemFactory) {
125                 public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) {
126                         unitResult.record(problem, referenceContext);
127                         requestor.acceptProblem(problem);
128                 }
129         },
130         true,
131         options.assertMode);
132         this.requestor = requestor;
133         typeNames = new char[4][];
134         superTypeNames = new char[4][];
135         nestedTypeIndex = 0;
136         this.options = options;
137 }
138
139 /** @deprecated use SourceElementParser(ISourceElementRequestor, IProblemFactory, CompilerOptions) */
140 public SourceElementParser(
141         final ISourceElementRequestor requestor, 
142         IProblemFactory problemFactory) {
143                 this(requestor, problemFactory, new CompilerOptions());
144 }
145
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();
154                 }
155 }
156
157 public void checkAnnotation() {
158         int firstCommentIndex = scanner.commentPtr;
159
160         super.checkAnnotation();
161
162         // modify the modifier source start to point at the first comment
163         if (firstCommentIndex >= 0) {
164                 modifiersSourceStart = scanner.commentStarts[0]; 
165         }
166 }
167
168 protected void classInstanceCreation(boolean alwaysQualified) {
169
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, 
182                         alloc.sourceStart);
183         }
184 }
185 protected void consumeConstructorHeaderName() {
186         // ConstructorHeaderName ::=  Modifiersopt 'Identifier' '('
187
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;
193                         return;
194                 }
195         }
196         SourceConstructorDeclaration cd = new SourceConstructorDeclaration(this.compilationUnit.compilationResult);
197
198         //name -- this is not really revelant but we do .....
199         cd.selector = identifierStack[identifierPtr];
200         long selectorSourcePositions = identifierPositionStack[identifierPtr--];
201         identifierLengthPtr--;
202
203         //modifiers
204         cd.declarationSourceStart = intStack[intPtr--];
205         cd.modifiers = intStack[intPtr--];
206
207         //highlight starts at the selector starts
208         cd.sourceStart = (int) (selectorSourcePositions >>> 32);
209         cd.selectorSourceEnd = (int) selectorSourcePositions;
210         pushOnAstStack(cd);
211
212         cd.sourceEnd = lParenPos;
213         cd.bodyStart = lParenPos+1;
214         listLength = 0; // initialize listLength before reading parameters/throws
215
216         // recovery
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;
223                 }
224         }       
225 }
226 /**
227  *
228  * INTERNAL USE-ONLY
229  */
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)))
236                 return;
237         ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1;
238 }
239 protected void consumeExitVariableWithoutInitialization() {
240         // ExitVariableWithoutInitialization ::= $empty
241         // do nothing by default
242         if (isLocalDeclaration() || ((currentToken != TokenNameCOMMA) && (currentToken != TokenNameSEMICOLON)))
243                 return;
244         ((SourceFieldDeclaration) astStack[astPtr]).fieldEndPosition = scanner.currentPosition - 1;
245 }
246 /**
247  *
248  * INTERNAL USE-ONLY
249  */
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);
257         }
258 }
259 protected void consumeMethodHeaderName() {
260         // MethodHeaderName ::= Modifiersopt Type 'Identifier' '('
261         SourceMethodDeclaration md = new SourceMethodDeclaration(this.compilationUnit.compilationResult);
262
263         //name
264         md.selector = identifierStack[identifierPtr];
265         long selectorSourcePositions = identifierPositionStack[identifierPtr--];
266         identifierLengthPtr--;
267         //type
268         md.returnType = getTypeReference(intStack[intPtr--]);
269         //modifiers
270         md.declarationSourceStart = intStack[intPtr--];
271         md.modifiers = intStack[intPtr--];
272
273         //highlight starts at selector start
274         md.sourceStart = (int) (selectorSourcePositions >>> 32);
275         md.selectorSourceEnd = (int) selectorSourcePositions;
276         pushOnAstStack(md);
277         md.sourceEnd = lParenPos;
278         md.bodyStart = lParenPos+1;
279         listLength = 0; // initialize listLength before reading parameters/throws
280         
281         // recovery
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;                  
290                 } else {
291                         lastCheckPoint = md.sourceStart;
292                         restartRecovery = true;
293                 }
294         }               
295 }
296 /**
297  *
298  * INTERNAL USE-ONLY
299  */
300 protected void consumeMethodInvocationName() {
301         // MethodInvocation ::= Name '(' ArgumentListopt ')'
302
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));
312         }
313 }
314 /**
315  *
316  * INTERNAL USE-ONLY
317  */
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));
327         }
328 }
329 /**
330  *
331  * INTERNAL USE-ONLY
332  */
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));
343         }
344 }
345 protected void consumeSingleTypeImportDeclarationName() {
346         // SingleTypeImportDeclarationName ::= 'import' Name
347         /* push an ImportRef build from the last name 
348         stored in the identifier stack. */
349
350         super.consumeSingleTypeImportDeclarationName();
351         ImportReference impt = (ImportReference)astStack[astPtr];
352         if (reportReferenceInfo) {
353                 requestor.acceptTypeReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
354         }
355 }
356 protected void consumeTypeImportOnDemandDeclarationName() {
357         // TypeImportOnDemandDeclarationName ::= 'import' Name '.' '*'
358         /* push an ImportRef build from the last name 
359         stored in the identifier stack. */
360
361         super.consumeTypeImportOnDemandDeclarationName();
362         ImportReference impt = (ImportReference)astStack[astPtr];
363         if (reportReferenceInfo) {
364                 requestor.acceptUnknownReference(impt.tokens, impt.sourceStart, impt.sourceEnd);
365         }
366 }
367 protected FieldDeclaration createFieldDeclaration(Expression initialization, char[] name, int sourceStart, int sourceEnd) {
368         return new SourceFieldDeclaration(null, name, sourceStart, sourceEnd);
369 }
370 protected CompilationUnitDeclaration endParse(int act) {
371         if (sourceType != null) {
372                 if (sourceType.isInterface()) {
373                         consumeInterfaceDeclaration();
374                 } else {
375                         consumeClassDeclaration();
376                 }
377         }
378         if (compilationUnit != null) {
379                 CompilationUnitDeclaration result = super.endParse(act);
380                 return result;
381         } else {
382                 return null;
383         }               
384 }
385 /*
386  * Flush annotations defined prior to a given positions.
387  *
388  * Note: annotations are stacked in syntactical order
389  *
390  * Either answer given <position>, or the end position of a comment line 
391  * immediately following the <position> (same line)
392  *
393  * e.g.
394  * void foo(){
395  * } // end of method foo
396  */
397  
398 public int flushAnnotationsDefinedPriorTo(int position) {
399
400         return lastFieldEndPosition = super.flushAnnotationsDefinedPriorTo(position);
401 }
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
405          */
406         int length;
407         if ((length = identifierLengthStack[identifierLengthPtr--]) == 1) {
408                 // single variable reference
409                 if (dim == 0) {
410                         SingleTypeReference ref = 
411                                 new SingleTypeReference(
412                                         identifierStack[identifierPtr], 
413                                         identifierPositionStack[identifierPtr--]);
414                         if (reportReferenceInfo) {
415                                 requestor.acceptTypeReference(ref.token, ref.sourceStart);
416                         }
417                         return ref;
418                 } else {
419                         ArrayTypeReference ref = 
420                                 new ArrayTypeReference(
421                                         identifierStack[identifierPtr], 
422                                         dim, 
423                                         identifierPositionStack[identifierPtr--]); 
424                         ref.sourceEnd = endPosition;
425                         if (reportReferenceInfo) {
426                                 requestor.acceptTypeReference(ref.token, ref.sourceStart);
427                         }
428                         return ref;
429                 }
430         } else {
431                 if (length < 0) { //flag for precompiled type reference on base types
432                         TypeReference ref = TypeReference.baseTypeReference(-length, dim);
433                         ref.sourceStart = intStack[intPtr--];
434                         if (dim == 0) {
435                                 ref.sourceEnd = intStack[intPtr--];
436                         } else {
437                                 intPtr--; // no need to use this position as it is an array
438                                 ref.sourceEnd = endPosition;
439                         }
440                         if (reportReferenceInfo){
441                                         requestor.acceptTypeReference(ref.getTypeName(), ref.sourceStart, ref.sourceEnd);
442                         }
443                         return ref;
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);
449                         System.arraycopy(
450                                 identifierPositionStack, 
451                                 identifierPtr + 1, 
452                                 positions, 
453                                 0, 
454                                 length); 
455                         if (dim == 0) {
456                                 QualifiedTypeReference ref = new QualifiedTypeReference(tokens, positions);
457                                 if (reportReferenceInfo) {
458                                         requestor.acceptTypeReference(ref.tokens, ref.sourceStart, ref.sourceEnd);
459                                 }
460                                 return ref;
461                         } else {
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);
467                                 }
468                                 return ref;
469                         }
470                 }
471         }
472 }
473 public NameReference getUnspecifiedReference() {
474         /* build a (unspecified) NameReference which may be qualified*/
475
476         int length;
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);
485                 }
486                 return ref;
487         } else {
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(
494                                 tokens, 
495                                 (int) (identifierPositionStack[identifierPtr + 1] >> 32), // sourceStart
496                                 (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
497                 if (reportReferenceInfo) {
498                         this.addUnknownRef(ref);
499                 }
500                 return ref;
501         }
502 }
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 */
510
511         int length;
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);
522                 }
523                 return ref;
524         }
525
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
531
532         char[][] tokens = new char[length][];
533         identifierPtr -= length;
534         System.arraycopy(identifierStack, identifierPtr + 1, tokens, 0, length);
535         QualifiedNameReference ref = 
536                 new QualifiedNameReference(
537                         tokens, 
538                         (int) (identifierPositionStack[identifierPtr + 1] >> 32), 
539         // sourceStart
540          (int) identifierPositionStack[identifierPtr + length]); // sourceEnd
541         ref.bits &= ~AstNode.RestrictiveFlagMASK;
542         ref.bits |= LOCAL | FIELD;
543         if (reportReferenceInfo) {
544                 this.addUnknownRef(ref);
545         }
546         return ref;
547 }
548 /**
549  *
550  * INTERNAL USE-ONLY
551  */
552 private boolean isLocalDeclaration() {
553         int nestedDepth = nestedType;
554         while (nestedDepth >= 0) {
555                 if (nestedMethod[nestedDepth] != 0) {
556                         return true;
557                 }
558                 nestedDepth--;
559         }
560         return false;
561 }
562 /*
563  * Update the bodyStart of the corresponding parse node
564  */
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]);
571                         return;
572                 }
573                 return;
574         }
575         // range check
576         boolean isInRange = 
577                                 scanner.initialPosition <= parsedUnit.sourceStart
578                                 && scanner.eofPosition >= parsedUnit.sourceEnd;
579         
580         if (reportReferenceInfo) {
581                 notifyAllUnknownReferences();
582         }
583         // collect the top level ast nodes
584         int length = 0;
585         AstNode[] nodes = null;
586         if (sourceType == null){
587                 if (isInRange) {
588                         requestor.enterCompilationUnit();
589                 }
590                 ImportReference currentPackage = parsedUnit.currentPackage;
591                 ImportReference[] imports = parsedUnit.imports;
592                 TypeDeclaration[] types = parsedUnit.types;
593                 length = 
594                         (currentPackage == null ? 0 : 1) 
595                         + (imports == null ? 0 : imports.length)
596                         + (types == null ? 0 : types.length);
597                 nodes = new AstNode[length];
598                 int index = 0;
599                 if (currentPackage != null) {
600                         nodes[index++] = currentPackage;
601                 }
602                 if (imports != null) {
603                         for (int i = 0, max = imports.length; i < max; i++) {
604                                 nodes[index++] = imports[i];
605                         }
606                 }
607                 if (types != null) {
608                         for (int i = 0, max = types.length; i < max; i++) {
609                                 nodes[index++] = types[i];
610                         }
611                 }
612         } else {
613                 TypeDeclaration[] types = parsedUnit.types;
614                 if (types != null) {
615                         length = types.length;
616                         nodes = new AstNode[length];
617                         for (int i = 0, max = types.length; i < max; i++) {
618                                 nodes[i] = types[i];
619                         }
620                 }
621         }
622         
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);
632                                 } else {
633                                         notifySourceElementRequestor(importRef, false);
634                                 }
635                         } else { // instanceof TypeDeclaration
636                                 notifySourceElementRequestor((TypeDeclaration)node, sourceType == null);
637                         }
638                 }
639         }
640         
641         if (sourceType == null){
642                 if (isInRange) {
643                         requestor.exitCompilationUnit(parsedUnit.sourceEnd);
644                 }
645         }
646 }
647
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);
657                                 } else {
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);
666                                 }
667                         } else {
668                                 // variable or type
669                                 if (nameRef instanceof SingleNameReference) {
670                                         requestor.acceptUnknownReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
671                                 } else {
672                                         //QualifiedNameReference
673                                         requestor.acceptUnknownReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
674                                 }
675                         }
676                 } else if ((nameRef.bits & BindingIds.TYPE) != 0) {
677                         if (nameRef instanceof SingleNameReference) {
678                                 requestor.acceptTypeReference(((SingleNameReference) nameRef).token, nameRef.sourceStart);
679                         } else {
680                                 // it is a QualifiedNameReference
681                                 requestor.acceptTypeReference(((QualifiedNameReference) nameRef).tokens, nameRef.sourceStart, nameRef.sourceEnd);
682                         }
683                 }
684         }
685 }
686 /*
687  * Update the bodyStart of the corresponding parse node
688  */
689 public void notifySourceElementRequestor(AbstractMethodDeclaration methodDeclaration) {
690
691         // range check
692         boolean isInRange = 
693                                 scanner.initialPosition <= methodDeclaration.declarationSourceStart
694                                 && scanner.eofPosition >= methodDeclaration.declarationSourceEnd;
695
696         if (methodDeclaration.isClinit()) {
697                 this.visitIfNeeded(methodDeclaration);
698                 return;
699         }
700
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);
712                                                 break;
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);
719                                                 break;
720                                 }
721                         }
722                 }       
723                 return; 
724         }       
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;
735                 }
736         }
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(), '.'); 
745                 }
746         }
747         // by default no selector end position
748         int selectorSourceEnd = -1;
749         if (methodDeclaration.isConstructor()) {
750                 if (methodDeclaration instanceof SourceConstructorDeclaration) {
751                         selectorSourceEnd = 
752                                 ((SourceConstructorDeclaration) methodDeclaration).selectorSourceEnd; 
753                 }
754                 if (isInRange){
755                         requestor.enterConstructor(
756                                 methodDeclaration.declarationSourceStart, 
757                                 methodDeclaration.modifiers, 
758                                 methodDeclaration.selector, 
759                                 methodDeclaration.sourceStart, 
760                                 selectorSourceEnd, 
761                                 argumentTypes, 
762                                 argumentNames, 
763                                 thrownExceptionTypes);
764                 }
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);
775                                                 break;
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);
782                                                 break;
783                                 }
784                         }
785                 }
786                 this.visitIfNeeded(methodDeclaration);
787                 if (isInRange){
788                         requestor.exitConstructor(methodDeclaration.declarationSourceEnd);
789                 }
790                 return;
791         }
792         if (methodDeclaration instanceof SourceMethodDeclaration) {
793                 selectorSourceEnd = 
794                         ((SourceMethodDeclaration) methodDeclaration).selectorSourceEnd; 
795         }
796         if (isInRange){
797                 requestor.enterMethod(
798                         methodDeclaration.declarationSourceStart, 
799                         methodDeclaration.modifiers & AccJustFlag, 
800                         returnTypeName(((MethodDeclaration) methodDeclaration).returnType), 
801                         methodDeclaration.selector, 
802                         methodDeclaration.sourceStart, 
803                         selectorSourceEnd, 
804                         argumentTypes, 
805                         argumentNames, 
806                         thrownExceptionTypes); 
807         }               
808         this.visitIfNeeded(methodDeclaration);
809
810         if (isInRange){ 
811                 requestor.exitMethod(methodDeclaration.declarationSourceEnd);
812         }
813 }
814 /*
815 * Update the bodyStart of the corresponding parse node
816 */
817 public void notifySourceElementRequestor(FieldDeclaration fieldDeclaration) {
818         
819         // range check
820         boolean isInRange = 
821                                 scanner.initialPosition <= fieldDeclaration.declarationSourceStart
822                                 && scanner.eofPosition >= fieldDeclaration.declarationSourceEnd;
823
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;
831                         }
832                 }
833                 if (isInRange) {
834                         requestor.enterField(
835                                 fieldDeclaration.declarationSourceStart, 
836                                 fieldDeclaration.modifiers & AccJustFlag, 
837                                 returnTypeName(fieldDeclaration.type), 
838                                 fieldDeclaration.name, 
839                                 fieldDeclaration.sourceStart, 
840                                 fieldDeclaration.sourceEnd); 
841                 }
842                 this.visitIfNeeded(fieldDeclaration);
843                 if (isInRange){
844                         requestor.exitField(fieldEndPosition);
845                 }
846
847         } else {
848                 if (isInRange){
849                         requestor.enterInitializer(
850                                 fieldDeclaration.declarationSourceStart,
851                                 fieldDeclaration.modifiers); 
852                 }
853                 this.visitIfNeeded((Initializer)fieldDeclaration);
854                 if (isInRange){
855                         requestor.exitInitializer(fieldDeclaration.declarationSourceEnd);
856                 }
857         }
858 }
859 public void notifySourceElementRequestor(
860         ImportReference importReference, 
861         boolean isPackage) {
862         if (isPackage) {
863                 requestor.acceptPackage(
864                         importReference.declarationSourceStart, 
865                         importReference.declarationSourceEnd, 
866                         CharOperation.concatWith(importReference.getImportName(), '.')); 
867         } else {
868                 requestor.acceptImport(
869                         importReference.declarationSourceStart, 
870                         importReference.declarationSourceEnd, 
871                         CharOperation.concatWith(importReference.getImportName(), '.'), 
872                         importReference.onDemand); 
873         }
874 }
875 public void notifySourceElementRequestor(TypeDeclaration typeDeclaration, boolean notifyTypePresence) {
876         
877         // range check
878         boolean isInRange = 
879                                 scanner.initialPosition <= typeDeclaration.declarationSourceStart
880                                 && scanner.eofPosition >= typeDeclaration.declarationSourceEnd;
881         
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;
888         int fieldIndex = 0;
889         int methodIndex = 0;
890         int memberTypeIndex = 0;
891         boolean isInterface = typeDeclaration.isInterface();
892
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][];
900                 } else {
901                         if (typeDeclaration instanceof AnonymousLocalTypeDeclaration) {
902                                 // see PR 3442
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][];
908                                 }
909                         }
910                 }
911                 if (superInterfaces != null) {
912                         for (int i = 0; i < superInterfacesLength; i++) {
913                                 interfaceNames[i] = 
914                                         CharOperation.concatWith(superInterfaces[i].getTypeName(), '.'); 
915                         }
916                 }
917                 if (isInterface) {
918                         if (isInRange){
919                                 requestor.enterInterface(
920                                         typeDeclaration.declarationSourceStart, 
921                                         typeDeclaration.modifiers & AccJustFlag, 
922                                         typeDeclaration.name, 
923                                         typeDeclaration.sourceStart, 
924                                         typeDeclaration.sourceEnd, 
925                                         interfaceNames);
926                         }
927                         if (nestedTypeIndex == typeNames.length) {
928                                 // need a resize
929                                 System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
930                                 System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
931                         }
932                         typeNames[nestedTypeIndex] = typeDeclaration.name;
933                         superTypeNames[nestedTypeIndex++] = JAVA_LANG_OBJECT;
934                 } else {
935                         TypeReference superclass = typeDeclaration.superclass;
936                         if (superclass == null) {
937                                 if (isInRange){
938                                         requestor.enterClass(
939                                                 typeDeclaration.declarationSourceStart, 
940                                                 typeDeclaration.modifiers, 
941                                                 typeDeclaration.name, 
942                                                 typeDeclaration.sourceStart, 
943                                                 typeDeclaration.sourceEnd, 
944                                                 null, 
945                                                 interfaceNames); 
946                                 }
947                         } else {
948                                 if (isInRange){
949                                         requestor.enterClass(
950                                                 typeDeclaration.declarationSourceStart, 
951                                                 typeDeclaration.modifiers, 
952                                                 typeDeclaration.name, 
953                                                 typeDeclaration.sourceStart, 
954                                                 typeDeclaration.sourceEnd, 
955                                                 CharOperation.concatWith(superclass.getTypeName(), '.'), 
956                                                 interfaceNames); 
957                                 }
958                         }
959                         if (nestedTypeIndex == typeNames.length) {
960                                 // need a resize
961                                 System.arraycopy(typeNames, 0, (typeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
962                                 System.arraycopy(superTypeNames, 0, (superTypeNames = new char[nestedTypeIndex * 2][]), 0, nestedTypeIndex);
963                         }
964                         typeNames[nestedTypeIndex] = typeDeclaration.name;
965                         superTypeNames[nestedTypeIndex++] = superclass == null ? JAVA_LANG_OBJECT : CharOperation.concatWith(superclass.getTypeName(), '.');
966                 }
967         }
968         while ((fieldIndex < fieldCount)
969                 || (memberTypeIndex < memberTypeCount)
970                 || (methodIndex < methodCount)) {
971                 FieldDeclaration nextFieldDeclaration = null;
972                 AbstractMethodDeclaration nextMethodDeclaration = null;
973                 TypeDeclaration nextMemberDeclaration = null;
974
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
982                         }
983                 }
984                 if (methodIndex < methodCount) {
985                         nextMethodDeclaration = methods[methodIndex];
986                         if (nextMethodDeclaration.declarationSourceStart < position) {
987                                 position = nextMethodDeclaration.declarationSourceStart;
988                                 nextDeclarationType = 1; // METHOD
989                         }
990                 }
991                 if (memberTypeIndex < memberTypeCount) {
992                         nextMemberDeclaration = memberTypes[memberTypeIndex];
993                         if (nextMemberDeclaration.declarationSourceStart < position) {
994                                 position = nextMemberDeclaration.declarationSourceStart;
995                                 nextDeclarationType = 2; // MEMBER
996                         }
997                 }
998                 switch (nextDeclarationType) {
999                         case 0 :
1000                                 fieldIndex++;
1001                                 notifySourceElementRequestor(nextFieldDeclaration);
1002                                 break;
1003                         case 1 :
1004                                 methodIndex++;
1005                                 notifySourceElementRequestor(nextMethodDeclaration);
1006                                 break;
1007                         case 2 :
1008                                 memberTypeIndex++;
1009                                 notifySourceElementRequestor(nextMemberDeclaration, true);
1010                 }
1011         }
1012         if (notifyTypePresence){
1013                 if (isInRange){
1014                         if (isInterface) {
1015                                 requestor.exitInterface(typeDeclaration.declarationSourceEnd);
1016                         } else {
1017                                 requestor.exitClass(typeDeclaration.declarationSourceEnd);
1018                         }
1019                 }
1020                 nestedTypeIndex--;
1021         }
1022 }
1023 public void parseCompilationUnit(
1024         ICompilationUnit unit, 
1025         int start, 
1026         int end, 
1027         boolean needReferenceInfo) {
1028
1029         reportReferenceInfo = needReferenceInfo;
1030         boolean old = diet;
1031         if (needReferenceInfo) {
1032                 unknownRefs = new NameReference[10];
1033                 unknownRefsCounter = 0;
1034         }
1035         try {
1036                 diet = true;
1037                 CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0, this.options.maxProblemsPerUnit);
1038                 CompilationUnitDeclaration parsedUnit = parse(unit, compilationUnitResult, start, end);
1039                 if (needReferenceInfo){
1040                         diet = false;
1041                         this.getMethodBodies(parsedUnit);
1042                 }               
1043                 this.scanner.resetTo(start, end);
1044                 notifySourceElementRequestor(parsedUnit);
1045         } catch (AbortCompilation e) {
1046         } finally {
1047                 if (scanner.recordLineSeparator) {
1048                         requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
1049                 }
1050                 diet = old;
1051         }
1052 }
1053 public void parseCompilationUnit(
1054         ICompilationUnit unit, 
1055         boolean needReferenceInfo) {
1056         boolean old = diet;
1057         if (needReferenceInfo) {
1058                 unknownRefs = new NameReference[10];
1059                 unknownRefsCounter = 0;
1060         }
1061                 
1062         try {
1063 /*              diet = !needReferenceInfo;
1064                 reportReferenceInfo = needReferenceInfo;
1065                 CompilationResult compilationUnitResult = new CompilationResult(unit, 0, 0);
1066                 parse(unit, compilationUnitResult);             
1067 */              diet = true;
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){
1074                         diet = false;
1075                         this.getMethodBodies(parsedUnit);
1076                 }
1077                 this.scanner.resetTo(initialStart, initialEnd);
1078                 notifySourceElementRequestor(parsedUnit);
1079         } catch (AbortCompilation e) {
1080         } finally {
1081                 if (scanner.recordLineSeparator) {
1082                         requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
1083                 }
1084                 diet = old;
1085         }
1086 }
1087 public void parseTypeMemberDeclarations(
1088         ISourceType sourceType, 
1089         ICompilationUnit sourceUnit, 
1090         int start, 
1091         int end, 
1092         boolean needReferenceInfo) {
1093         boolean old = diet;
1094         if (needReferenceInfo) {
1095                 unknownRefs = new NameReference[10];
1096                 unknownRefsCounter = 0;
1097         }
1098         
1099         try {
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}, 
1107                                 false,
1108                                 false, 
1109                                 problemReporter(), 
1110                                 compilationUnitResult); 
1111                 if ((unit == null) || (unit.types == null) || (unit.types.length != 1))
1112                         return;
1113                 this.sourceType = sourceType;
1114                 try {
1115                         /* automaton initialization */
1116                         initialize();
1117                         goForClassBodyDeclarations();
1118                         /* scanner initialization */
1119                         scanner.setSource(sourceUnit.getContents());
1120                         scanner.resetTo(start, end);
1121                         /* unit creation */
1122                         referenceContext = compilationUnit = unit;
1123                         /* initialize the astStacl */
1124                         // the compilationUnitDeclaration should contain exactly one type
1125                         pushOnAstStack(unit.types[0]);
1126                         /* run automaton */
1127                         parse();
1128                         notifySourceElementRequestor(unit);
1129                 } finally {
1130                         unit = compilationUnit;
1131                         compilationUnit = null; // reset parser
1132                 }
1133         } catch (AbortCompilation e) {
1134         } finally {
1135                 if (scanner.recordLineSeparator) {
1136                         requestor.acceptLineSeparatorPositions(scanner.getLineEnds());
1137                 }
1138                 diet = old;
1139         }
1140 }
1141
1142 public void parseTypeMemberDeclarations(
1143         char[] contents, 
1144         int start, 
1145         int end) {
1146
1147         boolean old = diet;
1148         
1149         try {
1150                 diet = true;
1151
1152                 /* automaton initialization */
1153                 initialize();
1154                 goForClassBodyDeclarations();
1155                 /* scanner initialization */
1156                 scanner.setSource(contents);
1157                 scanner.recordLineSeparator = false;
1158                 scanner.resetTo(start, end);
1159
1160                 /* unit creation */
1161                 referenceContext = null;
1162
1163                 /* initialize the astStacl */
1164                 // the compilationUnitDeclaration should contain exactly one type
1165                 /* run automaton */
1166                 parse();
1167                 notifySourceElementRequestor((CompilationUnitDeclaration)null);
1168         } catch (AbortCompilation e) {
1169         } finally {
1170                 diet = old;
1171         }
1172 }
1173 /**
1174  * Sort the given ast nodes by their positions.
1175  */
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];
1180         do {
1181                 while (sortedCollection[left].sourceStart < mid.sourceStart) {
1182                         left++;
1183                 }
1184                 while (mid.sourceStart < sortedCollection[right].sourceStart) {
1185                         right--;
1186                 }
1187                 if (left <= right) {
1188                         AstNode tmp = sortedCollection[left];
1189                         sortedCollection[left] = sortedCollection[right];
1190                         sortedCollection[right] = tmp;
1191                         left++;
1192                         right--;
1193                 }
1194         } while (left <= right);
1195         if (original_left < right) {
1196                 quickSort(sortedCollection, original_left, right);
1197         }
1198         if (left < original_right) {
1199                 quickSort(sortedCollection, left, original_right);
1200         }
1201 }
1202 /*
1203  * Answer a char array representation of the type name formatted like:
1204  * - type name + dimensions
1205  * Example:
1206  * "A[][]".toCharArray()
1207  * "java.lang.String".toCharArray()
1208  */
1209 private char[] returnTypeName(TypeReference type) {
1210         if (type == null)
1211                 return null;
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] = ']';
1218                 }
1219                 return CharOperation.concat(
1220                         CharOperation.concatWith(type.getTypeName(), '.'), 
1221                         dimensionsArray); 
1222         }
1223         return CharOperation.concatWith(type.getTypeName(), '.');
1224 }
1225
1226 public void addUnknownRef(NameReference nameRef) {
1227         if (this.unknownRefs.length == this.unknownRefsCounter) {
1228                 // resize
1229                 System.arraycopy(
1230                         this.unknownRefs,
1231                         0,
1232                         (this.unknownRefs = new NameReference[this.unknownRefsCounter * 2]),
1233                         0,
1234                         this.unknownRefsCounter);
1235         }
1236         this.unknownRefs[this.unknownRefsCounter++] = nameRef;
1237 }
1238 private TypeReference typeReference(
1239         int dim, 
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.
1245          */
1246
1247         int length;
1248         TypeReference ref;
1249         if ((length = identifierLengthStack[localIdentifierLengthPtr]) == 1) {
1250                 // single variable reference
1251                 if (dim == 0) {
1252                         ref = 
1253                                 new SingleTypeReference(
1254                                         identifierStack[localIdentifierPtr], 
1255                                         identifierPositionStack[localIdentifierPtr--]); 
1256                 } else {
1257                         ref = 
1258                                 new ArrayTypeReference(
1259                                         identifierStack[localIdentifierPtr], 
1260                                         dim, 
1261                                         identifierPositionStack[localIdentifierPtr--]);
1262                         ref.sourceEnd = endPosition;                     
1263                 }
1264         } else {
1265                 if (length < 0) { //flag for precompiled type reference on base types
1266                         ref = TypeReference.baseTypeReference(-length, dim);
1267                         ref.sourceStart = intStack[localIntPtr--];
1268                         if (dim == 0) {
1269                                 ref.sourceEnd = intStack[localIntPtr--];
1270                         } else {
1271                                 localIntPtr--;
1272                                 ref.sourceEnd = endPosition;
1273                         }       
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);
1279                         System.arraycopy(
1280                                 identifierPositionStack, 
1281                                 localIdentifierPtr + 1, 
1282                                 positions, 
1283                                 0, 
1284                                 length); 
1285                         if (dim == 0)  {
1286                                 ref = new QualifiedTypeReference(tokens, positions);
1287                         } else {
1288                                 ref = new ArrayQualifiedTypeReference(tokens, dim, positions);
1289                                 ref.sourceEnd = endPosition;
1290                         }
1291                 }
1292         };
1293         return ref;
1294 }
1295
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);
1303                         }
1304         }
1305 }
1306
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);
1312                         }
1313         }
1314 }
1315
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);
1321                         }
1322         }
1323 }
1324
1325 protected void reportSyntaxError(int act, int currentKind, int stateStackTop) {
1326         if (compilationUnit == null) return;
1327         super.reportSyntaxError(act, currentKind,stateStackTop);
1328 }
1329
1330 }