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