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 unit;
42 * The info object for the compilation unit being parsed
44 protected CompilationUnitElementInfo unitInfo;
47 * The import container info - null until created
49 protected JavaElementInfo importContainerInfo = 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 newElements;
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 infoStack;
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 handleStack;
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.unitInfo = unitInfo;
131 this.newElements = newElements;
132 this.fSourceFileName = unit.getElementName().toCharArray();
135 * @see ISourceElementRequestor
137 public void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand) {
140 JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
141 JavaElement parentHandle= (JavaElement) this.handleStack.peek();
142 if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
143 Assert.isTrue(false); // Should not happen
146 ICompilationUnit parentCU= (ICompilationUnit)parentHandle;
147 //create the import container and its info
148 ImportContainer importContainer= (ImportContainer)parentCU.getImportContainer();
149 if (this.importContainerInfo == null) {
150 this.importContainerInfo= new JavaElementInfo();
151 this.importContainerInfo.setIsStructureKnown(true);
152 parentInfo.addChild(importContainer);
153 this.newElements.put(importContainer, this.importContainerInfo);
156 // tack on the '.*' if it is onDemand
159 importName= new String(name) + ".*"; //$NON-NLS-1$
161 importName= new String(name);
164 ImportDeclaration handle = new ImportDeclaration(importContainer, importName);
165 resolveDuplicates(handle);
167 ImportDeclarationElementInfo info = new ImportDeclarationElementInfo();
168 info.setSourceRangeStart(declarationStart);
169 info.setSourceRangeEnd(declarationEnd);
170 // info.setFlags(modifiers);
171 info.setName(name); // no trailing * if onDemand
172 info.setOnDemand(onDemand);
174 this.importContainerInfo.addChild(handle);
175 this.newElements.put(handle, info);
178 * @see ISourceElementRequestor
182 * Table of line separator position. This table is passed once at the end
183 * of the parse action, so as to allow computation of normalized ranges.
185 * A line separator might corresponds to several characters in the source,
188 public void acceptLineSeparatorPositions(int[] positions) {
191 * @see ISourceElementRequestor
193 //public void acceptPackage(int declarationStart, int declarationEnd, char[] name) {
195 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
196 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
197 // IPackageDeclaration handle = null;
198 // fPackageName= name;
200 // if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
201 // handle = new PackageDeclaration((ICompilationUnit) parentHandle, new String(name));
204 // Assert.isTrue(false); // Should not happen
206 // resolveDuplicates(handle);
208 // SourceRefElementInfo info = new SourceRefElementInfo();
209 // info.setSourceRangeStart(declarationStart);
210 // info.setSourceRangeEnd(declarationEnd);
212 // parentInfo.addChild(handle);
213 // fNewElements.put(handle, info);
216 public void acceptProblem(IProblem problem) {
217 if ((problem.getID() & IProblem.Syntax) != 0) {
218 this.hasSyntaxErrors = true;
222 * Convert these type names to signatures.
226 static String[] convertTypeNamesToSigs(char[][] typeNames) {
227 if (typeNames == null)
228 return fgEmptyStringArray;
229 int n = typeNames.length;
231 return fgEmptyStringArray;
232 String[] typeSigs = new String[n];
233 for (int i = 0; i < n; ++i) {
234 typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
239 * @see ISourceElementRequestor
241 public void enterClass(
242 int declarationStart,
248 char[][] superinterfaces) {
250 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, superclass, superinterfaces);
254 * @see ISourceElementRequestor
256 public void enterCompilationUnit() {
257 infoStack = new Stack();
258 handleStack = new Stack();
259 infoStack.push(unitInfo);
260 handleStack.push(unit);
263 * @see ISourceElementRequestor
265 public void enterConstructor(
266 int declarationStart,
271 char[][] parameterTypes,
272 char[][] parameterNames,
273 char[][] exceptionTypes) {
289 * @see ISourceElementRequestor
291 public void enterField(int declarationStart, int modifiers, char[] type, char[] name, int nameSourceStart, int nameSourceEnd) {
293 SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) infoStack.peek();
294 JavaElement parentHandle = (JavaElement) handleStack.peek();
295 IField handle = null;
297 if (parentHandle.getElementType() == IJavaElement.TYPE) {
298 handle = new SourceField(parentHandle, new String(name));
300 Assert.isTrue(false); // Should not happen
302 resolveDuplicates(handle);
304 SourceFieldElementInfo info = new SourceFieldElementInfo();
306 info.setNameSourceStart(nameSourceStart);
307 info.setNameSourceEnd(nameSourceEnd);
308 info.setSourceRangeStart(declarationStart);
309 info.setFlags(modifiers);
310 info.setTypeName(type);
312 parentInfo.addChild(handle);
313 newElements.put(handle, info);
315 infoStack.push(info);
316 handleStack.push(handle);
319 * @see ISourceElementRequestor
321 //public void enterInitializer(
322 // int declarationSourceStart,
324 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
325 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
326 // IInitializer handle = null;
328 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
329 // handle = ((IType) parentHandle).getInitializer(1);
332 // Assert.isTrue(false); // Should not happen
334 // resolveDuplicates(handle);
336 // InitializerElementInfo info = new InitializerElementInfo();
337 // info.setSourceRangeStart(declarationSourceStart);
338 // info.setFlags(modifiers);
340 // parentInfo.addChild(handle);
341 // fNewElements.put(handle, info);
343 // fInfoStack.push(info);
344 // fHandleStack.push(handle);
347 * @see ISourceElementRequestor
349 public void enterInterface(
350 int declarationStart,
355 char[][] superinterfaces) {
357 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, null, superinterfaces);
361 * @see ISourceElementRequestor
363 public void enterMethod(
364 int declarationStart,
370 char[][] parameterTypes,
371 char[][] parameterNames,
372 char[][] exceptionTypes) {
387 * @see ISourceElementRequestor
389 protected void enterMethod(
390 int declarationStart,
396 char[][] parameterTypes,
397 char[][] parameterNames,
398 char[][] exceptionTypes,
399 boolean isConstructor) {
400 SourceTypeElementInfo parentInfo = null;
402 parentInfo = (SourceTypeElementInfo) infoStack.peek();
403 } catch (ClassCastException e) {
404 // parentInfo = null;
406 JavaElement parentHandle = (JavaElement) handleStack.peek();
407 IMethod handle = null;
409 // translate nulls to empty arrays
410 if (parameterTypes == null) {
411 parameterTypes = fgEmptyCharChar;
413 if (parameterNames == null) {
414 parameterNames = fgEmptyCharChar;
416 if (exceptionTypes == null) {
417 exceptionTypes = fgEmptyCharChar;
420 String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
421 // TODO : jsurfer changed
422 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
423 handle = new SourceMethod(parentHandle, new String(name), parameterTypeSigs);
426 // Assert.isTrue(false); // Should not happen
428 resolveDuplicates(handle);
430 SourceMethodElementInfo info = new SourceMethodElementInfo();
431 info.setSourceRangeStart(declarationStart);
432 int flags = modifiers;
434 info.setNameSourceStart(nameSourceStart);
435 info.setNameSourceEnd(nameSourceEnd);
436 info.setConstructor(isConstructor);
437 info.setFlags(flags);
438 info.setArgumentNames(parameterNames);
439 info.setArgumentTypeNames(parameterTypes);
440 info.setReturnType(returnType == null ? new char[] { 'v', 'o', 'i', 'd' }
442 info.setExceptionTypeNames(exceptionTypes);
444 if (parentInfo == null) {
445 unitInfo.addChild(handle);
447 parentInfo.addChild(handle);
449 newElements.put(handle, info);
450 infoStack.push(info);
451 handleStack.push(handle);
454 * Common processing for classes and interfaces.
456 protected void enterType(
457 int declarationStart,
463 char[][] superinterfaces) {
465 char[] enclosingTypeName = null;
466 char[] qualifiedName = null;
468 JavaElementInfo parentInfo = (JavaElementInfo) infoStack.peek();
469 JavaElement parentHandle = (JavaElement) handleStack.peek();
471 String nameString = new String(name);
473 if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
474 handle = ((ICompilationUnit) parentHandle).getType(nameString);
475 if (fPackageName == null) {
476 qualifiedName = nameString.toCharArray();
478 qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
480 } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
481 handle = ((IType) parentHandle).getType(nameString);
482 enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
483 qualifiedName = (new String(((SourceTypeElementInfo) parentInfo).getQualifiedName()) + "." + nameString).toCharArray(); //$NON-NLS-1$
485 Assert.isTrue(false); // Should not happen
487 resolveDuplicates(handle);
489 SourceTypeElementInfo info = new SourceTypeElementInfo();
490 info.setHandle(handle);
491 info.setSourceRangeStart(declarationStart);
492 info.setFlags(modifiers);
494 info.setNameSourceStart(nameSourceStart);
495 info.setNameSourceEnd(nameSourceEnd);
496 info.setSuperclassName(superclass);
497 info.setSuperInterfaceNames(superinterfaces);
498 info.setEnclosingTypeName(enclosingTypeName);
499 info.setSourceFileName(fSourceFileName);
500 info.setPackageName(fPackageName);
501 info.setQualifiedName(qualifiedName);
502 // for (Iterator iter = fNewElements.keySet().iterator(); iter.hasNext();){
503 // Object object = iter.next();
504 // if (object instanceof IImportDeclaration)
505 // info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
508 parentInfo.addChild(handle);
509 newElements.put(handle, info);
511 infoStack.push(info);
512 handleStack.push(handle);
516 * @see ISourceElementRequestor
518 public void exitClass(int declarationEnd) {
520 exitMember(declarationEnd);
523 * @see ISourceElementRequestor
525 public void exitCompilationUnit(int declarationEnd) {
526 unitInfo.setSourceLength(declarationEnd + 1);
528 // determine if there were any parsing errors
529 unitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
532 * @see ISourceElementRequestor
534 public void exitConstructor(int declarationEnd) {
535 exitMember(declarationEnd);
538 * @see ISourceElementRequestor
540 public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
541 SourceFieldElementInfo info = (SourceFieldElementInfo) infoStack.pop();
542 info.setSourceRangeEnd(declarationSourceEnd);
544 // remember initializer source if field is a constant
545 if (initializationStart != -1) {
546 int flags = info.flags;
548 if (Flags.isStatic(flags) && Flags.isFinal(flags)
549 || ((typeInfo = infoStack.peek()) instanceof SourceTypeElementInfo
550 && (Flags.isInterface(((SourceTypeElementInfo)typeInfo).flags)))) {
551 int length = declarationEnd - initializationStart;
553 char[] initializer = new char[length];
554 System.arraycopy(this.parser.scanner.source, initializationStart, initializer, 0, length);
555 info.initializationSource = initializer;
562 * @see ISourceElementRequestor
564 public void exitInitializer(int declarationEnd) {
565 exitMember(declarationEnd);
568 * @see ISourceElementRequestor
570 public void exitInterface(int declarationEnd) {
571 exitMember(declarationEnd);
574 * common processing for classes and interfaces
576 protected void exitMember(int declarationEnd) {
577 SourceRefElementInfo info = (SourceRefElementInfo) infoStack.pop();
578 info.setSourceRangeEnd(declarationEnd);
582 * @see ISourceElementRequestor
584 public void exitMethod(int declarationEnd) {
585 exitMember(declarationEnd);
589 * Resolves duplicate handles by incrementing the occurrence count
590 * of the handle being created until there is no conflict.
592 protected void resolveDuplicates(IJavaElement handle) {
593 while (newElements.containsKey(handle)) {
594 JavaElement h = (JavaElement) handle;
595 h.setOccurrenceCount(h.getOccurrenceCount() + 1);