Organized imports
[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 unit;
40
41   /**
42    * The info object for the compilation unit being parsed
43    */
44   protected CompilationUnitElementInfo unitInfo;
45
46   /**
47    * The import container info - null until created
48    */
49   protected JavaElementInfo importContainerInfo = 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 newElements;
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 infoStack;
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 handleStack;
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.unit = unit;
130     this.unitInfo = unitInfo;
131     this.newElements = 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     //, int modifiers) {
139   
140         JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
141         JavaElement parentHandle= (JavaElement) this.handleStack.peek();
142         if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
143                 Assert.isTrue(false); // Should not happen
144         }
145
146         ICompilationUnit parentCU= (ICompilationUnit)parentHandle;
147         //create the import container and its info
148         ImportContainer importContainer= (ImportContainer)parentCU.getImportContainer();
149         if (this.importContainerInfo == null) {
150                 this.importContainerInfo= new JavaElementInfo();
151                 this.importContainerInfo.setIsStructureKnown(true);
152                 parentInfo.addChild(importContainer);
153                 this.newElements.put(importContainer, this.importContainerInfo);
154         }
155         
156         // tack on the '.*' if it is onDemand
157         String importName;
158         if (onDemand) {
159                 importName= new String(name) + ".*"; //$NON-NLS-1$
160         } else {
161                 importName= new String(name);
162         }
163         
164         ImportDeclaration handle = new ImportDeclaration(importContainer, importName);
165         resolveDuplicates(handle);
166         
167         ImportDeclarationElementInfo info = new ImportDeclarationElementInfo();
168         info.setSourceRangeStart(declarationStart);
169         info.setSourceRangeEnd(declarationEnd);
170 //      info.setFlags(modifiers);
171         info.setName(name); // no trailing * if onDemand
172         info.setOnDemand(onDemand);
173
174         this.importContainerInfo.addChild(handle);
175         this.newElements.put(handle, info);
176   }
177   /**
178    * @see ISourceElementRequestor
179    */
180   
181   /*
182    * Table of line separator position. This table is passed once at the end
183    * of the parse action, so as to allow computation of normalized ranges.
184    *
185    * A line separator might corresponds to several characters in the source,
186    * 
187    */
188   public void acceptLineSeparatorPositions(int[] positions) {
189   }
190   /**
191    * @see ISourceElementRequestor
192    */
193   //public void acceptPackage(int declarationStart, int declarationEnd, char[] name) {
194   //
195   //            JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
196   //            JavaElement parentHandle= (JavaElement)fHandleStack.peek();
197   //            IPackageDeclaration handle = null;
198   //            fPackageName= name;
199   //            
200   //            if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
201   //                    handle = new PackageDeclaration((ICompilationUnit) parentHandle, new String(name));
202   //            }
203   //            else {
204   //                    Assert.isTrue(false); // Should not happen
205   //            }
206   //            resolveDuplicates(handle);
207   //            
208   //            SourceRefElementInfo info = new SourceRefElementInfo();
209   //            info.setSourceRangeStart(declarationStart);
210   //            info.setSourceRangeEnd(declarationEnd);
211   //
212   //            parentInfo.addChild(handle);
213   //            fNewElements.put(handle, info);
214   //
215   //}
216   public void acceptProblem(IProblem problem) {
217     if ((problem.getID() & IProblem.Syntax) != 0) {
218       this.hasSyntaxErrors = true;
219     }
220   }
221   /**
222    * Convert these type names to signatures.
223    * @see Signature.
224    */
225   /* default */
226   static String[] convertTypeNamesToSigs(char[][] typeNames) {
227     if (typeNames == null)
228       return fgEmptyStringArray;
229     int n = typeNames.length;
230     if (n == 0)
231       return fgEmptyStringArray;
232     String[] typeSigs = new String[n];
233     for (int i = 0; i < n; ++i) {
234       typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
235     }
236     return typeSigs;
237   }
238   /**
239    * @see ISourceElementRequestor
240    */
241   public void enterClass(
242     int declarationStart,
243     int modifiers,
244     char[] name,
245     int nameSourceStart,
246     int nameSourceEnd,
247     char[] superclass,
248     char[][] superinterfaces) {
249
250     enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, superclass, superinterfaces);
251
252   }
253   /**
254    * @see ISourceElementRequestor
255    */
256   public void enterCompilationUnit() {
257     infoStack = new Stack();
258     handleStack = new Stack();
259     infoStack.push(unitInfo);
260     handleStack.push(unit);
261   }
262   /**
263    * @see ISourceElementRequestor
264    */
265   public void enterConstructor(
266     int declarationStart,
267     int modifiers,
268     char[] name,
269     int nameSourceStart,
270     int nameSourceEnd,
271     char[][] parameterTypes,
272     char[][] parameterNames,
273     char[][] exceptionTypes) {
274
275     enterMethod(
276       declarationStart,
277       modifiers,
278       null,
279       name,
280       nameSourceStart,
281       nameSourceEnd,
282       parameterTypes,
283       parameterNames,
284       exceptionTypes,
285       true);
286   }
287
288   /**
289    * @see ISourceElementRequestor
290    */
291   public void enterField(int declarationStart, int modifiers, char[] type, char[] name, int nameSourceStart, int nameSourceEnd) {
292
293     SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) infoStack.peek();
294     JavaElement parentHandle = (JavaElement) handleStack.peek();
295     IField handle = null;
296
297     if (parentHandle.getElementType() == IJavaElement.TYPE) {
298       handle = new SourceField(parentHandle, new String(name));
299     } else {
300       Assert.isTrue(false); // Should not happen
301     }
302     resolveDuplicates(handle);
303
304     SourceFieldElementInfo info = new SourceFieldElementInfo();
305     info.setName(name);
306     info.setNameSourceStart(nameSourceStart);
307     info.setNameSourceEnd(nameSourceEnd);
308     info.setSourceRangeStart(declarationStart);
309     info.setFlags(modifiers);
310     info.setTypeName(type);
311
312     parentInfo.addChild(handle);
313     newElements.put(handle, info);
314
315     infoStack.push(info);
316     handleStack.push(handle);
317   }
318   /**
319    * @see ISourceElementRequestor
320    */
321   //public void enterInitializer(
322   //    int declarationSourceStart,
323   //    int modifiers) {
324   //            JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
325   //            JavaElement parentHandle= (JavaElement)fHandleStack.peek();
326   //            IInitializer handle = null;
327   //            
328   //            if (parentHandle.getElementType() == IJavaElement.TYPE) {
329   //                    handle = ((IType) parentHandle).getInitializer(1);
330   //            }
331   //            else {
332   //                    Assert.isTrue(false); // Should not happen
333   //            }
334   //            resolveDuplicates(handle);
335   //            
336   //            InitializerElementInfo info = new InitializerElementInfo();
337   //            info.setSourceRangeStart(declarationSourceStart);
338   //            info.setFlags(modifiers);
339   //
340   //            parentInfo.addChild(handle);
341   //            fNewElements.put(handle, info);
342   //
343   //            fInfoStack.push(info);
344   //            fHandleStack.push(handle);
345   //}
346   /**
347    * @see ISourceElementRequestor
348    */
349   public void enterInterface(
350     int declarationStart,
351     int modifiers,
352     char[] name,
353     int nameSourceStart,
354     int nameSourceEnd,
355     char[][] superinterfaces) {
356
357     enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, null, superinterfaces);
358
359   }
360   /**
361    * @see ISourceElementRequestor
362    */
363   public void enterMethod(
364     int declarationStart,
365     int modifiers,
366     char[] returnType,
367     char[] name,
368     int nameSourceStart,
369     int nameSourceEnd,
370     char[][] parameterTypes,
371     char[][] parameterNames,
372     char[][] exceptionTypes) {
373
374     enterMethod(
375       declarationStart,
376       modifiers,
377       returnType,
378       name,
379       nameSourceStart,
380       nameSourceEnd,
381       parameterTypes,
382       parameterNames,
383       exceptionTypes,
384       false);
385   }
386   /**
387    * @see ISourceElementRequestor
388    */
389   protected void enterMethod(
390     int declarationStart,
391     int modifiers,
392     char[] returnType,
393     char[] name,
394     int nameSourceStart,
395     int nameSourceEnd,
396     char[][] parameterTypes,
397     char[][] parameterNames,
398     char[][] exceptionTypes,
399     boolean isConstructor) {
400     SourceTypeElementInfo parentInfo = null;
401     try {
402       parentInfo = (SourceTypeElementInfo) infoStack.peek();
403     } catch (ClassCastException e) {
404       //                        parentInfo = null;
405     }
406     JavaElement parentHandle = (JavaElement) handleStack.peek();
407     IMethod handle = null;
408
409     // translate nulls to empty arrays
410     if (parameterTypes == null) {
411       parameterTypes = fgEmptyCharChar;
412     }
413     if (parameterNames == null) {
414       parameterNames = fgEmptyCharChar;
415     }
416     if (exceptionTypes == null) {
417       exceptionTypes = fgEmptyCharChar;
418     }
419
420     String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
421     // TODO : jsurfer changed
422 //      if (parentHandle.getElementType() == IJavaElement.TYPE) {
423                 handle = new SourceMethod(parentHandle, new String(name), parameterTypeSigs);
424 //      }
425 //      else {
426 //              Assert.isTrue(false); // Should not happen
427 //      }
428         resolveDuplicates(handle);
429         
430     SourceMethodElementInfo info = new SourceMethodElementInfo();
431     info.setSourceRangeStart(declarationStart);
432     int flags = modifiers;
433     info.setName(name);
434     info.setNameSourceStart(nameSourceStart);
435     info.setNameSourceEnd(nameSourceEnd);
436     info.setConstructor(isConstructor);
437     info.setFlags(flags);
438     info.setArgumentNames(parameterNames);
439     info.setArgumentTypeNames(parameterTypes);
440     info.setReturnType(returnType == null ? new char[] { 'v', 'o', 'i', 'd' }
441     : returnType);
442     info.setExceptionTypeNames(exceptionTypes);
443
444     if (parentInfo == null) {
445       unitInfo.addChild(handle);
446     } else {
447       parentInfo.addChild(handle);
448     }
449     newElements.put(handle, info);
450     infoStack.push(info);
451     handleStack.push(handle);
452   }
453   /**
454    * Common processing for classes and interfaces.
455    */
456   protected void enterType(
457     int declarationStart,
458     int modifiers,
459     char[] name,
460     int nameSourceStart,
461     int nameSourceEnd,
462     char[] superclass,
463     char[][] superinterfaces) {
464
465     char[] enclosingTypeName = null;
466     char[] qualifiedName = null;
467
468     JavaElementInfo parentInfo = (JavaElementInfo) infoStack.peek();
469     JavaElement parentHandle = (JavaElement) handleStack.peek();
470     IType handle = null;
471     String nameString = new String(name);
472
473     if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
474       handle = ((ICompilationUnit) parentHandle).getType(nameString);
475       if (fPackageName == null) {
476         qualifiedName = nameString.toCharArray();
477       } else {
478         qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
479       }
480     } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
481       handle = ((IType) parentHandle).getType(nameString);
482       enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
483       qualifiedName = (new String(((SourceTypeElementInfo) parentInfo).getQualifiedName()) + "." + nameString).toCharArray(); //$NON-NLS-1$
484     } else {
485       Assert.isTrue(false); // Should not happen
486     }
487     resolveDuplicates(handle);
488
489     SourceTypeElementInfo info = new SourceTypeElementInfo();
490     info.setHandle(handle);
491     info.setSourceRangeStart(declarationStart);
492     info.setFlags(modifiers);
493     info.setName(name);
494     info.setNameSourceStart(nameSourceStart);
495     info.setNameSourceEnd(nameSourceEnd);
496     info.setSuperclassName(superclass);
497     info.setSuperInterfaceNames(superinterfaces);
498     info.setEnclosingTypeName(enclosingTypeName);
499     info.setSourceFileName(fSourceFileName);
500     info.setPackageName(fPackageName);
501     info.setQualifiedName(qualifiedName);
502     //  for (Iterator iter = fNewElements.keySet().iterator(); iter.hasNext();){
503     //          Object object = iter.next();
504     //          if (object instanceof IImportDeclaration)
505     //                  info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
506     //  }
507
508     parentInfo.addChild(handle);
509     newElements.put(handle, info);
510
511     infoStack.push(info);
512     handleStack.push(handle);
513
514   }
515   /**
516    * @see ISourceElementRequestor
517    */
518   public void exitClass(int declarationEnd) {
519
520     exitMember(declarationEnd);
521   }
522   /**
523    * @see ISourceElementRequestor
524    */
525   public void exitCompilationUnit(int declarationEnd) {
526     unitInfo.setSourceLength(declarationEnd + 1);
527
528     // determine if there were any parsing errors
529     unitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
530   }
531   /**
532    * @see ISourceElementRequestor
533    */
534   public void exitConstructor(int declarationEnd) {
535     exitMember(declarationEnd);
536   }
537   /**
538    * @see ISourceElementRequestor
539    */
540   public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
541         SourceFieldElementInfo info = (SourceFieldElementInfo) infoStack.pop();
542         info.setSourceRangeEnd(declarationSourceEnd);
543         
544         // remember initializer source if field is a constant
545         if (initializationStart != -1) {
546                 int flags = info.flags;
547                 Object typeInfo;
548                 if (Flags.isStatic(flags) && Flags.isFinal(flags)
549                                 || ((typeInfo = infoStack.peek()) instanceof SourceTypeElementInfo
550                                          && (Flags.isInterface(((SourceTypeElementInfo)typeInfo).flags)))) {
551                         int length = declarationEnd - initializationStart;
552                         if (length > 0) {
553                                 char[] initializer = new char[length];
554                                 System.arraycopy(this.parser.scanner.source, initializationStart, initializer, 0, length);
555                                 info.initializationSource = initializer;
556                         }
557                 }
558         }
559         handleStack.pop();
560   }
561   /**
562    * @see ISourceElementRequestor
563    */
564   public void exitInitializer(int declarationEnd) {
565     exitMember(declarationEnd);
566   }
567   /**
568    * @see ISourceElementRequestor
569    */
570   public void exitInterface(int declarationEnd) {
571     exitMember(declarationEnd);
572   }
573   /**
574    * common processing for classes and interfaces
575    */
576   protected void exitMember(int declarationEnd) {
577     SourceRefElementInfo info = (SourceRefElementInfo) infoStack.pop();
578     info.setSourceRangeEnd(declarationEnd);
579     handleStack.pop();
580   }
581   /**
582    * @see ISourceElementRequestor
583    */
584   public void exitMethod(int declarationEnd) {
585     exitMember(declarationEnd);
586   }
587
588   /**
589    * Resolves duplicate handles by incrementing the occurrence count
590    * of the handle being created until there is no conflict.
591    */
592   protected void resolveDuplicates(IJavaElement handle) {
593     while (newElements.containsKey(handle)) {
594       JavaElement h = (JavaElement) handle;
595       h.setOccurrenceCount(h.getOccurrenceCount() + 1);
596     }
597   }
598 }