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