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;
13 import java.util.HashMap;
14 import java.util.HashSet;
16 import java.util.Stack;
18 import net.sourceforge.phpdt.internal.core.ImportContainer;
19 import net.sourceforge.phpdt.internal.core.ImportDeclaration;
20 import net.sourceforge.phpdt.internal.core.ImportDeclarationElementInfo;
21 import net.sourceforge.phpdt.internal.core.JavaElement;
22 import net.sourceforge.phpdt.internal.core.JavaElementInfo;
24 import net.sourceforge.phpdt.core.Flags;
25 import net.sourceforge.phpdt.core.ICompilationUnit;
26 import net.sourceforge.phpdt.core.IField;
27 import net.sourceforge.phpdt.core.IJavaElement;
28 import net.sourceforge.phpdt.core.IMethod;
29 import net.sourceforge.phpdt.core.IType;
30 import net.sourceforge.phpdt.core.JavaModelException;
31 import net.sourceforge.phpdt.core.Signature;
32 import net.sourceforge.phpdt.core.compiler.IProblem;
33 import net.sourceforge.phpdt.internal.compiler.ISourceElementRequestor;
34 import net.sourceforge.phpdt.internal.compiler.parser.Parser;
35 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject;
36 import net.sourceforge.phpdt.internal.core.util.ReferenceInfoAdapter;
37 import net.sourceforge.phpdt.internal.corext.Assert;
40 * A requestor for the fuzzy parser, used to compute the children of an ICompilationUnit.
42 public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter implements ISourceElementRequestor {
45 * The handle to the compilation unit being parsed
47 protected ICompilationUnit unit;
50 * The info object for the compilation unit being parsed
52 protected CompilationUnitElementInfo unitInfo;
55 * The import container info - null until created
57 protected JavaElementInfo importContainerInfo = null;
60 * Hashtable of children elements of the compilation unit.
61 * Children are added to the table as they are found by
62 * the parser. Keys are handles, values are corresponding
65 protected Map newElements;
68 * Stack of parent scope info objects. The info on the
69 * top of the stack is the parent of the next element found.
70 * For example, when we locate a method, the parent info object
71 * will be the type the method is contained in.
73 protected Stack infoStack;
76 * Stack of parent handles, corresponding to the info stack. We
77 * keep both, since info objects do not have back pointers to
80 protected Stack handleStack;
83 * The name of the source file being parsed.
85 protected char[] fSourceFileName = null;
88 * The dot-separated name of the package the compilation unit
89 * is contained in - based on the package statement in the
90 * compilation unit, and initialized by #acceptPackage.
91 * Initialized to <code>null</code> for the default package.
93 protected char[] fPackageName = null;
96 * The number of references reported thus far. Used to
97 * expand the arrays of reference kinds and names.
99 protected int fRefCount = 0;
102 * The initial size of the reference kind and name
103 * arrays. If the arrays fill, they are doubled in
106 protected static int fgReferenceAllocation = 50;
109 * Problem requestor which will get notified of discovered problems
111 protected boolean hasSyntaxErrors = false;
114 * The parser this requestor is using.
116 // protected Parser parser;
117 protected Parser parser;
120 * Empty collections used for efficient initialization
122 protected static String[] fgEmptyStringArray = new String[0];
123 protected static byte[] fgEmptyByte = new byte[] {
125 protected static char[][] fgEmptyCharChar = new char[][] {
127 protected static char[] fgEmptyChar = new char[] {
130 protected HashtableOfObject fieldRefCache;
131 protected HashtableOfObject messageRefCache;
132 protected HashtableOfObject typeRefCache;
133 protected HashtableOfObject unknownRefCache;
135 protected CompilationUnitStructureRequestor(ICompilationUnit unit, CompilationUnitElementInfo unitInfo, Map newElements)
136 throws JavaModelException {
138 this.unitInfo = unitInfo;
139 this.newElements = newElements;
140 this.fSourceFileName = unit.getElementName().toCharArray();
143 * @see ISourceElementRequestor
145 public void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand) {
148 JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
149 JavaElement parentHandle= (JavaElement) this.handleStack.peek();
150 if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
151 Assert.isTrue(false); // Should not happen
154 ICompilationUnit parentCU= (ICompilationUnit)parentHandle;
155 //create the import container and its info
156 ImportContainer importContainer= (ImportContainer)parentCU.getImportContainer();
157 if (this.importContainerInfo == null) {
158 this.importContainerInfo= new JavaElementInfo();
159 this.importContainerInfo.setIsStructureKnown(true);
160 parentInfo.addChild(importContainer);
161 this.newElements.put(importContainer, this.importContainerInfo);
164 // tack on the '.*' if it is onDemand
167 importName= new String(name) + ".*"; //$NON-NLS-1$
169 importName= new String(name);
172 ImportDeclaration handle = new ImportDeclaration(importContainer, importName);
173 resolveDuplicates(handle);
175 ImportDeclarationElementInfo info = new ImportDeclarationElementInfo();
176 info.setSourceRangeStart(declarationStart);
177 info.setSourceRangeEnd(declarationEnd);
178 // info.setFlags(modifiers);
179 info.setName(name); // no trailing * if onDemand
180 info.setOnDemand(onDemand);
182 this.importContainerInfo.addChild(handle);
183 this.newElements.put(handle, info);
186 * @see ISourceElementRequestor
190 * Table of line separator position. This table is passed once at the end
191 * of the parse action, so as to allow computation of normalized ranges.
193 * A line separator might corresponds to several characters in the source,
196 public void acceptLineSeparatorPositions(int[] positions) {
199 * @see ISourceElementRequestor
201 //public void acceptPackage(int declarationStart, int declarationEnd, char[] name) {
203 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
204 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
205 // IPackageDeclaration handle = null;
206 // fPackageName= name;
208 // if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
209 // handle = new PackageDeclaration((ICompilationUnit) parentHandle, new String(name));
212 // Assert.isTrue(false); // Should not happen
214 // resolveDuplicates(handle);
216 // SourceRefElementInfo info = new SourceRefElementInfo();
217 // info.setSourceRangeStart(declarationStart);
218 // info.setSourceRangeEnd(declarationEnd);
220 // parentInfo.addChild(handle);
221 // fNewElements.put(handle, info);
224 public void acceptProblem(IProblem problem) {
225 if ((problem.getID() & IProblem.Syntax) != 0) {
226 this.hasSyntaxErrors = true;
230 * Convert these type names to signatures.
234 static String[] convertTypeNamesToSigs(char[][] typeNames) {
235 if (typeNames == null)
236 return fgEmptyStringArray;
237 int n = typeNames.length;
239 return fgEmptyStringArray;
240 String[] typeSigs = new String[n];
241 for (int i = 0; i < n; ++i) {
242 typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
247 * @see ISourceElementRequestor
249 public void enterClass(
250 int declarationStart,
256 char[][] superinterfaces) {
258 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, superclass, superinterfaces);
262 * @see ISourceElementRequestor
264 public void enterCompilationUnit() {
265 infoStack = new Stack();
266 handleStack = new Stack();
267 infoStack.push(unitInfo);
268 handleStack.push(unit);
271 * @see ISourceElementRequestor
273 public void enterConstructor(
274 int declarationStart,
279 char[][] parameterTypes,
280 char[][] parameterNames,
281 char[][] exceptionTypes) {
297 * @see ISourceElementRequestor
299 public void enterField(int declarationStart, int modifiers, char[] type, char[] name, int nameSourceStart, int nameSourceEnd) {
301 SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) infoStack.peek();
302 JavaElement parentHandle = (JavaElement) handleStack.peek();
303 IField handle = null;
305 if (parentHandle.getElementType() == IJavaElement.TYPE) {
306 handle = new SourceField(parentHandle, new String(name));
308 Assert.isTrue(false); // Should not happen
310 resolveDuplicates(handle);
312 SourceFieldElementInfo info = new SourceFieldElementInfo();
314 info.setNameSourceStart(nameSourceStart);
315 info.setNameSourceEnd(nameSourceEnd);
316 info.setSourceRangeStart(declarationStart);
317 info.setFlags(modifiers);
318 info.setTypeName(type);
320 parentInfo.addChild(handle);
321 newElements.put(handle, info);
323 infoStack.push(info);
324 handleStack.push(handle);
327 * @see ISourceElementRequestor
329 //public void enterInitializer(
330 // int declarationSourceStart,
332 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
333 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
334 // IInitializer handle = null;
336 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
337 // handle = ((IType) parentHandle).getInitializer(1);
340 // Assert.isTrue(false); // Should not happen
342 // resolveDuplicates(handle);
344 // InitializerElementInfo info = new InitializerElementInfo();
345 // info.setSourceRangeStart(declarationSourceStart);
346 // info.setFlags(modifiers);
348 // parentInfo.addChild(handle);
349 // fNewElements.put(handle, info);
351 // fInfoStack.push(info);
352 // fHandleStack.push(handle);
355 * @see ISourceElementRequestor
357 public void enterInterface(
358 int declarationStart,
363 char[][] superinterfaces) {
365 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, null, superinterfaces);
369 * @see ISourceElementRequestor
371 public void enterMethod(
372 int declarationStart,
378 char[][] parameterTypes,
379 char[][] parameterNames,
380 char[][] exceptionTypes) {
395 * @see ISourceElementRequestor
397 protected void enterMethod(
398 int declarationStart,
404 char[][] parameterTypes,
405 char[][] parameterNames,
406 char[][] exceptionTypes,
407 boolean isConstructor) {
408 SourceTypeElementInfo parentInfo = null;
410 parentInfo = (SourceTypeElementInfo) infoStack.peek();
411 } catch (ClassCastException e) {
412 // parentInfo = null;
414 JavaElement parentHandle = (JavaElement) handleStack.peek();
415 IMethod handle = null;
417 // translate nulls to empty arrays
418 if (parameterTypes == null) {
419 parameterTypes = fgEmptyCharChar;
421 if (parameterNames == null) {
422 parameterNames = fgEmptyCharChar;
424 if (exceptionTypes == null) {
425 exceptionTypes = fgEmptyCharChar;
428 String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
429 // TODO : jsurfer changed
430 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
431 handle = new SourceMethod(parentHandle, new String(name), parameterTypeSigs);
434 // Assert.isTrue(false); // Should not happen
436 resolveDuplicates(handle);
438 SourceMethodElementInfo info = new SourceMethodElementInfo();
439 info.setSourceRangeStart(declarationStart);
440 int flags = modifiers;
442 info.setNameSourceStart(nameSourceStart);
443 info.setNameSourceEnd(nameSourceEnd);
444 info.setConstructor(isConstructor);
445 info.setFlags(flags);
446 info.setArgumentNames(parameterNames);
447 info.setArgumentTypeNames(parameterTypes);
448 info.setReturnType(returnType == null ? new char[] { 'v', 'o', 'i', 'd' }
450 info.setExceptionTypeNames(exceptionTypes);
452 if (parentInfo == null) {
453 unitInfo.addChild(handle);
455 parentInfo.addChild(handle);
457 newElements.put(handle, info);
458 infoStack.push(info);
459 handleStack.push(handle);
462 * Common processing for classes and interfaces.
464 protected void enterType(
465 int declarationStart,
471 char[][] superinterfaces) {
473 char[] enclosingTypeName = null;
474 char[] qualifiedName = null;
476 JavaElementInfo parentInfo = (JavaElementInfo) infoStack.peek();
477 JavaElement parentHandle = (JavaElement) handleStack.peek();
479 String nameString = new String(name);
481 if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
482 handle = ((ICompilationUnit) parentHandle).getType(nameString);
483 if (fPackageName == null) {
484 qualifiedName = nameString.toCharArray();
486 qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
488 } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
489 handle = ((IType) parentHandle).getType(nameString);
490 enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
491 qualifiedName = (new String(((SourceTypeElementInfo) parentInfo).getQualifiedName()) + "." + nameString).toCharArray(); //$NON-NLS-1$
493 Assert.isTrue(false); // Should not happen
495 resolveDuplicates(handle);
497 SourceTypeElementInfo info = new SourceTypeElementInfo();
498 info.setHandle(handle);
499 info.setSourceRangeStart(declarationStart);
500 info.setFlags(modifiers);
502 info.setNameSourceStart(nameSourceStart);
503 info.setNameSourceEnd(nameSourceEnd);
504 info.setSuperclassName(superclass);
505 info.setSuperInterfaceNames(superinterfaces);
506 info.setEnclosingTypeName(enclosingTypeName);
507 info.setSourceFileName(fSourceFileName);
508 info.setPackageName(fPackageName);
509 info.setQualifiedName(qualifiedName);
510 // for (Iterator iter = fNewElements.keySet().iterator(); iter.hasNext();){
511 // Object object = iter.next();
512 // if (object instanceof IImportDeclaration)
513 // info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
516 parentInfo.addChild(handle);
517 newElements.put(handle, info);
519 infoStack.push(info);
520 handleStack.push(handle);
524 * @see ISourceElementRequestor
526 public void exitClass(int declarationEnd) {
528 exitMember(declarationEnd);
531 * @see ISourceElementRequestor
533 public void exitCompilationUnit(int declarationEnd) {
534 unitInfo.setSourceLength(declarationEnd + 1);
536 // determine if there were any parsing errors
537 unitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
540 * @see ISourceElementRequestor
542 public void exitConstructor(int declarationEnd) {
543 exitMember(declarationEnd);
546 * @see ISourceElementRequestor
548 public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
549 SourceFieldElementInfo info = (SourceFieldElementInfo) infoStack.pop();
550 info.setSourceRangeEnd(declarationSourceEnd);
552 // remember initializer source if field is a constant
553 if (initializationStart != -1) {
554 int flags = info.flags;
556 if (Flags.isStatic(flags) && Flags.isFinal(flags)
557 || ((typeInfo = infoStack.peek()) instanceof SourceTypeElementInfo
558 && (Flags.isInterface(((SourceTypeElementInfo)typeInfo).flags)))) {
559 int length = declarationEnd - initializationStart;
561 char[] initializer = new char[length];
562 System.arraycopy(this.parser.scanner.source, initializationStart, initializer, 0, length);
563 info.initializationSource = initializer;
570 * @see ISourceElementRequestor
572 public void exitInitializer(int declarationEnd) {
573 exitMember(declarationEnd);
576 * @see ISourceElementRequestor
578 public void exitInterface(int declarationEnd) {
579 exitMember(declarationEnd);
582 * common processing for classes and interfaces
584 protected void exitMember(int declarationEnd) {
585 SourceRefElementInfo info = (SourceRefElementInfo) infoStack.pop();
586 info.setSourceRangeEnd(declarationEnd);
590 * @see ISourceElementRequestor
592 public void exitMethod(int declarationEnd) {
593 exitMember(declarationEnd);
597 * Resolves duplicate handles by incrementing the occurrence count
598 * of the handle being created until there is no conflict.
600 protected void resolveDuplicates(IJavaElement handle) {
601 while (newElements.containsKey(handle)) {
602 JavaElement h = (JavaElement) handle;
603 h.setOccurrenceCount(h.getOccurrenceCount() + 1);