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