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