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