Refactory: replaced internal copy of Assert class with org.eclipse.core.runtime.Assert
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / CompilationUnitStructureRequestor.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
12
13 import java.util.Map;
14 import java.util.Stack;
15
16 import net.sourceforge.phpdt.core.Flags;
17 import net.sourceforge.phpdt.core.ICompilationUnit;
18 import net.sourceforge.phpdt.core.IField;
19 import net.sourceforge.phpdt.core.IJavaElement;
20 import net.sourceforge.phpdt.core.IMethod;
21 import net.sourceforge.phpdt.core.IType;
22 import net.sourceforge.phpdt.core.JavaModelException;
23 import net.sourceforge.phpdt.core.Signature;
24 import net.sourceforge.phpdt.core.compiler.IProblem;
25 import net.sourceforge.phpdt.internal.compiler.ISourceElementRequestor;
26 import net.sourceforge.phpdt.internal.compiler.parser.Parser;
27 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject;
28 import net.sourceforge.phpdt.internal.core.util.ReferenceInfoAdapter;
29 //incastrix
30 //import net.sourceforge.phpdt.internal.corext.Assert;
31 import org.eclipse.core.runtime.Assert;
32
33 /**
34  * A requestor for the fuzzy parser, used to compute the children of an
35  * ICompilationUnit.
36  */
37 public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter
38                 implements ISourceElementRequestor {
39
40         /**
41          * The handle to the compilation unit being parsed
42          */
43         protected ICompilationUnit unit;
44
45         /**
46          * The info object for the compilation unit being parsed
47          */
48         protected CompilationUnitElementInfo unitInfo;
49
50         /**
51          * The import container info - null until created
52          */
53         protected JavaElementInfo importContainerInfo = null;
54
55         /**
56          * Hashtable of children elements of the compilation unit. Children are
57          * added to the table as they are found by the parser. Keys are handles,
58          * values are corresponding info objects.
59          */
60         protected Map newElements;
61
62         /**
63          * Stack of parent scope info objects. The info on the top of the stack is
64          * the parent of the next element found. For example, when we locate a
65          * method, the parent info object will be the type the method is contained
66          * in.
67          */
68         protected Stack infoStack;
69
70         /**
71          * Stack of parent handles, corresponding to the info stack. We keep both,
72          * since info objects do not have back pointers to handles.
73          */
74         protected Stack handleStack;
75
76         /**
77          * The name of the source file being parsed.
78          */
79         protected char[] fSourceFileName = null;
80
81         /**
82          * The dot-separated name of the package the compilation unit is contained
83          * in - based on the package statement in the compilation unit, and
84          * initialized by #acceptPackage. Initialized to <code>null</code> for the
85          * default package.
86          */
87         protected char[] fPackageName = null;
88
89         /**
90          * The number of references reported thus far. Used to expand the arrays of
91          * reference kinds and names.
92          */
93         protected int fRefCount = 0;
94
95         /**
96          * The initial size of the reference kind and name arrays. If the arrays
97          * fill, they are doubled in size
98          */
99         protected static int fgReferenceAllocation = 50;
100
101         /**
102          * Problem requestor which will get notified of discovered problems
103          */
104         protected boolean hasSyntaxErrors = false;
105
106         /*
107          * The parser this requestor is using.
108          */
109         // protected Parser parser;
110         protected Parser parser;
111
112         /**
113          * Empty collections used for efficient initialization
114          */
115         protected static String[] fgEmptyStringArray = new String[0];
116
117         protected static byte[] fgEmptyByte = new byte[] {};
118
119         protected static char[][] fgEmptyCharChar = new char[][] {};
120
121         protected static char[] fgEmptyChar = new char[] {};
122
123         protected HashtableOfObject fieldRefCache;
124
125         protected HashtableOfObject messageRefCache;
126
127         protected HashtableOfObject typeRefCache;
128
129         protected HashtableOfObject unknownRefCache;
130
131         protected CompilationUnitStructureRequestor(ICompilationUnit unit,
132                         CompilationUnitElementInfo unitInfo, Map newElements)
133                         throws JavaModelException {
134                 this.unit = unit;
135                 this.unitInfo = unitInfo;
136                 this.newElements = newElements;
137                 this.fSourceFileName = unit.getElementName().toCharArray();
138         }
139
140         /**
141          * @see ISourceElementRequestor
142          */
143         public void acceptImport(int declarationStart, int declarationEnd,
144                         char[] name, boolean onDemand) {
145                 // , int modifiers) {
146
147                 JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
148                 JavaElement parentHandle = (JavaElement) this.handleStack.peek();
149                 if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
150                         Assert.isTrue(false); // Should not happen
151                 }
152
153                 ICompilationUnit parentCU = (ICompilationUnit) parentHandle;
154                 // create the import container and its info
155                 ImportContainer importContainer = (ImportContainer) parentCU
156                                 .getImportContainer();
157                 if (this.importContainerInfo == null) {
158                         this.importContainerInfo = new JavaElementInfo();
159                         this.importContainerInfo.setIsStructureKnown(true);
160                         parentInfo.addChild(importContainer);
161                         this.newElements.put(importContainer, this.importContainerInfo);
162                 }
163
164                 // tack on the '.*' if it is onDemand
165                 String importName;
166                 if (onDemand) {
167                         importName = new String(name) + ".*"; //$NON-NLS-1$
168                 } else {
169                         importName = new String(name);
170                 }
171
172                 ImportDeclaration handle = new ImportDeclaration(importContainer,
173                                 importName);
174                 resolveDuplicates(handle);
175
176                 ImportDeclarationElementInfo info = new ImportDeclarationElementInfo();
177                 info.setSourceRangeStart(declarationStart);
178                 info.setSourceRangeEnd(declarationEnd);
179                 // info.setFlags(modifiers);
180                 info.setName(name); // no trailing * if onDemand
181                 info.setOnDemand(onDemand);
182
183                 this.importContainerInfo.addChild(handle);
184                 this.newElements.put(handle, info);
185         }
186
187         /**
188          * @see ISourceElementRequestor
189          */
190
191         /*
192          * Table of line separator position. This table is passed once at the end of
193          * the parse action, so as to allow computation of normalized ranges.
194          * 
195          * A line separator might corresponds to several characters in the source,
196          * 
197          */
198         public void acceptLineSeparatorPositions(int[] positions) {
199         }
200
201         /**
202          * @see ISourceElementRequestor
203          */
204         // public void acceptPackage(int declarationStart, int declarationEnd,
205         // char[] name) {
206         //
207         // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
208         // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
209         // IPackageDeclaration handle = null;
210         // fPackageName= name;
211         //              
212         // if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
213         // handle = new PackageDeclaration((ICompilationUnit) parentHandle, new
214         // String(name));
215         // }
216         // else {
217         // Assert.isTrue(false); // Should not happen
218         // }
219         // resolveDuplicates(handle);
220         //              
221         // SourceRefElementInfo info = new SourceRefElementInfo();
222         // info.setSourceRangeStart(declarationStart);
223         // info.setSourceRangeEnd(declarationEnd);
224         //
225         // parentInfo.addChild(handle);
226         // fNewElements.put(handle, info);
227         //
228         // }
229         public void acceptProblem(IProblem problem) {
230                 if ((problem.getID() & IProblem.Syntax) != 0) {
231                         this.hasSyntaxErrors = true;
232                 }
233         }
234
235         /**
236          * Convert these type names to signatures.
237          * 
238          * @see Signature.
239          */
240         /* default */
241         static String[] convertTypeNamesToSigs(char[][] typeNames) {
242                 if (typeNames == null)
243                         return fgEmptyStringArray;
244                 int n = typeNames.length;
245                 if (n == 0)
246                         return fgEmptyStringArray;
247                 String[] typeSigs = new String[n];
248                 for (int i = 0; i < n; ++i) {
249                         typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
250                 }
251                 return typeSigs;
252         }
253
254         /**
255          * @see ISourceElementRequestor
256          */
257         public void enterClass(int declarationStart, int modifiers, char[] name,
258                         int nameSourceStart, int nameSourceEnd, char[] superclass,
259                         char[][] superinterfaces) {
260
261                 enterType(declarationStart, modifiers, name, nameSourceStart,
262                                 nameSourceEnd, superclass, superinterfaces);
263
264         }
265
266         /**
267          * @see ISourceElementRequestor
268          */
269         public void enterCompilationUnit() {
270                 infoStack = new Stack();
271                 handleStack = new Stack();
272                 infoStack.push(unitInfo);
273                 handleStack.push(unit);
274         }
275
276         /**
277          * @see ISourceElementRequestor
278          */
279         public void enterConstructor(int declarationStart, int modifiers,
280                         char[] name, int nameSourceStart, int nameSourceEnd,
281                         char[][] parameterTypes, char[][] parameterNames,
282                         char[][] exceptionTypes) {
283
284                 enterMethod(declarationStart, modifiers, null, name, nameSourceStart,
285                                 nameSourceEnd, parameterTypes, parameterNames, exceptionTypes,
286                                 true);
287         }
288
289         /**
290          * @see ISourceElementRequestor
291          */
292         public void enterField(int declarationStart, int modifiers, char[] type,
293                         char[] name, int nameSourceStart, int nameSourceEnd) {
294
295                 SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) infoStack
296                                 .peek();
297                 JavaElement parentHandle = (JavaElement) handleStack.peek();
298                 IField handle = null;
299
300                 if (parentHandle.getElementType() == IJavaElement.TYPE) {
301                         handle = new SourceField(parentHandle, new String(name));
302                 } else {
303                         Assert.isTrue(false); // Should not happen
304                 }
305                 resolveDuplicates(handle);
306
307                 SourceFieldElementInfo info = new SourceFieldElementInfo();
308                 info.setName(name);
309                 info.setNameSourceStart(nameSourceStart);
310                 info.setNameSourceEnd(nameSourceEnd);
311                 info.setSourceRangeStart(declarationStart);
312                 info.setFlags(modifiers);
313                 info.setTypeName(type);
314
315                 parentInfo.addChild(handle);
316                 newElements.put(handle, info);
317
318                 infoStack.push(info);
319                 handleStack.push(handle);
320         }
321
322         /**
323          * @see ISourceElementRequestor
324          */
325         // public void enterInitializer(
326         // int declarationSourceStart,
327         // int modifiers) {
328         // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
329         // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
330         // IInitializer handle = null;
331         //              
332         // if (parentHandle.getElementType() == IJavaElement.TYPE) {
333         // handle = ((IType) parentHandle).getInitializer(1);
334         // }
335         // else {
336         // Assert.isTrue(false); // Should not happen
337         // }
338         // resolveDuplicates(handle);
339         //              
340         // InitializerElementInfo info = new InitializerElementInfo();
341         // info.setSourceRangeStart(declarationSourceStart);
342         // info.setFlags(modifiers);
343         //
344         // parentInfo.addChild(handle);
345         // fNewElements.put(handle, info);
346         //
347         // fInfoStack.push(info);
348         // fHandleStack.push(handle);
349         // }
350         /**
351          * @see ISourceElementRequestor
352          */
353         public void enterInterface(int declarationStart, int modifiers,
354                         char[] name, int nameSourceStart, int nameSourceEnd,
355                         char[][] superinterfaces) {
356
357                 enterType(declarationStart, modifiers, name, nameSourceStart,
358                                 nameSourceEnd, null, superinterfaces);
359
360         }
361
362         /**
363          * @see ISourceElementRequestor
364          */
365         public void enterMethod(int declarationStart, int modifiers,
366                         char[] returnType, char[] name, int nameSourceStart,
367                         int nameSourceEnd, char[][] parameterTypes,
368                         char[][] parameterNames, char[][] exceptionTypes) {
369
370                 enterMethod(declarationStart, modifiers, returnType, name,
371                                 nameSourceStart, nameSourceEnd, parameterTypes, parameterNames,
372                                 exceptionTypes, false);
373         }
374
375         /**
376          * @see ISourceElementRequestor
377          */
378         protected void enterMethod(int declarationStart, int modifiers,
379                         char[] returnType, char[] name, int nameSourceStart,
380                         int nameSourceEnd, char[][] parameterTypes,
381                         char[][] parameterNames, char[][] exceptionTypes,
382                         boolean isConstructor) {
383                 SourceTypeElementInfo parentInfo = null;
384                 try {
385                         parentInfo = (SourceTypeElementInfo) infoStack.peek();
386                 } catch (ClassCastException e) {
387                         // parentInfo = null;
388                 }
389                 JavaElement parentHandle = (JavaElement) handleStack.peek();
390                 IMethod handle = null;
391
392                 // translate nulls to empty arrays
393                 if (parameterTypes == null) {
394                         parameterTypes = fgEmptyCharChar;
395                 }
396                 if (parameterNames == null) {
397                         parameterNames = fgEmptyCharChar;
398                 }
399                 if (exceptionTypes == null) {
400                         exceptionTypes = fgEmptyCharChar;
401                 }
402
403                 String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
404                 // TODO : jsurfer changed
405                 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
406                 handle = new SourceMethod(parentHandle, new String(name),
407                                 parameterTypeSigs);
408                 // }
409                 // else {
410                 // Assert.isTrue(false); // Should not happen
411                 // }
412                 resolveDuplicates(handle);
413
414                 SourceMethodElementInfo info = new SourceMethodElementInfo();
415                 info.setSourceRangeStart(declarationStart);
416                 int flags = modifiers;
417                 info.setName(name);
418                 info.setNameSourceStart(nameSourceStart);
419                 info.setNameSourceEnd(nameSourceEnd);
420                 info.setConstructor(isConstructor);
421                 info.setFlags(flags);
422                 info.setArgumentNames(parameterNames);
423                 info.setArgumentTypeNames(parameterTypes);
424                 info
425                                 .setReturnType(returnType == null ? new char[] { 'v', 'o', 'i',
426                                                 'd' } : returnType);
427                 info.setExceptionTypeNames(exceptionTypes);
428
429                 if (parentInfo == null) {
430                         unitInfo.addChild(handle);
431                 } else {
432                         parentInfo.addChild(handle);
433                 }
434                 newElements.put(handle, info);
435                 infoStack.push(info);
436                 handleStack.push(handle);
437         }
438
439         /**
440          * Common processing for classes and interfaces.
441          */
442         protected void enterType(int declarationStart, int modifiers, char[] name,
443                         int nameSourceStart, int nameSourceEnd, char[] superclass,
444                         char[][] superinterfaces) {
445
446                 char[] enclosingTypeName = null;
447                 char[] qualifiedName = null;
448
449                 JavaElementInfo parentInfo = (JavaElementInfo) infoStack.peek();
450                 JavaElement parentHandle = (JavaElement) handleStack.peek();
451                 IType handle = null;
452                 String nameString = new String(name);
453
454                 if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
455                         handle = ((ICompilationUnit) parentHandle).getType(nameString);
456                         if (fPackageName == null) {
457                                 qualifiedName = nameString.toCharArray();
458                         } else {
459                                 qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
460                         }
461                 } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
462                         handle = ((IType) parentHandle).getType(nameString);
463                         enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
464                         qualifiedName = (new String(((SourceTypeElementInfo) parentInfo)
465                                         .getQualifiedName())
466                                         + "." + nameString).toCharArray(); //$NON-NLS-1$
467                 } else {
468                         Assert.isTrue(false); // Should not happen
469                 }
470                 resolveDuplicates(handle);
471
472                 SourceTypeElementInfo info = new SourceTypeElementInfo();
473                 info.setHandle(handle);
474                 info.setSourceRangeStart(declarationStart);
475                 info.setFlags(modifiers);
476                 info.setName(name);
477                 info.setNameSourceStart(nameSourceStart);
478                 info.setNameSourceEnd(nameSourceEnd);
479                 info.setSuperclassName(superclass);
480                 info.setSuperInterfaceNames(superinterfaces);
481                 info.setEnclosingTypeName(enclosingTypeName);
482                 info.setSourceFileName(fSourceFileName);
483                 info.setPackageName(fPackageName);
484                 info.setQualifiedName(qualifiedName);
485                 // for (Iterator iter = fNewElements.keySet().iterator();
486                 // iter.hasNext();){
487                 // Object object = iter.next();
488                 // if (object instanceof IImportDeclaration)
489                 // info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
490                 // }
491
492                 parentInfo.addChild(handle);
493                 newElements.put(handle, info);
494
495                 infoStack.push(info);
496                 handleStack.push(handle);
497
498         }
499
500         /**
501          * @see ISourceElementRequestor
502          */
503         public void exitClass(int declarationEnd) {
504
505                 exitMember(declarationEnd);
506         }
507
508         /**
509          * @see ISourceElementRequestor
510          */
511         public void exitCompilationUnit(int declarationEnd) {
512                 unitInfo.setSourceLength(declarationEnd + 1);
513
514                 // determine if there were any parsing errors
515                 unitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
516         }
517
518         /**
519          * @see ISourceElementRequestor
520          */
521         public void exitConstructor(int declarationEnd) {
522                 exitMember(declarationEnd);
523         }
524
525         /**
526          * @see ISourceElementRequestor
527          */
528         public void exitField(int initializationStart, int declarationEnd,
529                         int declarationSourceEnd) {
530                 SourceFieldElementInfo info = (SourceFieldElementInfo) infoStack.pop();
531                 info.setSourceRangeEnd(declarationSourceEnd);
532
533                 // remember initializer source if field is a constant
534                 if (initializationStart != -1) {
535                         int flags = info.flags;
536                         Object typeInfo;
537                         if (Flags.isStatic(flags)
538                                         && Flags.isFinal(flags)
539                                         || ((typeInfo = infoStack.peek()) instanceof SourceTypeElementInfo && (Flags
540                                                         .isInterface(((SourceTypeElementInfo) typeInfo).flags)))) {
541                                 int length = declarationEnd - initializationStart;
542                                 if (length > 0) {
543                                         char[] initializer = new char[length];
544                                         System.arraycopy(this.parser.scanner.source,
545                                                         initializationStart, initializer, 0, length);
546                                         info.initializationSource = initializer;
547                                 }
548                         }
549                 }
550                 handleStack.pop();
551         }
552
553         /**
554          * @see ISourceElementRequestor
555          */
556         public void exitInitializer(int declarationEnd) {
557                 exitMember(declarationEnd);
558         }
559
560         /**
561          * @see ISourceElementRequestor
562          */
563         public void exitInterface(int declarationEnd) {
564                 exitMember(declarationEnd);
565         }
566
567         /**
568          * common processing for classes and interfaces
569          */
570         protected void exitMember(int declarationEnd) {
571                 SourceRefElementInfo info = (SourceRefElementInfo) infoStack.pop();
572                 info.setSourceRangeEnd(declarationEnd);
573                 handleStack.pop();
574         }
575
576         /**
577          * @see ISourceElementRequestor
578          */
579         public void exitMethod(int declarationEnd) {
580                 exitMember(declarationEnd);
581         }
582
583         /**
584          * Resolves duplicate handles by incrementing the occurrence count of the
585          * handle being created until there is no conflict.
586          */
587         protected void resolveDuplicates(IJavaElement handle) {
588                 while (newElements.containsKey(handle)) {
589                         JavaElement h = (JavaElement) handle;
590                         h.setOccurrenceCount(h.getOccurrenceCount() + 1);
591                 }
592         }
593 }