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