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 fUnit;
 
  42    * The info object for the compilation unit being parsed
 
  44   protected CompilationUnitElementInfo fUnitInfo;
 
  47    * The import container info - null until created
 
  49   protected JavaElementInfo fImportContainerInfo = 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 fNewElements;
 
  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 fInfoStack;
 
  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 fHandleStack;
 
  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.fUnitInfo = unitInfo;
 
 131     this.fNewElements = newElements;
 
 132     this.fSourceFileName = unit.getElementName().toCharArray();
 
 135    * @see ISourceElementRequestor
 
 137   public void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand) {
 
 138         JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
 
 139         JavaElement parentHandle= (JavaElement)fHandleStack.peek();
 
 140         if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
 
 141                 Assert.isTrue(false); // Should not happen
 
 144         ICompilationUnit parentCU= (ICompilationUnit)parentHandle;
 
 145         //create the import container and its info
 
 146         ImportContainer importContainer= parentCU.getImportContainer();
 
 147         if (fImportContainerInfo == null) {
 
 148                 fImportContainerInfo= new JavaElementInfo();
 
 149                 fImportContainerInfo.setIsStructureKnown(true);
 
 150                 parentInfo.addChild(importContainer);
 
 151                 fNewElements.put(importContainer, fImportContainerInfo);
 
 154         // tack on the '.*' if it is onDemand
 
 157                 importName= new String(name) + ".*"; //$NON-NLS-1$
 
 159                 importName= new String(name);
 
 162         ImportDeclaration handle = new ImportDeclaration(importContainer, importName);
 
 163 //      ImportDeclaration handle = new ImportDeclaration(null, importName);
 
 164 //      resolveDuplicates(handle);
 
 166         SourceRefElementInfo info = new SourceRefElementInfo();
 
 167         info.setSourceRangeStart(declarationStart);
 
 168         info.setSourceRangeEnd(declarationEnd);
 
 170         fImportContainerInfo.addChild(handle);
 
 171         fNewElements.put(handle, info);
 
 174    * Table of line separator position. This table is passed once at the end
 
 175    * of the parse action, so as to allow computation of normalized ranges.
 
 177    * A line separator might corresponds to several characters in the source,
 
 180   public void acceptLineSeparatorPositions(int[] positions) {
 
 183    * @see ISourceElementRequestor
 
 185   //public void acceptPackage(int declarationStart, int declarationEnd, char[] name) {
 
 187   //            JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
 
 188   //            JavaElement parentHandle= (JavaElement)fHandleStack.peek();
 
 189   //            IPackageDeclaration handle = null;
 
 190   //            fPackageName= name;
 
 192   //            if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
 
 193   //                    handle = new PackageDeclaration((ICompilationUnit) parentHandle, new String(name));
 
 196   //                    Assert.isTrue(false); // Should not happen
 
 198   //            resolveDuplicates(handle);
 
 200   //            SourceRefElementInfo info = new SourceRefElementInfo();
 
 201   //            info.setSourceRangeStart(declarationStart);
 
 202   //            info.setSourceRangeEnd(declarationEnd);
 
 204   //            parentInfo.addChild(handle);
 
 205   //            fNewElements.put(handle, info);
 
 208   public void acceptProblem(IProblem problem) {
 
 209     if ((problem.getID() & IProblem.Syntax) != 0) {
 
 210       this.hasSyntaxErrors = true;
 
 214    * Convert these type names to signatures.
 
 218   static String[] convertTypeNamesToSigs(char[][] typeNames) {
 
 219     if (typeNames == null)
 
 220       return fgEmptyStringArray;
 
 221     int n = typeNames.length;
 
 223       return fgEmptyStringArray;
 
 224     String[] typeSigs = new String[n];
 
 225     for (int i = 0; i < n; ++i) {
 
 226       typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
 
 231    * @see ISourceElementRequestor
 
 233   public void enterClass(
 
 234     int declarationStart,
 
 240     char[][] superinterfaces) {
 
 242     enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, superclass, superinterfaces);
 
 246    * @see ISourceElementRequestor
 
 248   public void enterCompilationUnit() {
 
 249     fInfoStack = new Stack();
 
 250     fHandleStack = new Stack();
 
 251     fInfoStack.push(fUnitInfo);
 
 252     fHandleStack.push(fUnit);
 
 255    * @see ISourceElementRequestor
 
 257   public void enterConstructor(
 
 258     int declarationStart,
 
 263     char[][] parameterTypes,
 
 264     char[][] parameterNames,
 
 265     char[][] exceptionTypes) {
 
 281    * @see ISourceElementRequestor
 
 283   public void enterField(int declarationStart, int modifiers, char[] type, char[] name, int nameSourceStart, int nameSourceEnd) {
 
 285     SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
 
 286     JavaElement parentHandle = (JavaElement) fHandleStack.peek();
 
 287     IField handle = null;
 
 289     if (parentHandle.getElementType() == IJavaElement.TYPE) {
 
 290       handle = new SourceField(parentHandle, new String(name));
 
 292       Assert.isTrue(false); // Should not happen
 
 294     resolveDuplicates(handle);
 
 296     SourceFieldElementInfo info = new SourceFieldElementInfo();
 
 298     info.setNameSourceStart(nameSourceStart);
 
 299     info.setNameSourceEnd(nameSourceEnd);
 
 300     info.setSourceRangeStart(declarationStart);
 
 301     info.setFlags(modifiers);
 
 302     info.setTypeName(type);
 
 304     parentInfo.addChild(handle);
 
 305     fNewElements.put(handle, info);
 
 307     fInfoStack.push(info);
 
 308     fHandleStack.push(handle);
 
 311    * @see ISourceElementRequestor
 
 313   //public void enterInitializer(
 
 314   //    int declarationSourceStart,
 
 316   //            JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
 
 317   //            JavaElement parentHandle= (JavaElement)fHandleStack.peek();
 
 318   //            IInitializer handle = null;
 
 320   //            if (parentHandle.getElementType() == IJavaElement.TYPE) {
 
 321   //                    handle = ((IType) parentHandle).getInitializer(1);
 
 324   //                    Assert.isTrue(false); // Should not happen
 
 326   //            resolveDuplicates(handle);
 
 328   //            InitializerElementInfo info = new InitializerElementInfo();
 
 329   //            info.setSourceRangeStart(declarationSourceStart);
 
 330   //            info.setFlags(modifiers);
 
 332   //            parentInfo.addChild(handle);
 
 333   //            fNewElements.put(handle, info);
 
 335   //            fInfoStack.push(info);
 
 336   //            fHandleStack.push(handle);
 
 339    * @see ISourceElementRequestor
 
 341   public void enterInterface(
 
 342     int declarationStart,
 
 347     char[][] superinterfaces) {
 
 349     enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, null, superinterfaces);
 
 353    * @see ISourceElementRequestor
 
 355   public void enterMethod(
 
 356     int declarationStart,
 
 362     char[][] parameterTypes,
 
 363     char[][] parameterNames,
 
 364     char[][] exceptionTypes) {
 
 379    * @see ISourceElementRequestor
 
 381   protected void enterMethod(
 
 382     int declarationStart,
 
 388     char[][] parameterTypes,
 
 389     char[][] parameterNames,
 
 390     char[][] exceptionTypes,
 
 391     boolean isConstructor) {
 
 392     SourceTypeElementInfo parentInfo = null;
 
 394       parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
 
 395     } catch (ClassCastException e) {
 
 396       //                        parentInfo = null;
 
 398     JavaElement parentHandle = (JavaElement) fHandleStack.peek();
 
 399     IMethod handle = null;
 
 401     // translate nulls to empty arrays
 
 402     if (parameterTypes == null) {
 
 403       parameterTypes = fgEmptyCharChar;
 
 405     if (parameterNames == null) {
 
 406       parameterNames = fgEmptyCharChar;
 
 408     if (exceptionTypes == null) {
 
 409       exceptionTypes = fgEmptyCharChar;
 
 412     String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
 
 413     // TODO : jsurfer changed
 
 414 //      if (parentHandle.getElementType() == IJavaElement.TYPE) {
 
 415                 handle = new SourceMethod(parentHandle, new String(name), parameterTypeSigs);
 
 418 //              Assert.isTrue(false); // Should not happen
 
 420         resolveDuplicates(handle);
 
 422     SourceMethodElementInfo info = new SourceMethodElementInfo();
 
 423     info.setSourceRangeStart(declarationStart);
 
 424     int flags = modifiers;
 
 426     info.setNameSourceStart(nameSourceStart);
 
 427     info.setNameSourceEnd(nameSourceEnd);
 
 428     info.setConstructor(isConstructor);
 
 429     info.setFlags(flags);
 
 430     info.setArgumentNames(parameterNames);
 
 431     info.setArgumentTypeNames(parameterTypes);
 
 432     info.setReturnType(returnType == null ? new char[] { 'v', 'o', 'i', 'd' }
 
 434     info.setExceptionTypeNames(exceptionTypes);
 
 436     if (parentInfo == null) {
 
 437       fUnitInfo.addChild(handle);
 
 439       parentInfo.addChild(handle);
 
 441     fNewElements.put(handle, info);
 
 442     fInfoStack.push(info);
 
 443     fHandleStack.push(handle);
 
 446    * Common processing for classes and interfaces.
 
 448   protected void enterType(
 
 449     int declarationStart,
 
 455     char[][] superinterfaces) {
 
 457     char[] enclosingTypeName = null;
 
 458     char[] qualifiedName = null;
 
 460     JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
 
 461     JavaElement parentHandle = (JavaElement) fHandleStack.peek();
 
 463     String nameString = new String(name);
 
 465     if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
 
 466       handle = ((ICompilationUnit) parentHandle).getType(nameString);
 
 467       if (fPackageName == null) {
 
 468         qualifiedName = nameString.toCharArray();
 
 470         qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
 
 472     } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
 
 473       handle = ((IType) parentHandle).getType(nameString);
 
 474       enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
 
 475       qualifiedName = (new String(((SourceTypeElementInfo) parentInfo).getQualifiedName()) + "." + nameString).toCharArray(); //$NON-NLS-1$
 
 477       Assert.isTrue(false); // Should not happen
 
 479     resolveDuplicates(handle);
 
 481     SourceTypeElementInfo info = new SourceTypeElementInfo();
 
 482     info.setHandle(handle);
 
 483     info.setSourceRangeStart(declarationStart);
 
 484     info.setFlags(modifiers);
 
 486     info.setNameSourceStart(nameSourceStart);
 
 487     info.setNameSourceEnd(nameSourceEnd);
 
 488     info.setSuperclassName(superclass);
 
 489     info.setSuperInterfaceNames(superinterfaces);
 
 490     info.setEnclosingTypeName(enclosingTypeName);
 
 491     info.setSourceFileName(fSourceFileName);
 
 492     info.setPackageName(fPackageName);
 
 493     info.setQualifiedName(qualifiedName);
 
 494     //  for (Iterator iter = fNewElements.keySet().iterator(); iter.hasNext();){
 
 495     //          Object object = iter.next();
 
 496     //          if (object instanceof IImportDeclaration)
 
 497     //                  info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
 
 500     parentInfo.addChild(handle);
 
 501     fNewElements.put(handle, info);
 
 503     fInfoStack.push(info);
 
 504     fHandleStack.push(handle);
 
 508    * @see ISourceElementRequestor
 
 510   public void exitClass(int declarationEnd) {
 
 512     exitMember(declarationEnd);
 
 515    * @see ISourceElementRequestor
 
 517   public void exitCompilationUnit(int declarationEnd) {
 
 518     fUnitInfo.setSourceLength(declarationEnd + 1);
 
 520     // determine if there were any parsing errors
 
 521     fUnitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
 
 524    * @see ISourceElementRequestor
 
 526   public void exitConstructor(int declarationEnd) {
 
 527     exitMember(declarationEnd);
 
 530    * @see ISourceElementRequestor
 
 532   public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
 
 533         SourceFieldElementInfo info = (SourceFieldElementInfo) fInfoStack.pop();
 
 534         info.setSourceRangeEnd(declarationSourceEnd);
 
 536         // remember initializer source if field is a constant
 
 537         if (initializationStart != -1) {
 
 538                 int flags = info.flags;
 
 540                 if (Flags.isStatic(flags) && Flags.isFinal(flags)
 
 541                                 || ((typeInfo = fInfoStack.peek()) instanceof SourceTypeElementInfo
 
 542                                          && (Flags.isInterface(((SourceTypeElementInfo)typeInfo).flags)))) {
 
 543                         int length = declarationEnd - initializationStart;
 
 545                                 char[] initializer = new char[length];
 
 546                                 System.arraycopy(this.parser.scanner.source, initializationStart, initializer, 0, length);
 
 547                                 info.initializationSource = initializer;
 
 554    * @see ISourceElementRequestor
 
 556   public void exitInitializer(int declarationEnd) {
 
 557     exitMember(declarationEnd);
 
 560    * @see ISourceElementRequestor
 
 562   public void exitInterface(int declarationEnd) {
 
 563     exitMember(declarationEnd);
 
 566    * common processing for classes and interfaces
 
 568   protected void exitMember(int declarationEnd) {
 
 569     SourceRefElementInfo info = (SourceRefElementInfo) fInfoStack.pop();
 
 570     info.setSourceRangeEnd(declarationEnd);
 
 574    * @see ISourceElementRequestor
 
 576   public void exitMethod(int declarationEnd) {
 
 577     exitMember(declarationEnd);
 
 581    * Resolves duplicate handles by incrementing the occurrence count
 
 582    * of the handle being created until there is no conflict.
 
 584   protected void resolveDuplicates(IJavaElement handle) {
 
 585     while (fNewElements.containsKey(handle)) {
 
 586       JavaElement h = (JavaElement) handle;
 
 587       h.setOccurrenceCount(h.getOccurrenceCount() + 1);