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.ICompilationUnit;
17 import net.sourceforge.phpdt.core.IField;
18 import net.sourceforge.phpdt.core.IJavaElement;
19 import net.sourceforge.phpdt.core.IMethod;
20 import net.sourceforge.phpdt.core.IType;
21 import net.sourceforge.phpdt.core.JavaModelException;
22 import net.sourceforge.phpdt.core.Signature;
23 import net.sourceforge.phpdt.core.compiler.IProblem;
24 import net.sourceforge.phpdt.internal.compiler.ISourceElementRequestor;
25 import net.sourceforge.phpdt.internal.compiler.parser.Parser;
26 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject;
27 import net.sourceforge.phpdt.internal.core.util.ReferenceInfoAdapter;
28 import net.sourceforge.phpdt.internal.corext.Assert;
31 * A requestor for the fuzzy parser, used to compute the children of an ICompilationUnit.
33 public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter implements ISourceElementRequestor {
36 * The handle to the compilation unit being parsed
38 protected ICompilationUnit fUnit;
41 * The info object for the compilation unit being parsed
43 protected CompilationUnitElementInfo fUnitInfo;
46 * The import container info - null until created
48 protected JavaElementInfo fImportContainerInfo = null;
51 * Hashtable of children elements of the compilation unit.
52 * Children are added to the table as they are found by
53 * the parser. Keys are handles, values are corresponding
56 protected Map fNewElements;
59 * Stack of parent scope info objects. The info on the
60 * top of the stack is the parent of the next element found.
61 * For example, when we locate a method, the parent info object
62 * will be the type the method is contained in.
64 protected Stack fInfoStack;
67 * Stack of parent handles, corresponding to the info stack. We
68 * keep both, since info objects do not have back pointers to
71 protected Stack fHandleStack;
74 * The name of the source file being parsed.
76 protected char[] fSourceFileName = null;
79 * The dot-separated name of the package the compilation unit
80 * is contained in - based on the package statement in the
81 * compilation unit, and initialized by #acceptPackage.
82 * Initialized to <code>null</code> for the default package.
84 protected char[] fPackageName = null;
87 * The number of references reported thus far. Used to
88 * expand the arrays of reference kinds and names.
90 protected int fRefCount = 0;
93 * The initial size of the reference kind and name
94 * arrays. If the arrays fill, they are doubled in
97 protected static int fgReferenceAllocation = 50;
100 * Problem requestor which will get notified of discovered problems
102 protected boolean hasSyntaxErrors = false;
105 * The parser this requestor is using.
107 // protected Parser parser;
108 protected Parser parser;
111 * Empty collections used for efficient initialization
113 protected static String[] fgEmptyStringArray = new String[0];
114 protected static byte[] fgEmptyByte = new byte[] {
116 protected static char[][] fgEmptyCharChar = new char[][] {
118 protected static char[] fgEmptyChar = new char[] {
121 protected HashtableOfObject fieldRefCache;
122 protected HashtableOfObject messageRefCache;
123 protected HashtableOfObject typeRefCache;
124 protected HashtableOfObject unknownRefCache;
126 protected CompilationUnitStructureRequestor(ICompilationUnit unit, CompilationUnitElementInfo unitInfo, Map newElements)
127 throws JavaModelException {
129 this.fUnitInfo = unitInfo;
130 this.fNewElements = newElements;
131 this.fSourceFileName = unit.getElementName().toCharArray();
134 * @see ISourceElementRequestor
136 //public void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand) {
137 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
138 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
139 // if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
140 // Assert.isTrue(false); // Should not happen
143 // ICompilationUnit parentCU= (ICompilationUnit)parentHandle;
144 // //create the import container and its info
145 // IImportContainer importContainer= parentCU.getImportContainer();
146 // if (fImportContainerInfo == null) {
147 // fImportContainerInfo= new JavaElementInfo();
148 // fImportContainerInfo.setIsStructureKnown(true);
149 // parentInfo.addChild(importContainer);
150 // fNewElements.put(importContainer, fImportContainerInfo);
153 // // tack on the '.*' if it is onDemand
154 // String importName;
156 // importName= new String(name) + ".*"; //$NON-NLS-1$
158 // importName= new String(name);
161 // ImportDeclaration handle = new ImportDeclaration(importContainer, importName);
162 // resolveDuplicates(handle);
164 // SourceRefElementInfo info = new SourceRefElementInfo();
165 // info.setSourceRangeStart(declarationStart);
166 // info.setSourceRangeEnd(declarationEnd);
168 // fImportContainerInfo.addChild(handle);
169 // fNewElements.put(handle, info);
172 * Table of line separator position. This table is passed once at the end
173 * of the parse action, so as to allow computation of normalized ranges.
175 * A line separator might corresponds to several characters in the source,
178 public void acceptLineSeparatorPositions(int[] positions) {
181 * @see ISourceElementRequestor
183 //public void acceptPackage(int declarationStart, int declarationEnd, char[] name) {
185 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
186 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
187 // IPackageDeclaration handle = null;
188 // fPackageName= name;
190 // if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
191 // handle = new PackageDeclaration((ICompilationUnit) parentHandle, new String(name));
194 // Assert.isTrue(false); // Should not happen
196 // resolveDuplicates(handle);
198 // SourceRefElementInfo info = new SourceRefElementInfo();
199 // info.setSourceRangeStart(declarationStart);
200 // info.setSourceRangeEnd(declarationEnd);
202 // parentInfo.addChild(handle);
203 // fNewElements.put(handle, info);
206 public void acceptProblem(IProblem problem) {
207 if ((problem.getID() & IProblem.Syntax) != 0) {
208 this.hasSyntaxErrors = true;
212 * Convert these type names to signatures.
216 static String[] convertTypeNamesToSigs(char[][] typeNames) {
217 if (typeNames == null)
218 return fgEmptyStringArray;
219 int n = typeNames.length;
221 return fgEmptyStringArray;
222 String[] typeSigs = new String[n];
223 for (int i = 0; i < n; ++i) {
224 typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
229 * @see ISourceElementRequestor
231 public void enterClass(
232 int declarationStart,
238 char[][] superinterfaces) {
240 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, superclass, superinterfaces);
244 * @see ISourceElementRequestor
246 public void enterCompilationUnit() {
247 fInfoStack = new Stack();
248 fHandleStack = new Stack();
249 fInfoStack.push(fUnitInfo);
250 fHandleStack.push(fUnit);
253 * @see ISourceElementRequestor
255 public void enterConstructor(
256 int declarationStart,
261 char[][] parameterTypes,
262 char[][] parameterNames,
263 char[][] exceptionTypes) {
278 * @see ISourceElementRequestor
280 public void enterField(int declarationStart, int modifiers, char[] type, char[] name, int nameSourceStart, int nameSourceEnd) {
282 SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
283 JavaElement parentHandle = (JavaElement) fHandleStack.peek();
284 IField handle = null;
286 if (parentHandle.getElementType() == IJavaElement.TYPE) {
287 handle = new SourceField((IType) parentHandle, new String(name));
289 Assert.isTrue(false); // Should not happen
291 resolveDuplicates(handle);
293 SourceFieldElementInfo info = new SourceFieldElementInfo();
295 info.setNameSourceStart(nameSourceStart);
296 info.setNameSourceEnd(nameSourceEnd);
297 info.setSourceRangeStart(declarationStart);
298 info.setFlags(modifiers);
299 info.setTypeName(type);
301 parentInfo.addChild(handle);
302 fNewElements.put(handle, info);
304 fInfoStack.push(info);
305 fHandleStack.push(handle);
308 * @see ISourceElementRequestor
310 //public void enterInitializer(
311 // int declarationSourceStart,
313 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
314 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
315 // IInitializer handle = null;
317 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
318 // handle = ((IType) parentHandle).getInitializer(1);
321 // Assert.isTrue(false); // Should not happen
323 // resolveDuplicates(handle);
325 // InitializerElementInfo info = new InitializerElementInfo();
326 // info.setSourceRangeStart(declarationSourceStart);
327 // info.setFlags(modifiers);
329 // parentInfo.addChild(handle);
330 // fNewElements.put(handle, info);
332 // fInfoStack.push(info);
333 // fHandleStack.push(handle);
336 * @see ISourceElementRequestor
338 public void enterInterface(
339 int declarationStart,
344 char[][] superinterfaces) {
346 enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, null, superinterfaces);
350 * @see ISourceElementRequestor
352 public void enterMethod(
353 int declarationStart,
359 char[][] parameterTypes,
360 char[][] parameterNames,
361 char[][] exceptionTypes) {
376 * @see ISourceElementRequestor
378 protected void enterMethod(
379 int declarationStart,
385 char[][] parameterTypes,
386 char[][] parameterNames,
387 char[][] exceptionTypes,
388 boolean isConstructor) {
389 SourceTypeElementInfo parentInfo = null;
391 parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
392 } catch (ClassCastException e) {
393 // parentInfo = null;
395 JavaElement parentHandle = (JavaElement) fHandleStack.peek();
396 IMethod handle = null;
398 // translate nulls to empty arrays
399 if (parameterTypes == null) {
400 parameterTypes = fgEmptyCharChar;
402 if (parameterNames == null) {
403 parameterNames = fgEmptyCharChar;
405 if (exceptionTypes == null) {
406 exceptionTypes = fgEmptyCharChar;
409 String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
410 if (parentHandle.getElementType() == IJavaElement.TYPE) {
411 handle = new SourceMethod((IType) parentHandle, new String(name), parameterTypeSigs);
412 } else if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
413 handle = new SourceMethod((ICompilationUnit) parentHandle, name==null?"":new String(name), parameterTypeSigs);
415 Assert.isTrue(false); // Should not happen
417 resolveDuplicates(handle);
419 SourceMethodElementInfo info = new SourceMethodElementInfo();
420 info.setSourceRangeStart(declarationStart);
421 int flags = modifiers;
423 info.setNameSourceStart(nameSourceStart);
424 info.setNameSourceEnd(nameSourceEnd);
425 info.setConstructor(isConstructor);
426 info.setFlags(flags);
427 info.setArgumentNames(parameterNames);
428 info.setArgumentTypeNames(parameterTypes);
429 info.setReturnType(returnType == null ? new char[] { 'v', 'o', 'i', 'd' }
431 info.setExceptionTypeNames(exceptionTypes);
433 if (parentInfo == null) {
434 fUnitInfo.addChild(handle);
436 parentInfo.addChild(handle);
438 fNewElements.put(handle, info);
439 fInfoStack.push(info);
440 fHandleStack.push(handle);
443 * Common processing for classes and interfaces.
445 protected void enterType(
446 int declarationStart,
452 char[][] superinterfaces) {
454 char[] enclosingTypeName = null;
455 char[] qualifiedName = null;
457 JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
458 JavaElement parentHandle = (JavaElement) fHandleStack.peek();
460 String nameString = new String(name);
462 if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
463 handle = ((ICompilationUnit) parentHandle).getType(nameString);
464 if (fPackageName == null) {
465 qualifiedName = nameString.toCharArray();
467 qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
469 } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
470 handle = ((IType) parentHandle).getType(nameString);
471 enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
472 qualifiedName = (new String(((SourceTypeElementInfo) parentInfo).getQualifiedName()) + "." + nameString).toCharArray(); //$NON-NLS-1$
474 Assert.isTrue(false); // Should not happen
476 resolveDuplicates(handle);
478 SourceTypeElementInfo info = new SourceTypeElementInfo();
479 info.setHandle(handle);
480 info.setSourceRangeStart(declarationStart);
481 info.setFlags(modifiers);
483 info.setNameSourceStart(nameSourceStart);
484 info.setNameSourceEnd(nameSourceEnd);
485 info.setSuperclassName(superclass);
486 info.setSuperInterfaceNames(superinterfaces);
487 info.setEnclosingTypeName(enclosingTypeName);
488 info.setSourceFileName(fSourceFileName);
489 info.setPackageName(fPackageName);
490 info.setQualifiedName(qualifiedName);
491 // for (Iterator iter = fNewElements.keySet().iterator(); iter.hasNext();){
492 // Object object = iter.next();
493 // if (object instanceof IImportDeclaration)
494 // info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
497 parentInfo.addChild(handle);
498 fNewElements.put(handle, info);
500 fInfoStack.push(info);
501 fHandleStack.push(handle);
505 * @see ISourceElementRequestor
507 public void exitClass(int declarationEnd) {
509 exitMember(declarationEnd);
512 * @see ISourceElementRequestor
514 public void exitCompilationUnit(int declarationEnd) {
515 fUnitInfo.setSourceLength(declarationEnd + 1);
517 // determine if there were any parsing errors
518 fUnitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
521 * @see ISourceElementRequestor
523 public void exitConstructor(int declarationEnd) {
524 exitMember(declarationEnd);
527 // * @see ISourceElementRequestor
529 //public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
530 // SourceFieldElementInfo info = (SourceFieldElementInfo) fInfoStack.pop();
531 // info.setSourceRangeEnd(declarationSourceEnd);
533 // // remember initializer source if field is a constant
534 // if (initializationStart != -1) {
535 // int flags = info.flags;
537 // if (Flags.isStatic(flags) && Flags.isFinal(flags)
538 // || ((typeInfo = fInfoStack.peek()) instanceof SourceTypeElementInfo
539 // && (Flags.isInterface(((SourceTypeElementInfo)typeInfo).flags)))) {
540 // int length = declarationEnd - initializationStart;
542 // char[] initializer = new char[length];
543 // System.arraycopy(this.parser.scanner.source, initializationStart, initializer, 0, length);
544 // info.initializationSource = initializer;
548 // fHandleStack.pop();
551 * @see ISourceElementRequestor
553 public void exitInitializer(int declarationEnd) {
554 exitMember(declarationEnd);
557 * @see ISourceElementRequestor
559 public void exitInterface(int declarationEnd) {
560 exitMember(declarationEnd);
563 * common processing for classes and interfaces
565 protected void exitMember(int declarationEnd) {
566 SourceRefElementInfo info = (SourceRefElementInfo) fInfoStack.pop();
567 info.setSourceRangeEnd(declarationEnd);
571 * @see ISourceElementRequestor
573 public void exitMethod(int declarationEnd) {
574 exitMember(declarationEnd);
578 * Resolves duplicate handles by incrementing the occurrence count
579 * of the handle being created until there is no conflict.
581 protected void resolveDuplicates(IJavaElement handle) {
582 while (fNewElements.containsKey(handle)) {
583 JavaElement h = (JavaElement) handle;
584 h.setOccurrenceCount(h.getOccurrenceCount() + 1);