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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core;
14 import java.util.Stack;
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;
33 * A requestor for the fuzzy parser, used to compute the children of an ICompilationUnit.
35 public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter implements ISourceElementRequestor {
38 * The handle to the compilation unit being parsed
40 protected ICompilationUnit fUnit;
43 * The info object for the compilation unit being parsed
45 protected CompilationUnitElementInfo fUnitInfo;
48 * The import container info - null until created
50 protected JavaElementInfo fImportContainerInfo = null;
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
58 protected Map fNewElements;
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.
66 protected Stack fInfoStack;
69 * Stack of parent handles, corresponding to the info stack. We
70 * keep both, since info objects do not have back pointers to
73 protected Stack fHandleStack;
76 * The name of the source file being parsed.
78 protected char[] fSourceFileName = null;
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.
86 protected char[] fPackageName = null;
89 * The number of references reported thus far. Used to
90 * expand the arrays of reference kinds and names.
92 protected int fRefCount = 0;
95 * The initial size of the reference kind and name
96 * arrays. If the arrays fill, they are doubled in
99 protected static int fgReferenceAllocation = 50;
102 * Problem requestor which will get notified of discovered problems
104 protected boolean hasSyntaxErrors = false;
107 * The parser this requestor is using.
109 // protected Parser parser;
110 protected Parser parser;
113 * Empty collections used for efficient initialization
115 protected static String[] fgEmptyStringArray = new String[0];
116 protected static byte[] fgEmptyByte = new byte[] {
118 protected static char[][] fgEmptyCharChar = new char[][] {
120 protected static char[] fgEmptyChar = new char[] {
123 protected HashtableOfObject fieldRefCache;
124 protected HashtableOfObject messageRefCache;
125 protected HashtableOfObject typeRefCache;
126 protected HashtableOfObject unknownRefCache;
128 protected CompilationUnitStructureRequestor(ICompilationUnit unit, CompilationUnitElementInfo unitInfo, Map newElements)
129 throws JavaModelException {
131 this.fUnitInfo = unitInfo;
132 this.fNewElements = newElements;
133 this.fSourceFileName = unit.getElementName().toCharArray();
136 * @see ISourceElementRequestor
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
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);
155 // tack on the '.*' if it is onDemand
158 importName= new String(name) + ".*"; //$NON-NLS-1$
160 importName= new String(name);
163 ImportDeclaration handle = new ImportDeclaration(importContainer, importName);
164 // ImportDeclaration handle = new ImportDeclaration(null, importName);
165 // resolveDuplicates(handle);
167 SourceRefElementInfo info = new SourceRefElementInfo();
168 info.setSourceRangeStart(declarationStart);
169 info.setSourceRangeEnd(declarationEnd);
171 fImportContainerInfo.addChild(handle);
172 fNewElements.put(handle, info);
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.
178 * A line separator might corresponds to several characters in the source,
181 public void acceptLineSeparatorPositions(int[] positions) {
184 * @see ISourceElementRequestor
186 //public void acceptPackage(int declarationStart, int declarationEnd, char[] name) {
188 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
189 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
190 // IPackageDeclaration handle = null;
191 // fPackageName= name;
193 // if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
194 // handle = new PackageDeclaration((ICompilationUnit) parentHandle, new String(name));
197 // Assert.isTrue(false); // Should not happen
199 // resolveDuplicates(handle);
201 // SourceRefElementInfo info = new SourceRefElementInfo();
202 // info.setSourceRangeStart(declarationStart);
203 // info.setSourceRangeEnd(declarationEnd);
205 // parentInfo.addChild(handle);
206 // fNewElements.put(handle, info);
209 public void acceptProblem(IProblem problem) {
210 if ((problem.getID() & IProblem.Syntax) != 0) {
211 this.hasSyntaxErrors = true;
215 * Convert these type names to signatures.
219 static String[] convertTypeNamesToSigs(char[][] typeNames) {
220 if (typeNames == null)
221 return fgEmptyStringArray;
222 int n = typeNames.length;
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);
232 * @see ISourceElementRequestor
234 public void enterClass(
235 int declarationStart,
241 char[][] superinterfaces) {
243 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, superclass, superinterfaces);
247 * @see ISourceElementRequestor
249 public void enterCompilationUnit() {
250 fInfoStack = new Stack();
251 fHandleStack = new Stack();
252 fInfoStack.push(fUnitInfo);
253 fHandleStack.push(fUnit);
256 * @see ISourceElementRequestor
258 public void enterConstructor(
259 int declarationStart,
264 char[][] parameterTypes,
265 char[][] parameterNames,
266 char[][] exceptionTypes) {
282 * @see ISourceElementRequestor
284 public void enterField(int declarationStart, int modifiers, char[] type, char[] name, int nameSourceStart, int nameSourceEnd) {
286 SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
287 JavaElement parentHandle = (JavaElement) fHandleStack.peek();
288 IField handle = null;
290 if (parentHandle.getElementType() == IJavaElement.TYPE) {
291 handle = new SourceField(parentHandle, new String(name));
293 Assert.isTrue(false); // Should not happen
295 resolveDuplicates(handle);
297 SourceFieldElementInfo info = new SourceFieldElementInfo();
299 info.setNameSourceStart(nameSourceStart);
300 info.setNameSourceEnd(nameSourceEnd);
301 info.setSourceRangeStart(declarationStart);
302 info.setFlags(modifiers);
303 info.setTypeName(type);
305 parentInfo.addChild(handle);
306 fNewElements.put(handle, info);
308 fInfoStack.push(info);
309 fHandleStack.push(handle);
312 * @see ISourceElementRequestor
314 //public void enterInitializer(
315 // int declarationSourceStart,
317 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
318 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
319 // IInitializer handle = null;
321 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
322 // handle = ((IType) parentHandle).getInitializer(1);
325 // Assert.isTrue(false); // Should not happen
327 // resolveDuplicates(handle);
329 // InitializerElementInfo info = new InitializerElementInfo();
330 // info.setSourceRangeStart(declarationSourceStart);
331 // info.setFlags(modifiers);
333 // parentInfo.addChild(handle);
334 // fNewElements.put(handle, info);
336 // fInfoStack.push(info);
337 // fHandleStack.push(handle);
340 * @see ISourceElementRequestor
342 public void enterInterface(
343 int declarationStart,
348 char[][] superinterfaces) {
350 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, null, superinterfaces);
354 * @see ISourceElementRequestor
356 public void enterMethod(
357 int declarationStart,
363 char[][] parameterTypes,
364 char[][] parameterNames,
365 char[][] exceptionTypes) {
380 * @see ISourceElementRequestor
382 protected void enterMethod(
383 int declarationStart,
389 char[][] parameterTypes,
390 char[][] parameterNames,
391 char[][] exceptionTypes,
392 boolean isConstructor) {
393 SourceTypeElementInfo parentInfo = null;
395 parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
396 } catch (ClassCastException e) {
397 // parentInfo = null;
399 JavaElement parentHandle = (JavaElement) fHandleStack.peek();
400 IMethod handle = null;
402 // translate nulls to empty arrays
403 if (parameterTypes == null) {
404 parameterTypes = fgEmptyCharChar;
406 if (parameterNames == null) {
407 parameterNames = fgEmptyCharChar;
409 if (exceptionTypes == null) {
410 exceptionTypes = fgEmptyCharChar;
413 String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
414 // TODO : jsurfer changed
415 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
416 handle = new SourceMethod(parentHandle, new String(name), parameterTypeSigs);
419 // Assert.isTrue(false); // Should not happen
421 resolveDuplicates(handle);
423 SourceMethodElementInfo info = new SourceMethodElementInfo();
424 info.setSourceRangeStart(declarationStart);
425 int flags = modifiers;
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' }
435 info.setExceptionTypeNames(exceptionTypes);
437 if (parentInfo == null) {
438 fUnitInfo.addChild(handle);
440 parentInfo.addChild(handle);
442 fNewElements.put(handle, info);
443 fInfoStack.push(info);
444 fHandleStack.push(handle);
447 * Common processing for classes and interfaces.
449 protected void enterType(
450 int declarationStart,
456 char[][] superinterfaces) {
458 char[] enclosingTypeName = null;
459 char[] qualifiedName = null;
461 JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
462 JavaElement parentHandle = (JavaElement) fHandleStack.peek();
464 String nameString = new String(name);
466 if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
467 handle = ((ICompilationUnit) parentHandle).getType(nameString);
468 if (fPackageName == null) {
469 qualifiedName = nameString.toCharArray();
471 qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
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$
478 Assert.isTrue(false); // Should not happen
480 resolveDuplicates(handle);
482 SourceTypeElementInfo info = new SourceTypeElementInfo();
483 info.setHandle(handle);
484 info.setSourceRangeStart(declarationStart);
485 info.setFlags(modifiers);
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());
501 parentInfo.addChild(handle);
502 fNewElements.put(handle, info);
504 fInfoStack.push(info);
505 fHandleStack.push(handle);
509 * @see ISourceElementRequestor
511 public void exitClass(int declarationEnd) {
513 exitMember(declarationEnd);
516 * @see ISourceElementRequestor
518 public void exitCompilationUnit(int declarationEnd) {
519 fUnitInfo.setSourceLength(declarationEnd + 1);
521 // determine if there were any parsing errors
522 fUnitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
525 * @see ISourceElementRequestor
527 public void exitConstructor(int declarationEnd) {
528 exitMember(declarationEnd);
531 * @see ISourceElementRequestor
533 public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
534 SourceFieldElementInfo info = (SourceFieldElementInfo) fInfoStack.pop();
535 info.setSourceRangeEnd(declarationSourceEnd);
537 // remember initializer source if field is a constant
538 if (initializationStart != -1) {
539 int flags = info.flags;
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;
546 char[] initializer = new char[length];
547 System.arraycopy(this.parser.scanner.source, initializationStart, initializer, 0, length);
548 info.initializationSource = initializer;
555 * @see ISourceElementRequestor
557 public void exitInitializer(int declarationEnd) {
558 exitMember(declarationEnd);
561 * @see ISourceElementRequestor
563 public void exitInterface(int declarationEnd) {
564 exitMember(declarationEnd);
567 * common processing for classes and interfaces
569 protected void exitMember(int declarationEnd) {
570 SourceRefElementInfo info = (SourceRefElementInfo) fInfoStack.pop();
571 info.setSourceRangeEnd(declarationEnd);
575 * @see ISourceElementRequestor
577 public void exitMethod(int declarationEnd) {
578 exitMember(declarationEnd);
582 * Resolves duplicate handles by incrementing the occurrence count
583 * of the handle being created until there is no conflict.
585 protected void resolveDuplicates(IJavaElement handle) {
586 while (fNewElements.containsKey(handle)) {
587 JavaElement h = (JavaElement) handle;
588 h.setOccurrenceCount(h.getOccurrenceCount() + 1);