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.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;
32 * A requestor for the fuzzy parser, used to compute the children of an ICompilationUnit.
34 public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter implements ISourceElementRequestor {
37 * The handle to the compilation unit being parsed
39 protected ICompilationUnit fUnit;
42 * The info object for the compilation unit being parsed
44 protected CompilationUnitElementInfo fUnitInfo;
47 * The import container info - null until created
49 protected JavaElementInfo fImportContainerInfo = null;
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
57 protected Map fNewElements;
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.
65 protected Stack fInfoStack;
68 * Stack of parent handles, corresponding to the info stack. We
69 * keep both, since info objects do not have back pointers to
72 protected Stack fHandleStack;
75 * The name of the source file being parsed.
77 protected char[] fSourceFileName = null;
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.
85 protected char[] fPackageName = null;
88 * The number of references reported thus far. Used to
89 * expand the arrays of reference kinds and names.
91 protected int fRefCount = 0;
94 * The initial size of the reference kind and name
95 * arrays. If the arrays fill, they are doubled in
98 protected static int fgReferenceAllocation = 50;
101 * Problem requestor which will get notified of discovered problems
103 protected boolean hasSyntaxErrors = false;
106 * The parser this requestor is using.
108 // protected Parser parser;
109 protected Parser parser;
112 * Empty collections used for efficient initialization
114 protected static String[] fgEmptyStringArray = new String[0];
115 protected static byte[] fgEmptyByte = new byte[] {
117 protected static char[][] fgEmptyCharChar = new char[][] {
119 protected static char[] fgEmptyChar = new char[] {
122 protected HashtableOfObject fieldRefCache;
123 protected HashtableOfObject messageRefCache;
124 protected HashtableOfObject typeRefCache;
125 protected HashtableOfObject unknownRefCache;
127 protected CompilationUnitStructureRequestor(ICompilationUnit unit, CompilationUnitElementInfo unitInfo, Map newElements)
128 throws JavaModelException {
130 this.fUnitInfo = unitInfo;
131 this.fNewElements = newElements;
132 this.fSourceFileName = unit.getElementName().toCharArray();
135 * @see ISourceElementRequestor
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
144 // ICompilationUnit parentCU= (ICompilationUnit)parentHandle;
145 // //create the import container and its info
146 // IImportContainer importContainer= parentCU.getImportContainer();
147 // if (fImportContainerInfo == null) {
148 // fImportContainerInfo= new JavaElementInfo();
149 // fImportContainerInfo.setIsStructureKnown(true);
150 // parentInfo.addChild(importContainer);
151 // fNewElements.put(importContainer, fImportContainerInfo);
154 // // tack on the '.*' if it is onDemand
155 // String importName;
157 // importName= new String(name) + ".*"; //$NON-NLS-1$
159 // importName= new String(name);
162 // ImportDeclaration handle = new ImportDeclaration(importContainer, importName);
163 // resolveDuplicates(handle);
165 // SourceRefElementInfo info = new SourceRefElementInfo();
166 // info.setSourceRangeStart(declarationStart);
167 // info.setSourceRangeEnd(declarationEnd);
169 // fImportContainerInfo.addChild(handle);
170 // fNewElements.put(handle, info);
173 * Table of line separator position. This table is passed once at the end
174 * of the parse action, so as to allow computation of normalized ranges.
176 * A line separator might corresponds to several characters in the source,
179 public void acceptLineSeparatorPositions(int[] positions) {
182 * @see ISourceElementRequestor
184 //public void acceptPackage(int declarationStart, int declarationEnd, char[] name) {
186 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
187 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
188 // IPackageDeclaration handle = null;
189 // fPackageName= name;
191 // if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
192 // handle = new PackageDeclaration((ICompilationUnit) parentHandle, new String(name));
195 // Assert.isTrue(false); // Should not happen
197 // resolveDuplicates(handle);
199 // SourceRefElementInfo info = new SourceRefElementInfo();
200 // info.setSourceRangeStart(declarationStart);
201 // info.setSourceRangeEnd(declarationEnd);
203 // parentInfo.addChild(handle);
204 // fNewElements.put(handle, info);
207 public void acceptProblem(IProblem problem) {
208 if ((problem.getID() & IProblem.Syntax) != 0) {
209 this.hasSyntaxErrors = true;
213 * Convert these type names to signatures.
217 static String[] convertTypeNamesToSigs(char[][] typeNames) {
218 if (typeNames == null)
219 return fgEmptyStringArray;
220 int n = typeNames.length;
222 return fgEmptyStringArray;
223 String[] typeSigs = new String[n];
224 for (int i = 0; i < n; ++i) {
225 typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
230 * @see ISourceElementRequestor
232 public void enterClass(
233 int declarationStart,
239 char[][] superinterfaces) {
241 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, superclass, superinterfaces);
245 * @see ISourceElementRequestor
247 public void enterCompilationUnit() {
248 fInfoStack = new Stack();
249 fHandleStack = new Stack();
250 fInfoStack.push(fUnitInfo);
251 fHandleStack.push(fUnit);
254 * @see ISourceElementRequestor
256 public void enterConstructor(
257 int declarationStart,
262 char[][] parameterTypes,
263 char[][] parameterNames,
264 char[][] exceptionTypes) {
280 * @see ISourceElementRequestor
282 public void enterField(int declarationStart, int modifiers, char[] type, char[] name, int nameSourceStart, int nameSourceEnd) {
284 SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
285 JavaElement parentHandle = (JavaElement) fHandleStack.peek();
286 IField handle = null;
288 if (parentHandle.getElementType() == IJavaElement.TYPE) {
289 handle = new SourceField(parentHandle, new String(name));
291 Assert.isTrue(false); // Should not happen
293 resolveDuplicates(handle);
295 SourceFieldElementInfo info = new SourceFieldElementInfo();
297 info.setNameSourceStart(nameSourceStart);
298 info.setNameSourceEnd(nameSourceEnd);
299 info.setSourceRangeStart(declarationStart);
300 info.setFlags(modifiers);
301 info.setTypeName(type);
303 parentInfo.addChild(handle);
304 fNewElements.put(handle, info);
306 fInfoStack.push(info);
307 fHandleStack.push(handle);
310 * @see ISourceElementRequestor
312 //public void enterInitializer(
313 // int declarationSourceStart,
315 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
316 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
317 // IInitializer handle = null;
319 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
320 // handle = ((IType) parentHandle).getInitializer(1);
323 // Assert.isTrue(false); // Should not happen
325 // resolveDuplicates(handle);
327 // InitializerElementInfo info = new InitializerElementInfo();
328 // info.setSourceRangeStart(declarationSourceStart);
329 // info.setFlags(modifiers);
331 // parentInfo.addChild(handle);
332 // fNewElements.put(handle, info);
334 // fInfoStack.push(info);
335 // fHandleStack.push(handle);
338 * @see ISourceElementRequestor
340 public void enterInterface(
341 int declarationStart,
346 char[][] superinterfaces) {
348 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, null, superinterfaces);
352 * @see ISourceElementRequestor
354 public void enterMethod(
355 int declarationStart,
361 char[][] parameterTypes,
362 char[][] parameterNames,
363 char[][] exceptionTypes) {
378 * @see ISourceElementRequestor
380 protected void enterMethod(
381 int declarationStart,
387 char[][] parameterTypes,
388 char[][] parameterNames,
389 char[][] exceptionTypes,
390 boolean isConstructor) {
391 SourceTypeElementInfo parentInfo = null;
393 parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
394 } catch (ClassCastException e) {
395 // parentInfo = null;
397 JavaElement parentHandle = (JavaElement) fHandleStack.peek();
398 IMethod handle = null;
400 // translate nulls to empty arrays
401 if (parameterTypes == null) {
402 parameterTypes = fgEmptyCharChar;
404 if (parameterNames == null) {
405 parameterNames = fgEmptyCharChar;
407 if (exceptionTypes == null) {
408 exceptionTypes = fgEmptyCharChar;
411 String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
412 // TODO : jsurfer changed
413 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
414 handle = new SourceMethod(parentHandle, new String(name), parameterTypeSigs);
417 // Assert.isTrue(false); // Should not happen
419 resolveDuplicates(handle);
421 SourceMethodElementInfo info = new SourceMethodElementInfo();
422 info.setSourceRangeStart(declarationStart);
423 int flags = modifiers;
425 info.setNameSourceStart(nameSourceStart);
426 info.setNameSourceEnd(nameSourceEnd);
427 info.setConstructor(isConstructor);
428 info.setFlags(flags);
429 info.setArgumentNames(parameterNames);
430 info.setArgumentTypeNames(parameterTypes);
431 info.setReturnType(returnType == null ? new char[] { 'v', 'o', 'i', 'd' }
433 info.setExceptionTypeNames(exceptionTypes);
435 if (parentInfo == null) {
436 fUnitInfo.addChild(handle);
438 parentInfo.addChild(handle);
440 fNewElements.put(handle, info);
441 fInfoStack.push(info);
442 fHandleStack.push(handle);
445 * Common processing for classes and interfaces.
447 protected void enterType(
448 int declarationStart,
454 char[][] superinterfaces) {
456 char[] enclosingTypeName = null;
457 char[] qualifiedName = null;
459 JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
460 JavaElement parentHandle = (JavaElement) fHandleStack.peek();
462 String nameString = new String(name);
464 if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
465 handle = ((ICompilationUnit) parentHandle).getType(nameString);
466 if (fPackageName == null) {
467 qualifiedName = nameString.toCharArray();
469 qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
471 } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
472 handle = ((IType) parentHandle).getType(nameString);
473 enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
474 qualifiedName = (new String(((SourceTypeElementInfo) parentInfo).getQualifiedName()) + "." + nameString).toCharArray(); //$NON-NLS-1$
476 Assert.isTrue(false); // Should not happen
478 resolveDuplicates(handle);
480 SourceTypeElementInfo info = new SourceTypeElementInfo();
481 info.setHandle(handle);
482 info.setSourceRangeStart(declarationStart);
483 info.setFlags(modifiers);
485 info.setNameSourceStart(nameSourceStart);
486 info.setNameSourceEnd(nameSourceEnd);
487 info.setSuperclassName(superclass);
488 info.setSuperInterfaceNames(superinterfaces);
489 info.setEnclosingTypeName(enclosingTypeName);
490 info.setSourceFileName(fSourceFileName);
491 info.setPackageName(fPackageName);
492 info.setQualifiedName(qualifiedName);
493 // for (Iterator iter = fNewElements.keySet().iterator(); iter.hasNext();){
494 // Object object = iter.next();
495 // if (object instanceof IImportDeclaration)
496 // info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
499 parentInfo.addChild(handle);
500 fNewElements.put(handle, info);
502 fInfoStack.push(info);
503 fHandleStack.push(handle);
507 * @see ISourceElementRequestor
509 public void exitClass(int declarationEnd) {
511 exitMember(declarationEnd);
514 * @see ISourceElementRequestor
516 public void exitCompilationUnit(int declarationEnd) {
517 fUnitInfo.setSourceLength(declarationEnd + 1);
519 // determine if there were any parsing errors
520 fUnitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
523 * @see ISourceElementRequestor
525 public void exitConstructor(int declarationEnd) {
526 exitMember(declarationEnd);
529 * @see ISourceElementRequestor
531 public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
532 SourceFieldElementInfo info = (SourceFieldElementInfo) fInfoStack.pop();
533 info.setSourceRangeEnd(declarationSourceEnd);
535 // remember initializer source if field is a constant
536 if (initializationStart != -1) {
537 int flags = info.flags;
539 if (Flags.isStatic(flags) && Flags.isFinal(flags)
540 || ((typeInfo = fInfoStack.peek()) instanceof SourceTypeElementInfo
541 && (Flags.isInterface(((SourceTypeElementInfo)typeInfo).flags)))) {
542 int length = declarationEnd - initializationStart;
544 char[] initializer = new char[length];
545 System.arraycopy(this.parser.scanner.source, initializationStart, initializer, 0, length);
546 info.initializationSource = initializer;
553 * @see ISourceElementRequestor
555 public void exitInitializer(int declarationEnd) {
556 exitMember(declarationEnd);
559 * @see ISourceElementRequestor
561 public void exitInterface(int declarationEnd) {
562 exitMember(declarationEnd);
565 * common processing for classes and interfaces
567 protected void exitMember(int declarationEnd) {
568 SourceRefElementInfo info = (SourceRefElementInfo) fInfoStack.pop();
569 info.setSourceRangeEnd(declarationEnd);
573 * @see ISourceElementRequestor
575 public void exitMethod(int declarationEnd) {
576 exitMember(declarationEnd);
580 * Resolves duplicate handles by incrementing the occurrence count
581 * of the handle being created until there is no conflict.
583 protected void resolveDuplicates(IJavaElement handle) {
584 while (fNewElements.containsKey(handle)) {
585 JavaElement h = (JavaElement) handle;
586 h.setOccurrenceCount(h.getOccurrenceCount() + 1);