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
35 public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter
36 implements ISourceElementRequestor {
39 * The handle to the compilation unit being parsed
41 protected ICompilationUnit unit;
44 * The info object for the compilation unit being parsed
46 protected CompilationUnitElementInfo unitInfo;
49 * The import container info - null until created
51 protected JavaElementInfo importContainerInfo = null;
54 * Hashtable of children elements of the compilation unit. Children are
55 * added to the table as they are found by the parser. Keys are handles,
56 * values are corresponding info objects.
58 protected Map newElements;
61 * Stack of parent scope info objects. The info on the top of the stack is
62 * the parent of the next element found. For example, when we locate a
63 * method, the parent info object will be the type the method is contained
66 protected Stack infoStack;
69 * Stack of parent handles, corresponding to the info stack. We keep both,
70 * since info objects do not have back pointers to handles.
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 is contained
81 * in - based on the package statement in the compilation unit, and
82 * initialized by #acceptPackage. Initialized to <code>null</code> for the
85 protected char[] fPackageName = null;
88 * The number of references reported thus far. Used to expand the arrays of
89 * reference kinds and names.
91 protected int fRefCount = 0;
94 * The initial size of the reference kind and name arrays. If the arrays
95 * fill, they are doubled in size
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];
115 protected static byte[] fgEmptyByte = new byte[] {};
117 protected static char[][] fgEmptyCharChar = new char[][] {};
119 protected static char[] fgEmptyChar = new char[] {};
121 protected HashtableOfObject fieldRefCache;
123 protected HashtableOfObject messageRefCache;
125 protected HashtableOfObject typeRefCache;
127 protected HashtableOfObject unknownRefCache;
129 protected CompilationUnitStructureRequestor(ICompilationUnit unit,
130 CompilationUnitElementInfo unitInfo, Map newElements)
131 throws JavaModelException {
133 this.unitInfo = unitInfo;
134 this.newElements = newElements;
135 this.fSourceFileName = unit.getElementName().toCharArray();
139 * @see ISourceElementRequestor
141 public void acceptImport(int declarationStart, int declarationEnd,
142 char[] name, boolean onDemand) {
143 // , int modifiers) {
145 JavaElementInfo parentInfo = (JavaElementInfo) this.infoStack.peek();
146 JavaElement parentHandle = (JavaElement) this.handleStack.peek();
147 if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
148 Assert.isTrue(false); // Should not happen
151 ICompilationUnit parentCU = (ICompilationUnit) parentHandle;
152 // create the import container and its info
153 ImportContainer importContainer = (ImportContainer) parentCU
154 .getImportContainer();
155 if (this.importContainerInfo == null) {
156 this.importContainerInfo = new JavaElementInfo();
157 this.importContainerInfo.setIsStructureKnown(true);
158 parentInfo.addChild(importContainer);
159 this.newElements.put(importContainer, this.importContainerInfo);
162 // tack on the '.*' if it is onDemand
165 importName = new String(name) + ".*"; //$NON-NLS-1$
167 importName = new String(name);
170 ImportDeclaration handle = new ImportDeclaration(importContainer,
172 resolveDuplicates(handle);
174 ImportDeclarationElementInfo info = new ImportDeclarationElementInfo();
175 info.setSourceRangeStart(declarationStart);
176 info.setSourceRangeEnd(declarationEnd);
177 // info.setFlags(modifiers);
178 info.setName(name); // no trailing * if onDemand
179 info.setOnDemand(onDemand);
181 this.importContainerInfo.addChild(handle);
182 this.newElements.put(handle, info);
186 * @see ISourceElementRequestor
190 * Table of line separator position. This table is passed once at the end of
191 * 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) {
200 * @see ISourceElementRequestor
202 // public void acceptPackage(int declarationStart, int declarationEnd,
205 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
206 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
207 // IPackageDeclaration handle = null;
208 // fPackageName= name;
210 // if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
211 // handle = new PackageDeclaration((ICompilationUnit) parentHandle, new
215 // Assert.isTrue(false); // Should not happen
217 // resolveDuplicates(handle);
219 // SourceRefElementInfo info = new SourceRefElementInfo();
220 // info.setSourceRangeStart(declarationStart);
221 // info.setSourceRangeEnd(declarationEnd);
223 // parentInfo.addChild(handle);
224 // fNewElements.put(handle, info);
227 public void acceptProblem(IProblem problem) {
228 if ((problem.getID() & IProblem.Syntax) != 0) {
229 this.hasSyntaxErrors = true;
234 * Convert these type names to signatures.
239 static String[] convertTypeNamesToSigs(char[][] typeNames) {
240 if (typeNames == null)
241 return fgEmptyStringArray;
242 int n = typeNames.length;
244 return fgEmptyStringArray;
245 String[] typeSigs = new String[n];
246 for (int i = 0; i < n; ++i) {
247 typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
253 * @see ISourceElementRequestor
255 public void enterClass(int declarationStart, int modifiers, char[] name,
256 int nameSourceStart, int nameSourceEnd, char[] superclass,
257 char[][] superinterfaces) {
259 enterType(declarationStart, modifiers, name, nameSourceStart,
260 nameSourceEnd, superclass, superinterfaces);
265 * @see ISourceElementRequestor
267 public void enterCompilationUnit() {
268 infoStack = new Stack();
269 handleStack = new Stack();
270 infoStack.push(unitInfo);
271 handleStack.push(unit);
275 * @see ISourceElementRequestor
277 public void enterConstructor(int declarationStart, int modifiers,
278 char[] name, int nameSourceStart, int nameSourceEnd,
279 char[][] parameterTypes, char[][] parameterNames,
280 char[][] exceptionTypes) {
282 enterMethod(declarationStart, modifiers, null, name, nameSourceStart,
283 nameSourceEnd, parameterTypes, parameterNames, exceptionTypes,
288 * @see ISourceElementRequestor
290 public void enterField(int declarationStart, int modifiers, char[] type,
291 char[] name, int nameSourceStart, int nameSourceEnd) {
293 SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) infoStack
295 JavaElement parentHandle = (JavaElement) handleStack.peek();
296 IField handle = null;
298 if (parentHandle.getElementType() == IJavaElement.TYPE) {
299 handle = new SourceField(parentHandle, new String(name));
301 Assert.isTrue(false); // Should not happen
303 resolveDuplicates(handle);
305 SourceFieldElementInfo info = new SourceFieldElementInfo();
307 info.setNameSourceStart(nameSourceStart);
308 info.setNameSourceEnd(nameSourceEnd);
309 info.setSourceRangeStart(declarationStart);
310 info.setFlags(modifiers);
311 info.setTypeName(type);
313 parentInfo.addChild(handle);
314 newElements.put(handle, info);
316 infoStack.push(info);
317 handleStack.push(handle);
321 * @see ISourceElementRequestor
323 // public void enterInitializer(
324 // int declarationSourceStart,
326 // JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
327 // JavaElement parentHandle= (JavaElement)fHandleStack.peek();
328 // IInitializer handle = null;
330 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
331 // handle = ((IType) parentHandle).getInitializer(1);
334 // Assert.isTrue(false); // Should not happen
336 // resolveDuplicates(handle);
338 // InitializerElementInfo info = new InitializerElementInfo();
339 // info.setSourceRangeStart(declarationSourceStart);
340 // info.setFlags(modifiers);
342 // parentInfo.addChild(handle);
343 // fNewElements.put(handle, info);
345 // fInfoStack.push(info);
346 // fHandleStack.push(handle);
349 * @see ISourceElementRequestor
351 public void enterInterface(int declarationStart, int modifiers,
352 char[] name, int nameSourceStart, int nameSourceEnd,
353 char[][] superinterfaces) {
355 enterType(declarationStart, modifiers, name, nameSourceStart,
356 nameSourceEnd, null, superinterfaces);
361 * @see ISourceElementRequestor
363 public void enterMethod(int declarationStart, int modifiers,
364 char[] returnType, char[] name, int nameSourceStart,
365 int nameSourceEnd, char[][] parameterTypes,
366 char[][] parameterNames, char[][] exceptionTypes) {
368 enterMethod(declarationStart, modifiers, returnType, name,
369 nameSourceStart, nameSourceEnd, parameterTypes, parameterNames,
370 exceptionTypes, false);
374 * @see ISourceElementRequestor
376 protected void enterMethod(int declarationStart, int modifiers,
377 char[] returnType, char[] name, int nameSourceStart,
378 int nameSourceEnd, char[][] parameterTypes,
379 char[][] parameterNames, char[][] exceptionTypes,
380 boolean isConstructor) {
381 SourceTypeElementInfo parentInfo = null;
383 parentInfo = (SourceTypeElementInfo) infoStack.peek();
384 } catch (ClassCastException e) {
385 // parentInfo = null;
387 JavaElement parentHandle = (JavaElement) handleStack.peek();
388 IMethod handle = null;
390 // translate nulls to empty arrays
391 if (parameterTypes == null) {
392 parameterTypes = fgEmptyCharChar;
394 if (parameterNames == null) {
395 parameterNames = fgEmptyCharChar;
397 if (exceptionTypes == null) {
398 exceptionTypes = fgEmptyCharChar;
401 String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
402 // TODO : jsurfer changed
403 // if (parentHandle.getElementType() == IJavaElement.TYPE) {
404 handle = new SourceMethod(parentHandle, new String(name),
408 // Assert.isTrue(false); // Should not happen
410 resolveDuplicates(handle);
412 SourceMethodElementInfo info = new SourceMethodElementInfo();
413 info.setSourceRangeStart(declarationStart);
414 int flags = modifiers;
416 info.setNameSourceStart(nameSourceStart);
417 info.setNameSourceEnd(nameSourceEnd);
418 info.setConstructor(isConstructor);
419 info.setFlags(flags);
420 info.setArgumentNames(parameterNames);
421 info.setArgumentTypeNames(parameterTypes);
423 .setReturnType(returnType == null ? new char[] { 'v', 'o', 'i',
425 info.setExceptionTypeNames(exceptionTypes);
427 if (parentInfo == null) {
428 unitInfo.addChild(handle);
430 parentInfo.addChild(handle);
432 newElements.put(handle, info);
433 infoStack.push(info);
434 handleStack.push(handle);
438 * Common processing for classes and interfaces.
440 protected void enterType(int declarationStart, int modifiers, char[] name,
441 int nameSourceStart, int nameSourceEnd, char[] superclass,
442 char[][] superinterfaces) {
444 char[] enclosingTypeName = null;
445 char[] qualifiedName = null;
447 JavaElementInfo parentInfo = (JavaElementInfo) infoStack.peek();
448 JavaElement parentHandle = (JavaElement) handleStack.peek();
450 String nameString = new String(name);
452 if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
453 handle = ((ICompilationUnit) parentHandle).getType(nameString);
454 if (fPackageName == null) {
455 qualifiedName = nameString.toCharArray();
457 qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
459 } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
460 handle = ((IType) parentHandle).getType(nameString);
461 enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
462 qualifiedName = (new String(((SourceTypeElementInfo) parentInfo)
464 + "." + nameString).toCharArray(); //$NON-NLS-1$
466 Assert.isTrue(false); // Should not happen
468 resolveDuplicates(handle);
470 SourceTypeElementInfo info = new SourceTypeElementInfo();
471 info.setHandle(handle);
472 info.setSourceRangeStart(declarationStart);
473 info.setFlags(modifiers);
475 info.setNameSourceStart(nameSourceStart);
476 info.setNameSourceEnd(nameSourceEnd);
477 info.setSuperclassName(superclass);
478 info.setSuperInterfaceNames(superinterfaces);
479 info.setEnclosingTypeName(enclosingTypeName);
480 info.setSourceFileName(fSourceFileName);
481 info.setPackageName(fPackageName);
482 info.setQualifiedName(qualifiedName);
483 // for (Iterator iter = fNewElements.keySet().iterator();
485 // Object object = iter.next();
486 // if (object instanceof IImportDeclaration)
487 // info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
490 parentInfo.addChild(handle);
491 newElements.put(handle, info);
493 infoStack.push(info);
494 handleStack.push(handle);
499 * @see ISourceElementRequestor
501 public void exitClass(int declarationEnd) {
503 exitMember(declarationEnd);
507 * @see ISourceElementRequestor
509 public void exitCompilationUnit(int declarationEnd) {
510 unitInfo.setSourceLength(declarationEnd + 1);
512 // determine if there were any parsing errors
513 unitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
517 * @see ISourceElementRequestor
519 public void exitConstructor(int declarationEnd) {
520 exitMember(declarationEnd);
524 * @see ISourceElementRequestor
526 public void exitField(int initializationStart, int declarationEnd,
527 int declarationSourceEnd) {
528 SourceFieldElementInfo info = (SourceFieldElementInfo) infoStack.pop();
529 info.setSourceRangeEnd(declarationSourceEnd);
531 // remember initializer source if field is a constant
532 if (initializationStart != -1) {
533 int flags = info.flags;
535 if (Flags.isStatic(flags)
536 && Flags.isFinal(flags)
537 || ((typeInfo = infoStack.peek()) instanceof SourceTypeElementInfo && (Flags
538 .isInterface(((SourceTypeElementInfo) typeInfo).flags)))) {
539 int length = declarationEnd - initializationStart;
541 char[] initializer = new char[length];
542 System.arraycopy(this.parser.scanner.source,
543 initializationStart, initializer, 0, length);
544 info.initializationSource = initializer;
552 * @see ISourceElementRequestor
554 public void exitInitializer(int declarationEnd) {
555 exitMember(declarationEnd);
559 * @see ISourceElementRequestor
561 public void exitInterface(int declarationEnd) {
562 exitMember(declarationEnd);
566 * common processing for classes and interfaces
568 protected void exitMember(int declarationEnd) {
569 SourceRefElementInfo info = (SourceRefElementInfo) infoStack.pop();
570 info.setSourceRangeEnd(declarationEnd);
575 * @see ISourceElementRequestor
577 public void exitMethod(int declarationEnd) {
578 exitMember(declarationEnd);
582 * Resolves duplicate handles by incrementing the occurrence count of the
583 * handle being created until there is no conflict.
585 protected void resolveDuplicates(IJavaElement handle) {
586 while (newElements.containsKey(handle)) {
587 JavaElement h = (JavaElement) handle;
588 h.setOccurrenceCount(h.getOccurrenceCount() + 1);