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