new version with WorkingCopy Management
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / core / CompilationUnitStructureRequestor.java
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/CompilationUnitStructureRequestor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/CompilationUnitStructureRequestor.java
new file mode 100644 (file)
index 0000000..ce3680d
--- /dev/null
@@ -0,0 +1,587 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import java.util.Map;
+import java.util.Stack;
+
+import net.sourceforge.phpdt.core.ICompilationUnit;
+import net.sourceforge.phpdt.core.IField;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IMethod;
+import net.sourceforge.phpdt.core.IType;
+import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.core.Signature;
+import net.sourceforge.phpdt.core.compiler.IProblem;
+import net.sourceforge.phpdt.internal.compiler.ISourceElementRequestor;
+import net.sourceforge.phpdt.internal.compiler.parser.Parser;
+import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject;
+import net.sourceforge.phpdt.internal.core.util.ReferenceInfoAdapter;
+import net.sourceforge.phpdt.internal.corext.Assert;
+
+/**
+ * A requestor for the fuzzy parser, used to compute the children of an ICompilationUnit.
+ */
+public class CompilationUnitStructureRequestor extends ReferenceInfoAdapter implements ISourceElementRequestor {
+
+  /**
+   * The handle to the compilation unit being parsed
+   */
+  protected ICompilationUnit fUnit;
+
+  /**
+   * The info object for the compilation unit being parsed
+   */
+  protected CompilationUnitElementInfo fUnitInfo;
+
+  /**
+   * The import container info - null until created
+   */
+  protected JavaElementInfo fImportContainerInfo = null;
+
+  /**
+   * Hashtable of children elements of the compilation unit.
+   * Children are added to the table as they are found by
+   * the parser. Keys are handles, values are corresponding
+   * info objects.
+   */
+  protected Map fNewElements;
+
+  /**
+   * Stack of parent scope info objects. The info on the
+   * top of the stack is the parent of the next element found.
+   * For example, when we locate a method, the parent info object
+   * will be the type the method is contained in.
+   */
+  protected Stack fInfoStack;
+
+  /**
+   * Stack of parent handles, corresponding to the info stack. We
+   * keep both, since info objects do not have back pointers to
+   * handles.
+   */
+  protected Stack fHandleStack;
+
+  /**
+   * The name of the source file being parsed.
+   */
+  protected char[] fSourceFileName = null;
+
+  /**
+   * The dot-separated name of the package the compilation unit
+   * is contained in - based on the package statement in the
+   * compilation unit, and initialized by #acceptPackage.
+   * Initialized to <code>null</code> for the default package.
+   */
+  protected char[] fPackageName = null;
+
+  /**
+   * The number of references reported thus far. Used to
+   * expand the arrays of reference kinds and names.
+   */
+  protected int fRefCount = 0;
+
+  /**
+   * The initial size of the reference kind and name
+   * arrays. If the arrays fill, they are doubled in
+   * size
+   */
+  protected static int fgReferenceAllocation = 50;
+
+  /**
+   * Problem requestor which will get notified of discovered problems
+   */
+  protected boolean hasSyntaxErrors = false;
+
+  /*
+   * The parser this requestor is using.
+   */
+  //   protected Parser parser;
+  protected Parser parser;
+
+  /**
+   * Empty collections used for efficient initialization
+   */
+  protected static String[] fgEmptyStringArray = new String[0];
+  protected static byte[] fgEmptyByte = new byte[] {
+  };
+  protected static char[][] fgEmptyCharChar = new char[][] {
+  };
+  protected static char[] fgEmptyChar = new char[] {
+  };
+
+  protected HashtableOfObject fieldRefCache;
+  protected HashtableOfObject messageRefCache;
+  protected HashtableOfObject typeRefCache;
+  protected HashtableOfObject unknownRefCache;
+
+  protected CompilationUnitStructureRequestor(ICompilationUnit unit, CompilationUnitElementInfo unitInfo, Map newElements)
+    throws JavaModelException {
+    this.fUnit = unit;
+    this.fUnitInfo = unitInfo;
+    this.fNewElements = newElements;
+    this.fSourceFileName = unit.getElementName().toCharArray();
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  //public void acceptImport(int declarationStart, int declarationEnd, char[] name, boolean onDemand) {
+  //   JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
+  //   JavaElement parentHandle= (JavaElement)fHandleStack.peek();
+  //   if (!(parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT)) {
+  //           Assert.isTrue(false); // Should not happen
+  //   }
+  //
+  //   ICompilationUnit parentCU= (ICompilationUnit)parentHandle;
+  //   //create the import container and its info
+  //   IImportContainer importContainer= parentCU.getImportContainer();
+  //   if (fImportContainerInfo == null) {
+  //           fImportContainerInfo= new JavaElementInfo();
+  //           fImportContainerInfo.setIsStructureKnown(true);
+  //           parentInfo.addChild(importContainer);
+  //           fNewElements.put(importContainer, fImportContainerInfo);
+  //   }
+  //   
+  //   // tack on the '.*' if it is onDemand
+  //   String importName;
+  //   if (onDemand) {
+  //           importName= new String(name) + ".*"; //$NON-NLS-1$
+  //   } else {
+  //           importName= new String(name);
+  //   }
+  //   
+  //   ImportDeclaration handle = new ImportDeclaration(importContainer, importName);
+  //   resolveDuplicates(handle);
+  //   
+  //   SourceRefElementInfo info = new SourceRefElementInfo();
+  //   info.setSourceRangeStart(declarationStart);
+  //   info.setSourceRangeEnd(declarationEnd);
+  //
+  //   fImportContainerInfo.addChild(handle);
+  //   fNewElements.put(handle, info);
+  //}
+  /*
+   * Table of line separator position. This table is passed once at the end
+   * of the parse action, so as to allow computation of normalized ranges.
+   *
+   * A line separator might corresponds to several characters in the source,
+   * 
+   */
+  public void acceptLineSeparatorPositions(int[] positions) {
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  //public void acceptPackage(int declarationStart, int declarationEnd, char[] name) {
+  //
+  //           JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
+  //           JavaElement parentHandle= (JavaElement)fHandleStack.peek();
+  //           IPackageDeclaration handle = null;
+  //           fPackageName= name;
+  //           
+  //           if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
+  //                   handle = new PackageDeclaration((ICompilationUnit) parentHandle, new String(name));
+  //           }
+  //           else {
+  //                   Assert.isTrue(false); // Should not happen
+  //           }
+  //           resolveDuplicates(handle);
+  //           
+  //           SourceRefElementInfo info = new SourceRefElementInfo();
+  //           info.setSourceRangeStart(declarationStart);
+  //           info.setSourceRangeEnd(declarationEnd);
+  //
+  //           parentInfo.addChild(handle);
+  //           fNewElements.put(handle, info);
+  //
+  //}
+  public void acceptProblem(IProblem problem) {
+    if ((problem.getID() & IProblem.Syntax) != 0) {
+      this.hasSyntaxErrors = true;
+    }
+  }
+  /**
+   * Convert these type names to signatures.
+   * @see Signature.
+   */
+  /* default */
+  static String[] convertTypeNamesToSigs(char[][] typeNames) {
+    if (typeNames == null)
+      return fgEmptyStringArray;
+    int n = typeNames.length;
+    if (n == 0)
+      return fgEmptyStringArray;
+    String[] typeSigs = new String[n];
+    for (int i = 0; i < n; ++i) {
+      typeSigs[i] = Signature.createTypeSignature(typeNames[i], false);
+    }
+    return typeSigs;
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void enterClass(
+    int declarationStart,
+    int modifiers,
+    char[] name,
+    int nameSourceStart,
+    int nameSourceEnd,
+    char[] superclass,
+    char[][] superinterfaces) {
+
+    enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, superclass, superinterfaces);
+
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void enterCompilationUnit() {
+    fInfoStack = new Stack();
+    fHandleStack = new Stack();
+    fInfoStack.push(fUnitInfo);
+    fHandleStack.push(fUnit);
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void enterConstructor(
+    int declarationStart,
+    int modifiers,
+    char[] name,
+    int nameSourceStart,
+    int nameSourceEnd,
+    char[][] parameterTypes,
+    char[][] parameterNames,
+    char[][] exceptionTypes) {
+
+    enterMethod(
+      declarationStart,
+      modifiers,
+      null,
+      name,
+      nameSourceStart,
+      nameSourceEnd,
+      parameterTypes,
+      parameterNames,
+      exceptionTypes,
+      true);
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void enterField(int declarationStart, int modifiers, char[] type, char[] name, int nameSourceStart, int nameSourceEnd) {
+
+    SourceTypeElementInfo parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
+    JavaElement parentHandle = (JavaElement) fHandleStack.peek();
+    IField handle = null;
+
+    if (parentHandle.getElementType() == IJavaElement.TYPE) {
+      handle = new SourceField((IType) parentHandle, new String(name));
+    } else {
+      Assert.isTrue(false); // Should not happen
+    }
+    resolveDuplicates(handle);
+
+    SourceFieldElementInfo info = new SourceFieldElementInfo();
+    info.setName(name);
+    info.setNameSourceStart(nameSourceStart);
+    info.setNameSourceEnd(nameSourceEnd);
+    info.setSourceRangeStart(declarationStart);
+    info.setFlags(modifiers);
+    info.setTypeName(type);
+
+    parentInfo.addChild(handle);
+    fNewElements.put(handle, info);
+
+    fInfoStack.push(info);
+    fHandleStack.push(handle);
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  //public void enterInitializer(
+  //   int declarationSourceStart,
+  //   int modifiers) {
+  //           JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
+  //           JavaElement parentHandle= (JavaElement)fHandleStack.peek();
+  //           IInitializer handle = null;
+  //           
+  //           if (parentHandle.getElementType() == IJavaElement.TYPE) {
+  //                   handle = ((IType) parentHandle).getInitializer(1);
+  //           }
+  //           else {
+  //                   Assert.isTrue(false); // Should not happen
+  //           }
+  //           resolveDuplicates(handle);
+  //           
+  //           InitializerElementInfo info = new InitializerElementInfo();
+  //           info.setSourceRangeStart(declarationSourceStart);
+  //           info.setFlags(modifiers);
+  //
+  //           parentInfo.addChild(handle);
+  //           fNewElements.put(handle, info);
+  //
+  //           fInfoStack.push(info);
+  //           fHandleStack.push(handle);
+  //}
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void enterInterface(
+    int declarationStart,
+    int modifiers,
+    char[] name,
+    int nameSourceStart,
+    int nameSourceEnd,
+    char[][] superinterfaces) {
+
+    enterType(declarationStart, modifiers, name, nameSourceStart, nameSourceEnd, null, superinterfaces);
+
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void enterMethod(
+    int declarationStart,
+    int modifiers,
+    char[] returnType,
+    char[] name,
+    int nameSourceStart,
+    int nameSourceEnd,
+    char[][] parameterTypes,
+    char[][] parameterNames,
+    char[][] exceptionTypes) {
+
+    enterMethod(
+      declarationStart,
+      modifiers,
+      returnType,
+      name,
+      nameSourceStart,
+      nameSourceEnd,
+      parameterTypes,
+      parameterNames,
+      exceptionTypes,
+      false);
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  protected void enterMethod(
+    int declarationStart,
+    int modifiers,
+    char[] returnType,
+    char[] name,
+    int nameSourceStart,
+    int nameSourceEnd,
+    char[][] parameterTypes,
+    char[][] parameterNames,
+    char[][] exceptionTypes,
+    boolean isConstructor) {
+    SourceTypeElementInfo parentInfo = null;
+    try {
+      parentInfo = (SourceTypeElementInfo) fInfoStack.peek();
+    } catch (ClassCastException e) {
+      //                       parentInfo = null;
+    }
+    JavaElement parentHandle = (JavaElement) fHandleStack.peek();
+    IMethod handle = null;
+
+    // translate nulls to empty arrays
+    if (parameterTypes == null) {
+      parameterTypes = fgEmptyCharChar;
+    }
+    if (parameterNames == null) {
+      parameterNames = fgEmptyCharChar;
+    }
+    if (exceptionTypes == null) {
+      exceptionTypes = fgEmptyCharChar;
+    }
+
+    String[] parameterTypeSigs = convertTypeNamesToSigs(parameterTypes);
+    if (parentHandle.getElementType() == IJavaElement.TYPE) {
+      handle = new SourceMethod((IType) parentHandle, new String(name), parameterTypeSigs);
+    } else if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
+      handle = new SourceMethod((ICompilationUnit) parentHandle, name==null?"":new String(name), parameterTypeSigs);
+    } else {
+      Assert.isTrue(false); // Should not happen
+    }
+    resolveDuplicates(handle);
+
+    SourceMethodElementInfo info = new SourceMethodElementInfo();
+    info.setSourceRangeStart(declarationStart);
+    int flags = modifiers;
+    info.setName(name);
+    info.setNameSourceStart(nameSourceStart);
+    info.setNameSourceEnd(nameSourceEnd);
+    info.setConstructor(isConstructor);
+    info.setFlags(flags);
+    info.setArgumentNames(parameterNames);
+    info.setArgumentTypeNames(parameterTypes);
+    info.setReturnType(returnType == null ? new char[] { 'v', 'o', 'i', 'd' }
+    : returnType);
+    info.setExceptionTypeNames(exceptionTypes);
+
+    if (parentInfo == null) {
+      fUnitInfo.addChild(handle);
+    } else {
+      parentInfo.addChild(handle);
+    }
+    fNewElements.put(handle, info);
+    fInfoStack.push(info);
+    fHandleStack.push(handle);
+  }
+  /**
+   * Common processing for classes and interfaces.
+   */
+  protected void enterType(
+    int declarationStart,
+    int modifiers,
+    char[] name,
+    int nameSourceStart,
+    int nameSourceEnd,
+    char[] superclass,
+    char[][] superinterfaces) {
+
+    char[] enclosingTypeName = null;
+    char[] qualifiedName = null;
+
+    JavaElementInfo parentInfo = (JavaElementInfo) fInfoStack.peek();
+    JavaElement parentHandle = (JavaElement) fHandleStack.peek();
+    IType handle = null;
+    String nameString = new String(name);
+
+    if (parentHandle.getElementType() == IJavaElement.COMPILATION_UNIT) {
+      handle = ((ICompilationUnit) parentHandle).getType(nameString);
+      if (fPackageName == null) {
+        qualifiedName = nameString.toCharArray();
+      } else {
+        qualifiedName = (new String(fPackageName) + "." + nameString).toCharArray(); //$NON-NLS-1$
+      }
+    } else if (parentHandle.getElementType() == IJavaElement.TYPE) {
+      handle = ((IType) parentHandle).getType(nameString);
+      enclosingTypeName = ((SourceTypeElementInfo) parentInfo).getName();
+      qualifiedName = (new String(((SourceTypeElementInfo) parentInfo).getQualifiedName()) + "." + nameString).toCharArray(); //$NON-NLS-1$
+    } else {
+      Assert.isTrue(false); // Should not happen
+    }
+    resolveDuplicates(handle);
+
+    SourceTypeElementInfo info = new SourceTypeElementInfo();
+    info.setHandle(handle);
+    info.setSourceRangeStart(declarationStart);
+    info.setFlags(modifiers);
+    info.setName(name);
+    info.setNameSourceStart(nameSourceStart);
+    info.setNameSourceEnd(nameSourceEnd);
+    info.setSuperclassName(superclass);
+    info.setSuperInterfaceNames(superinterfaces);
+    info.setEnclosingTypeName(enclosingTypeName);
+    info.setSourceFileName(fSourceFileName);
+    info.setPackageName(fPackageName);
+    info.setQualifiedName(qualifiedName);
+    // for (Iterator iter = fNewElements.keySet().iterator(); iter.hasNext();){
+    //         Object object = iter.next();
+    //         if (object instanceof IImportDeclaration)
+    //                 info.addImport(((IImportDeclaration)object).getElementName().toCharArray());
+    // }
+
+    parentInfo.addChild(handle);
+    fNewElements.put(handle, info);
+
+    fInfoStack.push(info);
+    fHandleStack.push(handle);
+
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void exitClass(int declarationEnd) {
+
+    exitMember(declarationEnd);
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void exitCompilationUnit(int declarationEnd) {
+    fUnitInfo.setSourceLength(declarationEnd + 1);
+
+    // determine if there were any parsing errors
+    fUnitInfo.setIsStructureKnown(!this.hasSyntaxErrors);
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void exitConstructor(int declarationEnd) {
+    exitMember(declarationEnd);
+  }
+  ///**
+  // * @see ISourceElementRequestor
+  // */
+  //public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
+  //   SourceFieldElementInfo info = (SourceFieldElementInfo) fInfoStack.pop();
+  //   info.setSourceRangeEnd(declarationSourceEnd);
+  //   
+  //   // remember initializer source if field is a constant
+  //   if (initializationStart != -1) {
+  //           int flags = info.flags;
+  //           Object typeInfo;
+  //           if (Flags.isStatic(flags) && Flags.isFinal(flags)
+  //                           || ((typeInfo = fInfoStack.peek()) instanceof SourceTypeElementInfo
+  //                                    && (Flags.isInterface(((SourceTypeElementInfo)typeInfo).flags)))) {
+  //                   int length = declarationEnd - initializationStart;
+  //                   if (length > 0) {
+  //                           char[] initializer = new char[length];
+  //                           System.arraycopy(this.parser.scanner.source, initializationStart, initializer, 0, length);
+  //                           info.initializationSource = initializer;
+  //                   }
+  //           }
+  //   }
+  //   fHandleStack.pop();
+  //}
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void exitInitializer(int declarationEnd) {
+    exitMember(declarationEnd);
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void exitInterface(int declarationEnd) {
+    exitMember(declarationEnd);
+  }
+  /**
+   * common processing for classes and interfaces
+   */
+  protected void exitMember(int declarationEnd) {
+    SourceRefElementInfo info = (SourceRefElementInfo) fInfoStack.pop();
+    info.setSourceRangeEnd(declarationEnd);
+    fHandleStack.pop();
+  }
+  /**
+   * @see ISourceElementRequestor
+   */
+  public void exitMethod(int declarationEnd) {
+    exitMember(declarationEnd);
+  }
+
+  /**
+   * Resolves duplicate handles by incrementing the occurrence count
+   * of the handle being created until there is no conflict.
+   */
+  protected void resolveDuplicates(IJavaElement handle) {
+    while (fNewElements.containsKey(handle)) {
+      JavaElement h = (JavaElement) handle;
+      h.setOccurrenceCount(h.getOccurrenceCount() + 1);
+    }
+  }
+}