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;
30 //import net.sourceforge.phpdt.internal.corext.Assert;
31 import org.eclipse.core.runtime.Assert;
34 * A requestor for the fuzzy parser, used to compute the children of an
37 public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter
38 implements ISourceElementRequestor {
41 * The handle to the compilation unit being parsed
43 protected ICompilationUnit unit;
46 * The info object for the compilation unit being parsed
48 protected CompilationUnitElementInfo unitInfo;
51 * The import container info - null until created
53 protected JavaElementInfo importContainerInfo = null;
56 * Hashtable of children elements of the compilation unit. Children are
57 * added to the table as they are found by the parser. Keys are handles,
58 * values are corresponding info objects.
60 protected Map newElements;
63 * Stack of parent scope info objects. The info on the top of the stack is
64 * the parent of the next element found. For example, when we locate a
65 * method, the parent info object will be the type the method is contained
68 protected Stack infoStack;
71 * Stack of parent handles, corresponding to the info stack. We keep both,
72 * since info objects do not have back pointers to handles.
74 protected Stack handleStack;
77 * The name of the source file being parsed.
79 protected char[] fSourceFileName = null;
82 * The dot-separated name of the package the compilation unit is contained
83 * in - based on the package statement in the compilation unit, and
84 * initialized by #acceptPackage. Initialized to <code>null</code> for the
87 protected char[] fPackageName = null;
90 * The number of references reported thus far. Used to expand the arrays of
91 * reference kinds and names.
93 protected int fRefCount = 0;
96 * The initial size of the reference kind and name arrays. If the arrays
97 * fill, they are doubled in size
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];
117 protected static byte[] fgEmptyByte = new byte[] {};
119 protected static char[][] fgEmptyCharChar = new char[][] {};
121 protected static char[] fgEmptyChar = new char[] {};
123 protected HashtableOfObject fieldRefCache;
125 protected HashtableOfObject messageRefCache;
127 protected HashtableOfObject typeRefCache;
129 protected HashtableOfObject unknownRefCache;
131 protected CompilationUnitStructureRequestor(ICompilationUnit unit,
132 CompilationUnitElementInfo unitInfo, Map newElements)
133 throws JavaModelException {
135 this.unitInfo = unitInfo;
136 this.newElements = newElements;
137 this.fSourceFileName = unit.getElementName().toCharArray();
141 * @see ISourceElementRequestor
143 public void acceptImport(int declarationStart, int declarationEnd,
144 char[] name, boolean onDemand) {
145 // , int modifiers) {
147 JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
148 JavaElement parentHandle = (JavaElement) this.handleStack.peek();
149 if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
150 Assert.isTrue(false); // Should not happen
153 ICompilationUnit parentCU = (ICompilationUnit) parentHandle;
154 // create the import container and its info
155 ImportContainer importContainer = (ImportContainer) parentCU
156 .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,
174 resolveDuplicates(handle);
176 ImportDeclarationElementInfo info = new ImportDeclarationElementInfo();
177 info.setSourceRangeStart(declarationStart);
178 info.setSourceRangeEnd(declarationEnd);
179 // info.setFlags(modifiers);
180 info.setName(name); // no trailing * if onDemand
181 info.setOnDemand(onDemand);
183 this.importContainerInfo.addChild(handle);
184 this.newElements.put(handle, info);
188 * @see ISourceElementRequestor
192 * Table of line separator position. This table is passed once at the end of
193 * the parse action, so as to allow computation of normalized ranges.
195 * A line separator might corresponds to several characters in the source,
198 public void acceptLineSeparatorPositions(int[] positions) {
202 * @see ISourceElementRequestor
204 // public void acceptPackage(int declarationStart, int declarationEnd,
207 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
208 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
209 // IPackageDeclaration handle = null;
210 // fPackageName= name;
212 // if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
213 // handle = new PackageDeclaration((ICompilationUnit) parentHandle, new
217 // Assert.isTrue(false); // Should not happen
219 // resolveDuplicates(handle);
221 // SourceRefElementInfo info = new SourceRefElementInfo();
222 // info.setSourceRangeStart(declarationStart);
223 // info.setSourceRangeEnd(declarationEnd);
225 // parentInfo.addChild(handle);
226 // fNewElements.put(handle, info);
229 public void acceptProblem(IProblem problem) {
230 if ((problem.getID() & IProblem.Syntax) != 0) {
231 this.hasSyntaxErrors = true;
236 * Convert these type names to signatures.
241 static String[] convertTypeNamesToSigs(char[][] typeNames) {
242 if (typeNames == null)
243 return fgEmptyStringArray;
244 int n = typeNames.length;
246 return fgEmptyStringArray;
247 String[] typeSigs = new String[n];
248 for (int i = 0; i < n; ++i) {
249 typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
255 * @see ISourceElementRequestor
257 public void enterClass(int declarationStart, int modifiers, char[] name,
258 int nameSourceStart, int nameSourceEnd, char[] superclass,
259 char[][] superinterfaces) {
261 enterType(declarationStart, modifiers, name, nameSourceStart,
262 nameSourceEnd, superclass, superinterfaces);
267 * @see ISourceElementRequestor
269 public void enterCompilationUnit() {
270 infoStack = new Stack();
271 handleStack = new Stack();
272 infoStack.push(unitInfo);
273 handleStack.push(unit);
277 * @see ISourceElementRequestor
279 public void enterConstructor(int declarationStart, int modifiers,
280 char[] name, int nameSourceStart, int nameSourceEnd,
281 char[][] parameterTypes, char[][] parameterNames,
282 char[][] exceptionTypes) {
284 enterMethod(declarationStart, modifiers, null, name, nameSourceStart,
285 nameSourceEnd, parameterTypes, parameterNames, exceptionTypes,
290 * @see ISourceElementRequestor
292 public void enterField(int declarationStart, int modifiers, char[] type,
293 char[] name, int nameSourceStart, int nameSourceEnd) {
295 SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) infoStack
297 JavaElement parentHandle = (JavaElement) handleStack.peek();
298 IField handle = null;
300 if (parentHandle.getElementType() == IJavaElement.TYPE) {
301 handle = new SourceField(parentHandle, new String(name));
303 Assert.isTrue(false); // Should not happen
305 resolveDuplicates(handle);
307 SourceFieldElementInfo info = new SourceFieldElementInfo();
309 info.setNameSourceStart(nameSourceStart);
310 info.setNameSourceEnd(nameSourceEnd);
311 info.setSourceRangeStart(declarationStart);
312 info.setFlags(modifiers);
313 info.setTypeName(type);
315 parentInfo.addChild(handle);
316 newElements.put(handle, info);
318 infoStack.push(info);
319 handleStack.push(handle);
323 * @see ISourceElementRequestor
325 // public void enterInitializer(
326 // int declarationSourceStart,
328 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
329 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
330 // IInitializer handle = null;
332 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
333 // handle = ((IType) parentHandle).getInitializer(1);
336 // Assert.isTrue(false); // Should not happen
338 // resolveDuplicates(handle);
340 // InitializerElementInfo info = new InitializerElementInfo();
341 // info.setSourceRangeStart(declarationSourceStart);
342 // info.setFlags(modifiers);
344 // parentInfo.addChild(handle);
345 // fNewElements.put(handle, info);
347 // fInfoStack.push(info);
348 // fHandleStack.push(handle);
351 * @see ISourceElementRequestor
353 public void enterInterface(int declarationStart, int modifiers,
354 char[] name, int nameSourceStart, int nameSourceEnd,
355 char[][] superinterfaces) {
357 enterType(declarationStart, modifiers, name, nameSourceStart,
358 nameSourceEnd, null, superinterfaces);
363 * @see ISourceElementRequestor
365 public void enterMethod(int declarationStart, int modifiers,
366 char[] returnType, char[] name, int nameSourceStart,
367 int nameSourceEnd, char[][] parameterTypes,
368 char[][] parameterNames, char[][] exceptionTypes) {
370 enterMethod(declarationStart, modifiers, returnType, name,
371 nameSourceStart, nameSourceEnd, parameterTypes, parameterNames,
372 exceptionTypes, false);
376 * @see ISourceElementRequestor
378 protected void enterMethod(int declarationStart, int modifiers,
379 char[] returnType, char[] name, int nameSourceStart,
380 int nameSourceEnd, char[][] parameterTypes,
381 char[][] parameterNames, char[][] exceptionTypes,
382 boolean isConstructor) {
383 SourceTypeElementInfo parentInfo = null;
385 parentInfo = (SourceTypeElementInfo) infoStack.peek();
386 } catch (ClassCastException e) {
387 // parentInfo = null;
389 JavaElement parentHandle = (JavaElement) handleStack.peek();
390 IMethod handle = null;
392 // translate nulls to empty arrays
393 if (parameterTypes == null) {
394 parameterTypes = fgEmptyCharChar;
396 if (parameterNames == null) {
397 parameterNames = fgEmptyCharChar;
399 if (exceptionTypes == null) {
400 exceptionTypes = fgEmptyCharChar;
403 String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
404 // TODO : jsurfer changed
405 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
406 handle = new SourceMethod(parentHandle, new String(name),
410 // Assert.isTrue(false); // Should not happen
412 resolveDuplicates(handle);
414 SourceMethodElementInfo info = new SourceMethodElementInfo();
415 info.setSourceRangeStart(declarationStart);
416 int flags = modifiers;
418 info.setNameSourceStart(nameSourceStart);
419 info.setNameSourceEnd(nameSourceEnd);
420 info.setConstructor(isConstructor);
421 info.setFlags(flags);
422 info.setArgumentNames(parameterNames);
423 info.setArgumentTypeNames(parameterTypes);
425 .setReturnType(returnType == null ? new char[] { 'v', 'o', 'i',
427 info.setExceptionTypeNames(exceptionTypes);
429 if (parentInfo == null) {
430 unitInfo.addChild(handle);
432 parentInfo.addChild(handle);
434 newElements.put(handle, info);
435 infoStack.push(info);
436 handleStack.push(handle);
440 * Common processing for classes and interfaces.
442 protected void enterType(int declarationStart, int modifiers, char[] name,
443 int nameSourceStart, int nameSourceEnd, char[] superclass,
444 char[][] superinterfaces) {
446 char[] enclosingTypeName = null;
447 char[] qualifiedName = null;
449 JavaElementInfo parentInfo = (JavaElementInfo) infoStack.peek();
450 JavaElement parentHandle = (JavaElement) handleStack.peek();
452 String nameString = new String(name);
454 if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
455 handle = ((ICompilationUnit) parentHandle).getType(nameString);
456 if (fPackageName == null) {
457 qualifiedName = nameString.toCharArray();
459 qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
461 } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
462 handle = ((IType) parentHandle).getType(nameString);
463 enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
464 qualifiedName = (new String(((SourceTypeElementInfo) parentInfo)
466 + "." + nameString).toCharArray(); //$NON-NLS-1$
468 Assert.isTrue(false); // Should not happen
470 resolveDuplicates(handle);
472 SourceTypeElementInfo info = new SourceTypeElementInfo();
473 info.setHandle(handle);
474 info.setSourceRangeStart(declarationStart);
475 info.setFlags(modifiers);
477 info.setNameSourceStart(nameSourceStart);
478 info.setNameSourceEnd(nameSourceEnd);
479 info.setSuperclassName(superclass);
480 info.setSuperInterfaceNames(superinterfaces);
481 info.setEnclosingTypeName(enclosingTypeName);
482 info.setSourceFileName(fSourceFileName);
483 info.setPackageName(fPackageName);
484 info.setQualifiedName(qualifiedName);
485 // for (Iterator iter = fNewElements.keySet().iterator();
487 // Object object = iter.next();
488 // if (object instanceof IImportDeclaration)
489 // info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
492 parentInfo.addChild(handle);
493 newElements.put(handle, info);
495 infoStack.push(info);
496 handleStack.push(handle);
501 * @see ISourceElementRequestor
503 public void exitClass(int declarationEnd) {
505 exitMember(declarationEnd);
509 * @see ISourceElementRequestor
511 public void exitCompilationUnit(int declarationEnd) {
512 unitInfo.setSourceLength(declarationEnd + 1);
514 // determine if there were any parsing errors
515 unitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
519 * @see ISourceElementRequestor
521 public void exitConstructor(int declarationEnd) {
522 exitMember(declarationEnd);
526 * @see ISourceElementRequestor
528 public void exitField(int initializationStart, int declarationEnd,
529 int declarationSourceEnd) {
530 SourceFieldElementInfo info = (SourceFieldElementInfo) infoStack.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)
538 && Flags.isFinal(flags)
539 || ((typeInfo = infoStack.peek()) instanceof SourceTypeElementInfo && (Flags
540 .isInterface(((SourceTypeElementInfo) typeInfo).flags)))) {
541 int length = declarationEnd - initializationStart;
543 char[] initializer = new char[length];
544 System.arraycopy(this.parser.scanner.source,
545 initializationStart, initializer, 0, length);
546 info.initializationSource = initializer;
554 * @see ISourceElementRequestor
556 public void exitInitializer(int declarationEnd) {
557 exitMember(declarationEnd);
561 * @see ISourceElementRequestor
563 public void exitInterface(int declarationEnd) {
564 exitMember(declarationEnd);
568 * common processing for classes and interfaces
570 protected void exitMember(int declarationEnd) {
571 SourceRefElementInfo info = (SourceRefElementInfo) infoStack.pop();
572 info.setSourceRangeEnd(declarationEnd);
577 * @see ISourceElementRequestor
579 public void exitMethod(int declarationEnd) {
580 exitMember(declarationEnd);
584 * Resolves duplicate handles by incrementing the occurrence count of the
585 * handle being created until there is no conflict.
587 protected void resolveDuplicates(IJavaElement handle) {
588 while (newElements.containsKey(handle)) {
589 JavaElement h = (JavaElement) handle;
590 h.setOccurrenceCount(h.getOccurrenceCount() + 1);