Package org.eclipse.jdt.core.dom

Source Code of org.eclipse.jdt.core.dom.AST

/*******************************************************************************
* Copyright (c) 2000, 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/

package org.eclipse.jdt.core.dom;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.IProgressMonitor;

import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.parser.Scanner;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.TextEdit;

/**
* Umbrella owner and abstract syntax tree node factory.
* An <code>AST</code> instance serves as the common owner of any number of
* AST nodes, and as the factory for creating new AST nodes owned by that
* instance.
* <p>
* Abstract syntax trees may be hand constructed by clients, using the
* <code>new<i>TYPE</i></code> factory methods to create new nodes, and the
* various <code>set<i>CHILD</i></code> methods
* (see {@link org.eclipse.jdt.core.dom.ASTNode ASTNode} and its subclasses)
* to connect them together.
* </p>
* <p>
* Each AST node belongs to a unique AST instance, called the owning AST.
* The children of an AST node always have the same owner as their parent node.
* If a node from one AST is to be added to a different AST, the subtree must
* be cloned first to ensures that the added nodes have the correct owning AST.
* </p>
* <p>
* There can be any number of AST nodes owned by a single AST instance that are
* unparented. Each of these nodes is the root of a separate little tree of nodes.
* The method <code>ASTNode.getRoot()</code> navigates from any node to the root
* of the tree that it is contained in. Ordinarily, an AST instance has one main
* tree (rooted at a <code>CompilationUnit</code>), with newly-created nodes appearing
* as additional roots until they are parented somewhere under the main tree.
* One can navigate from any node to its AST instance, but not conversely.
* </p>
* <p>
* The class {@link ASTParser} parses a string
* containing a Java source code and returns an abstract syntax tree
* for it. The resulting nodes carry source ranges relating the node back to
* the original source characters.
* </p>
* <p>
* Compilation units created by <code>ASTParser</code> from a
* source document can be serialized after arbitrary modifications
* with minimal loss of original formatting. Here is an example:
* <pre>
* Document doc = new Document("import java.util.List;\nclass X {}\n");
* ASTParser parser = ASTParser.newParser(AST.JLS3);
* parser.setSource(doc.get().toCharArray());
* CompilationUnit cu = (CompilationUnit) parser.createAST(null);
* cu.recordModifications();
* AST ast = cu.getAST();
* ImportDeclaration id = ast.newImportDeclaration();
* id.setName(ast.newName(new String[] {"java", "util", "Set"});
* cu.imports().add(id); // add import declaration at end
* TextEdit edits = cu.rewrite(document, null);
* UndoEdit undo = edits.apply(document);
* </pre>
* See also {@link org.eclipse.jdt.core.dom.rewrite.ASTRewrite} for
* an alternative way to describe and serialize changes to a
* read-only AST.
* </p>
* <p>
* Clients may create instances of this class using {@link #newAST(int)},
* but this class is not intended to be subclassed.
* </p>
*
* @see ASTParser
* @see ASTNode
* @since 2.0
* @noinstantiate This class is not intended to be instantiated by clients.
*/
public final class AST {
  /**
   * new Class[] {AST.class}
   * @since 3.0
   */
  private static final Class[] AST_CLASS = new Class[] {AST.class};

  /**
   * Constant for indicating the AST API that handles JLS2.
   * <p>
   * This API is capable of handling all constructs
   * in the Java language as described in the Java Language
     * Specification, Second Edition (JLS2).
     * JLS2 is a superset of all earlier versions of the
     * Java language, and the JLS2 API can be used to manipulate
     * programs written in all versions of the Java language
     * up to and including J2SE 1.4.
     * </p>
     *
   * @since 3.0
   * @deprecated Clients should use the {@link #JLS4} AST API instead.
   */
  public static final int JLS2 = 2;

  /**
   * Internal synonym for {@link #JLS2}. Use to alleviate
   * deprecation warnings.
   * @since 3.1
   */
  /*package*/ static final int JLS2_INTERNAL = JLS2;
 
  /**
   * Constant for indicating the AST API that handles JLS3.
   * <p>
   * This API is capable of handling all constructs in the
   * Java language as described in the Java Language
   * Specification, Third Edition (JLS3).
     * JLS3 is a superset of all earlier versions of the
     * Java language, and the JLS3 API can be used to manipulate
     * programs written in all versions of the Java language
     * up to and including J2SE 5 (aka JDK 1.5).
     * </p>
     *
   * @since 3.1
   * @deprecated Clients should use the {@link #JLS4} AST API instead.
   */
  public static final int JLS3 = 3;
 
  /**
   * Internal synonym for {@link #JLS3}. Use to alleviate
   * deprecation warnings.
   * @since 3.8
   */
  /*package*/ static final int JLS3_INTERNAL = JLS3;

  /**
   * Constant for indicating the AST API that handles JLS4 (aka JLS7).
   * <p>
   * This API is capable of handling all constructs in the
   * Java language as described in the Java Language
   * Specification, Java SE 7 Edition (JLS7) as specified by JSR336.
   * JLS4 is a superset of all earlier versions of the
   * Java language, and the JLS4 API can be used to manipulate
   * programs written in all versions of the Java language
   * up to and including Java SE 7 (aka JDK 1.7).
   * </p>
   *
   * @since 3.7.1
   */
  public static final int JLS4 = 4;

  /*
   * Must not collide with a value for ICompilationUnit constants
   */
  static final int RESOLVED_BINDINGS = 0x80000000;

  /**
   * Internal method.
   * <p>
   * This method converts the given internal compiler AST for the given source string
   * into a compilation unit. This method is not intended to be called by clients.
   * </p>
   *
    * @param level the API level; one of the <code>JLS*</code> level constants
   * @param compilationUnitDeclaration an internal AST node for a compilation unit declaration
   * @param source the string of the Java compilation unit
   * @param options compiler options
   * @param workingCopy the working copy that the AST is created from
   * @param monitor the progress monitor used to report progress and request cancellation,
   *     or <code>null</code> if none
   * @param isResolved whether the given compilation unit declaration is resolved
   * @return the compilation unit node
   * @deprecated Use org.eclipse.jdt.core.dom.AST.convertCompilationUnit(int, CompilationUnitDeclaration, Map, boolean, CompilationUnit, int, IProgressMonitor) instead
   * @noreference This method is not intended to be referenced by clients.
   */
  public static CompilationUnit convertCompilationUnit(
      int level,
      org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration compilationUnitDeclaration,
      char[] source,
      Map options,
      boolean isResolved,
      org.eclipse.jdt.internal.core.CompilationUnit workingCopy,
      int reconcileFlags,
      IProgressMonitor monitor) {
    return null;
  }

  /**
   * Internal method.
   * <p>
   * This method converts the given internal compiler AST for the given source string
   * into a compilation unit. This method is not intended to be called by clients.
   * </p>
   *
    * @param level the API level; one of the <code>JLS*</code> level constants
   * @param compilationUnitDeclaration an internal AST node for a compilation unit declaration
   * @param options compiler options
   * @param workingCopy the working copy that the AST is created from
   * @param monitor the progress monitor used to report progress and request cancellation,
   *     or <code>null</code> if none
   * @param isResolved whether the given compilation unit declaration is resolved
   * @return the compilation unit node
   * @since 3.4
   * @noreference This method is not intended to be referenced by clients.
   */
  public static CompilationUnit convertCompilationUnit(
    int level,
    org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration compilationUnitDeclaration,
    Map options,
    boolean isResolved,
    org.eclipse.jdt.internal.core.CompilationUnit workingCopy,
    int reconcileFlags,
    IProgressMonitor monitor) {

    ASTConverter converter = new ASTConverter(options, isResolved, monitor);
    AST ast = AST.newAST(level);
    int savedDefaultNodeFlag = ast.getDefaultNodeFlag();
    ast.setDefaultNodeFlag(ASTNode.ORIGINAL);
    BindingResolver resolver = null;
    if (isResolved) {
      resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope, workingCopy.owner, new DefaultBindingResolver.BindingTables(), false, true);
      ((DefaultBindingResolver) resolver).isRecoveringBindings = (reconcileFlags & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0;
      ast.setFlag(AST.RESOLVED_BINDINGS);
    } else {
      resolver = new BindingResolver();
    }
    ast.setFlag(reconcileFlags);
    ast.setBindingResolver(resolver);
    converter.setAST(ast);

    CompilationUnit unit = converter.convert(compilationUnitDeclaration, workingCopy.getContents());
    unit.setLineEndTable(compilationUnitDeclaration.compilationResult.getLineSeparatorPositions());
    unit.setTypeRoot(workingCopy.originalFromClone());
    ast.setDefaultNodeFlag(savedDefaultNodeFlag);
    return unit;
  }

  /**
   * Creates a new Java abstract syntax tree
     * (AST) following the specified set of API rules.
     * <p>
     * Clients should use this method specifying {@link #JLS4} as the
     * AST level in all cases, even when dealing with source of earlier JDK versions like 1.3 or 1.4.
     * </p>
     *
    * @param level the API level; one of the <code>JLS*</code> level constants
   * @return new AST instance following the specified set of API rules.
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the API level is not one of the <code>JLS*</code> level constants</li>
   * </ul>
     * @since 3.0
   */
  public static AST newAST(int level) {
    return new AST(level);
  }

  /**
   * Parses the given string as a Java compilation unit and creates and
   * returns a corresponding abstract syntax tree.
   * <p>
   * The returned compilation unit node is the root node of a new AST.
   * Each node in the subtree carries source range(s) information relating back
   * to positions in the given source string (the given source string itself
   * is not remembered with the AST).
   * The source range usually begins at the first character of the first token
   * corresponding to the node; leading whitespace and comments are <b>not</b>
   * included. The source range usually extends through the last character of
   * the last token corresponding to the node; trailing whitespace and
   * comments are <b>not</b> included. There are a handful of exceptions
   * (including compilation units and the various body declarations); the
   * specification for these node type spells out the details.
   * Source ranges nest properly: the source range for a child is always
   * within the source range of its parent, and the source ranges of sibling
   * nodes never overlap.
   * If a syntax error is detected while parsing, the relevant node(s) of the
   * tree will be flagged as <code>MALFORMED</code>.
   * </p>
   * <p>
   * This method does not compute binding information; all <code>resolveBinding</code>
   * methods applied to nodes of the resulting AST return <code>null</code>.
   * </p>
   *
   * @param source the string to be parsed as a Java compilation unit
   * @return the compilation unit node
   * @see ASTNode#getFlags()
   * @see ASTNode#MALFORMED
   * @see ASTNode#getStartPosition()
   * @see ASTNode#getLength()
   * @since 2.0
   * @deprecated Use {@link ASTParser} instead.
   */
  public static CompilationUnit parseCompilationUnit(char[] source) {
    if (source == null) {
      throw new IllegalArgumentException();
    }
    ASTParser c = ASTParser.newParser(AST.JLS2);
    c.setSource(source);
    ASTNode result = c.createAST(null);
    return (CompilationUnit) result;
  }

  /**
   * Parses the given string as the hypothetical contents of the named
   * compilation unit and creates and returns a corresponding abstract syntax tree.
   * <p>
   * The returned compilation unit node is the root node of a new AST.
   * Each node in the subtree carries source range(s) information relating back
   * to positions in the given source string (the given source string itself
   * is not remembered with the AST).
   * The source range usually begins at the first character of the first token
   * corresponding to the node; leading whitespace and comments are <b>not</b>
   * included. The source range usually extends through the last character of
   * the last token corresponding to the node; trailing whitespace and
   * comments are <b>not</b> included. There are a handful of exceptions
   * (including compilation units and the various body declarations); the
   * specification for these node type spells out the details.
   * Source ranges nest properly: the source range for a child is always
   * within the source range of its parent, and the source ranges of sibling
   * nodes never overlap.
   * If a syntax error is detected while parsing, the relevant node(s) of the
   * tree will be flagged as <code>MALFORMED</code>.
   * </p>
   * <p>
   * If the given project is not <code>null</code>, the various names
   * and types appearing in the compilation unit can be resolved to "bindings"
   * by calling the <code>resolveBinding</code> methods. These bindings
   * draw connections between the different parts of a program, and
   * generally afford a more powerful vantage point for clients who wish to
   * analyze a program's structure more deeply. These bindings come at a
   * considerable cost in both time and space, however, and should not be
   * requested frivolously. The additional space is not reclaimed until the
   * AST, all its nodes, and all its bindings become garbage. So it is very
   * important to not retain any of these objects longer than absolutely
   * necessary. Bindings are resolved at the time the AST is created. Subsequent
   * modifications to the AST do not affect the bindings returned by
   * <code>resolveBinding</code> methods in any way; these methods return the
   * same binding as before the AST was modified (including modifications
   * that rearrange subtrees by reparenting nodes).
   * If the given project is <code>null</code>, the analysis
   * does not go beyond parsing and building the tree, and all
   * <code>resolveBinding</code> methods return <code>null</code> from the
   * outset.
   * </p>
   * <p>
   * The name of the compilation unit must be supplied for resolving bindings.
   * This name should be suffixed by a dot ('.') followed by one of the
   * {@link JavaCore#getJavaLikeExtensions() Java-like extensions}
   * and match the name of the main
   * (public) class or interface declared in the source. For example, if the source
   * declares a public class named "Foo", the name of the compilation can be
   * "Foo.java". For the purposes of resolving bindings, types declared in the
   * source string hide types by the same name available through the classpath
   * of the given project.
   * </p>
   *
   * @param source the string to be parsed as a Java compilation unit
   * @param unitName the name of the compilation unit that would contain the source
   *    string, or <code>null</code> if <code>javaProject</code> is also <code>null</code>
   * @param project the Java project used to resolve names, or
   *    <code>null</code> if bindings are not resolved
   * @return the compilation unit node
   * @see ASTNode#getFlags()
   * @see ASTNode#MALFORMED
   * @see ASTNode#getStartPosition()
   * @see ASTNode#getLength()
   * @since 2.0
   * @deprecated Use {@link ASTParser} instead.
   */
  public static CompilationUnit parseCompilationUnit(
    char[] source,
    String unitName,
    IJavaProject project) {

    if (source == null) {
      throw new IllegalArgumentException();
    }
    ASTParser astParser = ASTParser.newParser(AST.JLS2);
    astParser.setSource(source);
    astParser.setUnitName(unitName);
    astParser.setProject(project);
    astParser.setResolveBindings(project != null);
    ASTNode result = astParser.createAST(null);
    return (CompilationUnit) result;
  }

  /**
   * Parses the source string corresponding to the given Java class file
   * element and creates and returns a corresponding abstract syntax tree.
   * The source string is obtained from the Java model element using
   * <code>IClassFile.getSource()</code>, and is only available for a class
   * files with attached source.
   * <p>
   * The returned compilation unit node is the root node of a new AST.
   * Each node in the subtree carries source range(s) information relating back
   * to positions in the source string (the source string is not remembered
   * with the AST).
   * The source range usually begins at the first character of the first token
   * corresponding to the node; leading whitespace and comments are <b>not</b>
   * included. The source range usually extends through the last character of
   * the last token corresponding to the node; trailing whitespace and
   * comments are <b>not</b> included. There are a handful of exceptions
   * (including compilation units and the various body declarations); the
   * specification for these node type spells out the details.
   * Source ranges nest properly: the source range for a child is always
   * within the source range of its parent, and the source ranges of sibling
   * nodes never overlap.
   * If a syntax error is detected while parsing, the relevant node(s) of the
   * tree will be flagged as <code>MALFORMED</code>.
   * </p>
   * <p>
   * If <code>resolveBindings</code> is <code>true</code>, the various names
   * and types appearing in the compilation unit can be resolved to "bindings"
   * by calling the <code>resolveBinding</code> methods. These bindings
   * draw connections between the different parts of a program, and
   * generally afford a more powerful vantage point for clients who wish to
   * analyze a program's structure more deeply. These bindings come at a
   * considerable cost in both time and space, however, and should not be
   * requested frivolously. The additional space is not reclaimed until the
   * AST, all its nodes, and all its bindings become garbage. So it is very
   * important to not retain any of these objects longer than absolutely
   * necessary. Bindings are resolved at the time the AST is created. Subsequent
   * modifications to the AST do not affect the bindings returned by
   * <code>resolveBinding</code> methods in any way; these methods return the
   * same binding as before the AST was modified (including modifications
   * that rearrange subtrees by reparenting nodes).
   * If <code>resolveBindings</code> is <code>false</code>, the analysis
   * does not go beyond parsing and building the tree, and all
   * <code>resolveBinding</code> methods return <code>null</code> from the
   * outset.
   * </p>
   *
   * @param classFile the Java model class file whose corresponding source code is to be parsed
   * @param resolveBindings <code>true</code> if bindings are wanted,
   *   and <code>false</code> if bindings are not of interest
   * @return the compilation unit node
   * @exception IllegalArgumentException if the given Java element does not
   * exist or if its source string cannot be obtained
   * @see ASTNode#getFlags()
   * @see ASTNode#MALFORMED
   * @see ASTNode#getStartPosition()
   * @see ASTNode#getLength()
   * @since 2.1
   * @deprecated Use {@link ASTParser} instead.
   */
  public static CompilationUnit parseCompilationUnit(
    IClassFile classFile,
    boolean resolveBindings) {

    if (classFile == null) {
      throw new IllegalArgumentException();
    }
    try {
      ASTParser c = ASTParser.newParser(AST.JLS2);
      c.setSource(classFile);
      c.setResolveBindings(resolveBindings);
      ASTNode result = c.createAST(null);
      return (CompilationUnit) result;
    } catch (IllegalStateException e) {
      // convert ASTParser's complaints into old form
      throw new IllegalArgumentException();
    }
  }

  /**
   * Parses the source string of the given Java model compilation unit element
   * and creates and returns a corresponding abstract syntax tree. The source
   * string is obtained from the Java model element using
   * <code>ICompilationUnit.getSource()</code>.
   * <p>
   * The returned compilation unit node is the root node of a new AST.
   * Each node in the subtree carries source range(s) information relating back
   * to positions in the source string (the source string is not remembered
   * with the AST).
   * The source range usually begins at the first character of the first token
   * corresponding to the node; leading whitespace and comments are <b>not</b>
   * included. The source range usually extends through the last character of
   * the last token corresponding to the node; trailing whitespace and
   * comments are <b>not</b> included. There are a handful of exceptions
   * (including compilation units and the various body declarations); the
   * specification for these node type spells out the details.
   * Source ranges nest properly: the source range for a child is always
   * within the source range of its parent, and the source ranges of sibling
   * nodes never overlap.
   * If a syntax error is detected while parsing, the relevant node(s) of the
   * tree will be flagged as <code>MALFORMED</code>.
   * </p>
   * <p>
   * If <code>resolveBindings</code> is <code>true</code>, the various names
   * and types appearing in the compilation unit can be resolved to "bindings"
   * by calling the <code>resolveBinding</code> methods. These bindings
   * draw connections between the different parts of a program, and
   * generally afford a more powerful vantage point for clients who wish to
   * analyze a program's structure more deeply. These bindings come at a
   * considerable cost in both time and space, however, and should not be
   * requested frivolously. The additional space is not reclaimed until the
   * AST, all its nodes, and all its bindings become garbage. So it is very
   * important to not retain any of these objects longer than absolutely
   * necessary. Bindings are resolved at the time the AST is created. Subsequent
   * modifications to the AST do not affect the bindings returned by
   * <code>resolveBinding</code> methods in any way; these methods return the
   * same binding as before the AST was modified (including modifications
   * that rearrange subtrees by reparenting nodes).
   * If <code>resolveBindings</code> is <code>false</code>, the analysis
   * does not go beyond parsing and building the tree, and all
   * <code>resolveBinding</code> methods return <code>null</code> from the
   * outset.
   * </p>
   *
   * @param unit the Java model compilation unit whose source code is to be parsed
   * @param resolveBindings <code>true</code> if bindings are wanted,
   *   and <code>false</code> if bindings are not of interest
   * @return the compilation unit node
   * @exception IllegalArgumentException if the given Java element does not
   * exist or if its source string cannot be obtained
   * @see ASTNode#getFlags()
   * @see ASTNode#MALFORMED
   * @see ASTNode#getStartPosition()
   * @see ASTNode#getLength()
   * @since 2.0
   * @deprecated Use {@link ASTParser} instead.
   */
  public static CompilationUnit parseCompilationUnit(
    ICompilationUnit unit,
    boolean resolveBindings) {

    try {
      ASTParser c = ASTParser.newParser(AST.JLS2);
      c.setSource(unit);
      c.setResolveBindings(resolveBindings);
      ASTNode result = c.createAST(null);
      return (CompilationUnit) result;
    } catch (IllegalStateException e) {
      // convert ASTParser's complaints into old form
      throw new IllegalArgumentException();
    }
  }

  /**
   * Level of AST API supported by this AST.
   * @since 3.0
   */
  int apiLevel;

  /**
   * Tag bit value. This represents internal state of the tree.
   */
  private int bits;

  /**
   * Default value of <code>flag<code> when a new node is created.
   */
  private int defaultNodeFlag = 0;

  /**
   * When disableEvents > 0, events are not reported and
   * the modification count stays fixed.
   * <p>
   * This mechanism is used in lazy initialization of a node
   * to prevent events from being reported for the modification
   * of the node as well as for the creation of the missing child.
   * </p>
   * @since 3.0
   */
  private int disableEvents = 0;

  /**
   * The event handler for this AST.
   * Initially an event handler that does not nothing.
   * @since 3.0
   */
  private NodeEventHandler eventHandler = new NodeEventHandler();

  /**
   * Internal object unique to the AST instance. Readers must synchronize on
   * this object when the modifying instance fields.
   * @since 3.0
   */
  private final Object internalASTLock = new Object();

  /**
   * Internal modification count; initially 0; increases monotonically
   * <b>by one or more</b> as the AST is successively modified.
   */
  private long modificationCount = 0;

  /**
   * Internal original modification count; value is equals to <code>
   * modificationCount</code> at the end of the parse (<code>ASTParser
   * </code>). If this ast is not created with a parser then value is 0.
   * @since 3.0
   */
  private long originalModificationCount = 0;

  /**
   * The binding resolver for this AST. Initially a binding resolver that
   * does not resolve names at all.
   */
  private BindingResolver resolver = new BindingResolver();

  /**
   * Internal ast rewriter used to record ast modification when record mode is enabled.
   */
  InternalASTRewrite rewriter;

  /**
   * Java Scanner used to validate preconditions for the creation of specific nodes
   * like CharacterLiteral, NumberLiteral, StringLiteral or SimpleName.
   */
  Scanner scanner;

  /**
   * new Object[] {this}
   * @since 3.0
   */
  private final Object[] THIS_AST= new Object[] {this};

  /**
   * Creates a new, empty abstract syntax tree using default options.
   *
   * @see JavaCore#getDefaultOptions()
   * @deprecated Clients should port their code to use the new JLS4 AST API and call
   *    {@link #newAST(int) AST.newAST(AST.JLS4)} instead of using this constructor.
   */
  public AST() {
    this(JavaCore.getDefaultOptions());
  }

  /**
   * Creates a new Java abstract syntax tree
     * (AST) following the specified set of API rules.
     *
    * @param level the API level; one of the <code>JLS*</code> level constants
     * @since 3.0
   */
  private AST(int level) {
    switch(level) {
      case JLS2_INTERNAL :
      case JLS3_INTERNAL :
        this.apiLevel = level;
        // initialize a scanner
        this.scanner = new Scanner(
            true /*comment*/,
            true /*whitespace*/,
            false /*nls*/,
            ClassFileConstants.JDK1_3 /*sourceLevel*/,
            ClassFileConstants.JDK1_5 /*complianceLevel*/,
            null/*taskTag*/,
            null/*taskPriorities*/,
            true/*taskCaseSensitive*/);
        break;
      case JLS4 :
        this.apiLevel = level;
        // initialize a scanner
        this.scanner = new Scanner(
            true /*comment*/,
            true /*whitespace*/,
            false /*nls*/,
            ClassFileConstants.JDK1_7 /*sourceLevel*/,
            ClassFileConstants.JDK1_7 /*complianceLevel*/,
            null/*taskTag*/,
            null/*taskPriorities*/,
            true/*taskCaseSensitive*/);
        break;
      default:
        throw new IllegalArgumentException("Unsupported JLS level"); //$NON-NLS-1$
    }
  }

  /**
   * Creates a new, empty abstract syntax tree using the given options.
   * <p>
   * Following option keys are significant:
   * <ul>
   * <li><code>"org.eclipse.jdt.core.compiler.source"</code> -
   *    indicates source compatibility mode (as per <code>JavaCore</code>);
   *    <code>"1.3"</code> means the source code is as per JDK 1.3;
   *    <code>"1.4"</code> means the source code is as per JDK 1.4
   *    (<code>"assert"</code> is now a keyword);
   *    <code>"1.5"</code> means the source code is as per JDK 1.5
   *    (<code>"enum"</code> is now a keyword);
   *    <code>"1.7"</code> means the source code is as per JDK 1.7;
   *    additional legal values may be added later. </li>
   * </ul>
   * Options other than the above are ignored.
   * </p>
   *
   * @param options the table of options (key type: <code>String</code>;
   *    value type: <code>String</code>)
   * @see JavaCore#getDefaultOptions()
   * @deprecated Clients should port their code to use the new JLS4 AST API and call
   *    {@link #newAST(int) AST.newAST(AST.JLS4)} instead of using this constructor.
   */
  public AST(Map options) {
    this(JLS2);
    Object sourceLevelOption = options.get(JavaCore.COMPILER_SOURCE);
    long sourceLevel = ClassFileConstants.JDK1_3;
    if (JavaCore.VERSION_1_4.equals(sourceLevelOption)) {
      sourceLevel = ClassFileConstants.JDK1_4;
    } else if (JavaCore.VERSION_1_5.equals(sourceLevelOption)) {
      sourceLevel = ClassFileConstants.JDK1_5;
    } else if (JavaCore.VERSION_1_7.equals(sourceLevelOption)) {
      sourceLevel = ClassFileConstants.JDK1_7;
    }
    Object complianceLevelOption = options.get(JavaCore.COMPILER_COMPLIANCE);
    long complianceLevel = ClassFileConstants.JDK1_3;
    if (JavaCore.VERSION_1_4.equals(complianceLevelOption)) {
      complianceLevel = ClassFileConstants.JDK1_4;
    } else if (JavaCore.VERSION_1_5.equals(complianceLevelOption)) {
      complianceLevel = ClassFileConstants.JDK1_5;
    } else if (JavaCore.VERSION_1_7.equals(complianceLevelOption)) {
      complianceLevel = ClassFileConstants.JDK1_7;
    }
    // override scanner if 1.4 or 1.5 asked for
    this.scanner = new Scanner(
      true /*comment*/,
      true /*whitespace*/,
      false /*nls*/,
      sourceLevel /*sourceLevel*/,
      complianceLevel /*complianceLevel*/,
      null/*taskTag*/,
      null/*taskPriorities*/,
      true/*taskCaseSensitive*/);
  }

  /**
   * Return the API level supported by this AST.
   *
   * @return level the API level; one of the <code>JLS*</code> level constants
     * declared on <code>AST</code>; assume this set is open-ended
     * @since 3.0
   */
  public int apiLevel() {
    return this.apiLevel;
  }

  /**
   * Creates an unparented node of the given node class
   * (non-abstract subclass of {@link ASTNode}).
   *
   * @param nodeClass AST node class
   * @return a new unparented node owned by this AST
   * @exception IllegalArgumentException if <code>nodeClass</code> is
   * <code>null</code> or is not a concrete node type class
   * @since 3.0
   */
  public ASTNode createInstance(Class nodeClass) {
    if (nodeClass == null) {
      throw new IllegalArgumentException();
    }
    try {
      // invoke constructor with signature Foo(AST)
      Constructor c = nodeClass.getDeclaredConstructor(AST_CLASS);
      Object result = c.newInstance(this.THIS_AST);
      return (ASTNode) result;
    } catch (NoSuchMethodException e) {
      // all AST node classes have a Foo(AST) constructor
      // therefore nodeClass is not legit
      throw new IllegalArgumentException();
    } catch (InstantiationException e) {
      // all concrete AST node classes can be instantiated
      // therefore nodeClass is not legit
      throw new IllegalArgumentException();
    } catch (IllegalAccessException e) {
      // all AST node classes have an accessible Foo(AST) constructor
      // therefore nodeClass is not legit
      throw new IllegalArgumentException();
    } catch (InvocationTargetException e) {
      // concrete AST node classes do not die in the constructor
      // therefore nodeClass is not legit
      throw new IllegalArgumentException();
    }
  }

  /**
   * Creates an unparented node of the given node type.
   * This convenience method is equivalent to:
   * <pre>
   * createInstance(ASTNode.nodeClassForType(nodeType))
   * </pre>
   *
   * @param nodeType AST node type, one of the node type
   * constants declared on {@link ASTNode}
   * @return a new unparented node owned by this AST
   * @exception IllegalArgumentException if <code>nodeType</code> is
   * not a legal AST node type
   * @since 3.0
   */
  public ASTNode createInstance(int nodeType) {
    // nodeClassForType throws IllegalArgumentException if nodeType is bogus
    Class nodeClass = ASTNode.nodeClassForType(nodeType);
    return createInstance(nodeClass);
  }

  /**
     * Disable events.
   * This method is thread-safe for AST readers.
   *
   * @see #reenableEvents()
     * @since 3.0
     */
  final void disableEvents() {
    synchronized (this.internalASTLock) {
      // guard against concurrent access by another reader
      this.disableEvents++;
    }
    // while disableEvents > 0 no events will be reported, and mod count will stay fixed
  }

  /**
   * Returns the binding resolver for this AST.
   *
   * @return the binding resolver for this AST
   */
  BindingResolver getBindingResolver() {
    return this.resolver;
  }

  /**
   * Returns default node flags of new nodes of this AST.
   *
   * @return the default node flags of new nodes of this AST
   * @since 3.0
   */
  int getDefaultNodeFlag() {
    return this.defaultNodeFlag;
  }

  /**
   * Returns the event handler for this AST.
   *
   * @return the event handler for this AST
   * @since 3.0
   */
  NodeEventHandler getEventHandler() {
    return this.eventHandler;
  }

  /**
   * Returns true if the ast tree was created with bindings recovery, false otherwise
   *
   * @return true if the ast tree was created with bindings recovery, false otherwise
   * @since 3.3
   */
  public boolean hasBindingsRecovery() {
    return (this.bits & ICompilationUnit.ENABLE_BINDINGS_RECOVERY) != 0;
  }

  /**
   * Returns true if the ast tree was created with bindings, false otherwise
   *
   * @return true if the ast tree was created with bindings, false otherwise
   * @since 3.3
   */
  public boolean hasResolvedBindings() {
    return (this.bits & RESOLVED_BINDINGS) != 0;
  }

  /**
   * Returns true if the ast tree was created with statements recovery, false otherwise
   *
   * @return true if the ast tree was created with statements recovery, false otherwise
   * @since 3.3
   */
  public boolean hasStatementsRecovery() {
    return (this.bits & ICompilationUnit.ENABLE_STATEMENTS_RECOVERY) != 0;
  }

  /* (omit javadoc for this method)
   * This method is a copy of setName(String[]) that doesn't do any validation.
   */
  Name internalNewName(String[] identifiers) {
    int count = identifiers.length;
    if (count == 0) {
      throw new IllegalArgumentException();
    }
    final SimpleName simpleName = new SimpleName(this);
    simpleName.internalSetIdentifier(identifiers[0]);
    Name result = simpleName;
    for (int i = 1; i < count; i++) {
      SimpleName name = new SimpleName(this);
      name.internalSetIdentifier(identifiers[i]);
      result = newQualifiedName(result, name);
    }
    return result;
  }

  /**
   * Returns the modification count for this AST. The modification count
   * is a non-negative value that increases (by 1 or perhaps by more) as
   * this AST or its nodes are changed. The initial value is unspecified.
   * <p>
   * The following things count as modifying an AST:
   * <ul>
   * <li>creating a new node owned by this AST,</li>
   * <li>adding a child to a node owned by this AST,</li>
   * <li>removing a child from a node owned by this AST,</li>
   * <li>setting a non-node attribute of a node owned by this AST.</li>
   * </ul>
   * </p>
   * Operations which do not entail creating or modifying existing nodes
   * do not increase the modification count.
   * <p>
   * N.B. This method may be called several times in the course
   * of a single client operation. The only promise is that the modification
   * count increases monotonically as the AST or its nodes change; there is
   * no promise that a modifying operation increases the count by exactly 1.
   * </p>
   *
   * @return the current value (non-negative) of the modification counter of
   *    this AST
   */
  public long modificationCount() {
    return this.modificationCount;
  }

  /**
   * Indicates that this AST is about to be modified.
   * <p>
   * The following things count as modifying an AST:
   * <ul>
   * <li>creating a new node owned by this AST</li>
   * <li>adding a child to a node owned by this AST</li>
   * <li>removing a child from a node owned by this AST</li>
   * <li>setting a non-node attribute of a node owned by this AST</li>.
   * </ul>
   * </p>
   * <p>
   * N.B. This method may be called several times in the course
   * of a single client operation.
   * </p>
   */
  void modifying() {
    // when this method is called during lazy init, events are disabled
    // and the modification count will not be increased
    if (this.disableEvents > 0) {
      return;
    }
    // increase the modification count
    this.modificationCount++;
  }

  /**
   * Creates and returns a new unparented annotation type declaration
   * node for an unspecified, but legal, name; no modifiers; no javadoc;
   * and an empty list of member declarations.
   *
   * @return a new unparented annotation type declaration node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public AnnotationTypeDeclaration newAnnotationTypeDeclaration() {
    AnnotationTypeDeclaration result = new AnnotationTypeDeclaration(this);
    return result;
  }

  /**
   * Creates and returns a new unparented annotation type
   * member declaration node for an unspecified, but legal,
   * member name and type; no modifiers; no javadoc;
   * and no default value.
   *
   * @return a new unparented annotation type member declaration node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public AnnotationTypeMemberDeclaration newAnnotationTypeMemberDeclaration() {
    AnnotationTypeMemberDeclaration result = new AnnotationTypeMemberDeclaration(this);
    return result;
  }

  /**
   * Creates and returns a new unparented anonymous class declaration
   * node owned by this AST. By default, the body declaration list is empty.
   *
   * @return a new unparented anonymous class declaration node
   */
  public AnonymousClassDeclaration newAnonymousClassDeclaration() {
    AnonymousClassDeclaration result = new AnonymousClassDeclaration(this);
    return result;
  }

  /**
   * Creates and returns a new unparented array access expression node
   * owned by this AST. By default, the array and index expression are
   * both unspecified (but legal).
   *
   * @return a new unparented array access expression node
   */
  public ArrayAccess newArrayAccess() {
    ArrayAccess result = new ArrayAccess(this);
    return result;
  }

  /**
   * Creates and returns a new unparented array creation expression node
   * owned by this AST. By default, the array type is an unspecified
   * 1-dimensional array, the list of dimensions is empty, and there is no
   * array initializer.
   * <p>
   * Examples:
   * <code>
   * <pre>
   * // new String[len]
   * ArrayCreation ac1 = ast.newArrayCreation();
   * ac1.setType(
   *    ast.newArrayType(
   *       ast.newSimpleType(ast.newSimpleName("String"))));
   * ac1.dimensions().add(ast.newSimpleName("len"));
     *
   * // new double[7][24][]
   * ArrayCreation ac2 = ast.newArrayCreation();
   * ac2.setType(
   *    ast.newArrayType(
   *       ast.newPrimitiveType(PrimitiveType.DOUBLE), 3));
   * ac2.dimensions().add(ast.newNumberLiteral("7"));
   * ac2.dimensions().add(ast.newNumberLiteral("24"));
   *
   * // new int[] {1, 2}
   * ArrayCreation ac3 = ast.newArrayCreation();
   * ac3.setType(
   *    ast.newArrayType(
   *       ast.newPrimitiveType(PrimitiveType.INT)));
   * ArrayInitializer ai = ast.newArrayInitializer();
   * ac3.setInitializer(ai);
   * ai.expressions().add(ast.newNumberLiteral("1"));
   * ai.expressions().add(ast.newNumberLiteral("2"));
   * </pre>
   * </code>
   * </p>
   *
   * @return a new unparented array creation expression node
   */
  public ArrayCreation newArrayCreation() {
    ArrayCreation result = new ArrayCreation(this);
    return result;
  }

  /**
   * Creates and returns a new unparented array initializer node
   * owned by this AST. By default, the initializer has no expressions.
   *
   * @return a new unparented array initializer node
   */
  public ArrayInitializer newArrayInitializer() {
    ArrayInitializer result = new ArrayInitializer(this);
    return result;
  }

  /**
   * Creates and returns a new unparented array type node with the given
   * component type, which may be another array type.
   *
   * @param componentType the component type (possibly another array type)
   * @return a new unparented array type node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * </ul>
   */
  public ArrayType newArrayType(Type componentType) {
    ArrayType result = new ArrayType(this);
    result.setComponentType(componentType);
    return result;
  }

  /**
   * Creates and returns a new unparented array type node with the given
   * element type and number of (additional) dimensions.
   * <p>
   * Note that if the element type passed in is an array type, the
   * element type of the result will not be the same as what was passed in.
   * </p>
   *
   * @param elementType the element type (can be an array type)
   * @param dimensions the number of dimensions, a positive number
   * @return a new unparented array type node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * <li>the element type is null</li>
   * <li>the number of dimensions is lower than 1</li>
   * <li>the number of dimensions is greater than 1000</li>
   * </ul>
   */
  public ArrayType newArrayType(Type elementType, int dimensions) {
    if (elementType == null) {
      throw new IllegalArgumentException();
    }
    if (dimensions < 1 || dimensions > 1000) {
      // we would blow our stacks anyway with a 1000-D array
      throw new IllegalArgumentException();
    }
    ArrayType result = new ArrayType(this);
    result.setComponentType(elementType);
    for (int i = 2; i <= dimensions; i++) {
      result = newArrayType(result);
    }
    return result;

  }

  /**
   * Creates a new unparented assert statement node owned by this AST.
   * By default, the first expression is unspecified, but legal, and has no
   * message expression.
   *
   * @return a new unparented assert statement node
   */
  public AssertStatement newAssertStatement() {
    return new AssertStatement(this);
  }

  /**
   * Creates and returns a new unparented assignment expression node
   * owned by this AST. By default, the assignment operator is "=" and
   * the left and right hand side expressions are unspecified, but
   * legal, names.
   *
   * @return a new unparented assignment expression node
   */
  public Assignment newAssignment() {
    Assignment result = new Assignment(this);
    return result;
  }

  /**
   * Creates an unparented block node owned by this AST, for an empty list
   * of statements.
   *
   * @return a new unparented, empty block node
   */
  public Block newBlock() {
    return new Block(this);
  }

  /**
   * Creates and returns a new block comment placeholder node.
   * <p>
   * Note that this node type is used to recording the source
   * range where a comment was found in the source string.
   * These comment nodes are normally found (only) in
   * {@linkplain CompilationUnit#getCommentList()
   * the comment table} for parsed compilation units.
   * </p>
   *
   * @return a new unparented block comment node
   * @since 3.0
   */
  public BlockComment newBlockComment() {
    BlockComment result = new BlockComment(this);
    return result;
  }

  /**
   * Creates and returns a new unparented boolean literal node.
   * <p>
   * For example, the assignment expression <code>foo = true</code>
   * is generated by the following snippet:
   * <code>
   * <pre>
   * Assignment e= ast.newAssignment();
   * e.setLeftHandSide(ast.newSimpleName("foo"));
   * e.setRightHandSide(ast.newBooleanLiteral(true));
   * </pre>
   * </code>
   * </p>
   *
   * @param value the boolean value
   * @return a new unparented boolean literal node
   */
  public BooleanLiteral newBooleanLiteral(boolean value) {
    BooleanLiteral result = new BooleanLiteral(this);
    result.setBooleanValue(value);
    return result;
  }

  /**
   * Creates an unparented break statement node owned by this AST.
   * The break statement has no label.
   *
   * @return a new unparented break statement node
   */
  public BreakStatement newBreakStatement() {
    return new BreakStatement(this);
  }

  /**
   * Creates and returns a new unparented cast expression node
   * owned by this AST. By default, the type and expression are unspecified
   * (but legal).
   *
   * @return a new unparented cast expression node
   */
  public CastExpression newCastExpression() {
    CastExpression result = new CastExpression(this);
    return result;
  }

  /**
   * Creates a new unparented catch clause node owned by this AST.
   * By default, the catch clause declares an unspecified, but legal,
   * exception declaration and has an empty block.
   *
   * @return a new unparented catch clause node
   */
  public CatchClause newCatchClause() {
    return new CatchClause(this);
  }

  /**
   * Creates and returns a new unparented character literal node.
   * Initially the node has an unspecified character literal.
   *
   * @return a new unparented character literal node
   */
  public CharacterLiteral newCharacterLiteral() {
    return new CharacterLiteral(this);
  }

  /**
   * Creates and returns a new unparented class instance creation
   * ("new") expression node owned by this AST. By default,
   * there is no qualifying expression, no type parameters,
   * an unspecified (but legal) type name, an empty list of
   * arguments, and does not declare an anonymous class declaration.
   *
   * @return a new unparented class instance creation expression node
   */
  public ClassInstanceCreation newClassInstanceCreation() {
    ClassInstanceCreation result = new ClassInstanceCreation(this);
    return result;
  }

  //=============================== DECLARATIONS ===========================
  /**
   * Creates an unparented compilation unit node owned by this AST.
   * The compilation unit initially has no package declaration, no
   * import declarations, and no type declarations.
   *
   * @return the new unparented compilation unit node
   */
  public CompilationUnit newCompilationUnit() {
    return new CompilationUnit(this);
  }

  /**
   * Creates and returns a new unparented conditional expression node
   * owned by this AST. By default, the condition and both expressions
   * are unspecified (but legal).
   *
   * @return a new unparented array conditional expression node
   */
  public ConditionalExpression newConditionalExpression() {
    ConditionalExpression result = new ConditionalExpression(this);
    return result;
  }

  /**
   * Creates an unparented alternate constructor ("this(...);") invocation
   * statement node owned by this AST. By default, the lists of arguments
   * and type arguments are both empty.
   * <p>
   * Note that this type of node is a Statement, whereas a regular
   * method invocation is an Expression. The only valid use of these
   * statements are as the first statement of a constructor body.
   * </p>
   *
   * @return a new unparented alternate constructor invocation statement node
   */
  public ConstructorInvocation newConstructorInvocation() {
    ConstructorInvocation result = new ConstructorInvocation(this);
    return result;
  }

  /**
   * Creates an unparented continue statement node owned by this AST.
   * The continue statement has no label.
   *
   * @return a new unparented continue statement node
   */
  public ContinueStatement newContinueStatement() {
    return new ContinueStatement(this);
  }

  /**
   * Creates a new unparented union type node owned by this AST.
   * By default, the union type has no types.
   *
   * @return a new unparented do statement node
   * @since 3.7.1
   */
  public UnionType newUnionType() {
    return new UnionType(this);
  }

  /**
   * Creates a new unparented do statement node owned by this AST.
   * By default, the expression is unspecified (but legal), and
   * the body statement is an empty block.
   *
   * @return a new unparented do statement node
   */
  public DoStatement newDoStatement() {
    return new DoStatement(this);
  }

  /**
   * Creates a new unparented empty statement node owned by this AST.
   *
   * @return a new unparented empty statement node
   */
  public EmptyStatement newEmptyStatement() {
    return new EmptyStatement(this);
  }

  /**
   * Creates a new unparented enhanced for statement node owned by this AST.
   * By default, the paramter and expression are unspecified
   * but legal subtrees, and the body is an empty block.
   *
   * @return a new unparented throw statement node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public EnhancedForStatement newEnhancedForStatement() {
    return new EnhancedForStatement(this);
  }

  /**
   * Creates an unparented enum constant declaration node owned by this AST.
   * The name of the constant is an unspecified, but legal, name;
   * no doc comment; no modifiers or annotations; no arguments;
   * and does not declare an anonymous class.
   *
   * @return a new unparented enum constant declaration node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public EnumConstantDeclaration newEnumConstantDeclaration() {
    EnumConstantDeclaration result = new EnumConstantDeclaration(this);
    return result;
  }

  /**
   * Creates an unparented enum declaration node owned by this AST.
   * The name of the enum is an unspecified, but legal, name;
   * no doc comment; no modifiers or annotations;
   * no superinterfaces; and empty lists of enum constants
   * and body declarations.
   *
   * @return a new unparented enum declaration node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public EnumDeclaration newEnumDeclaration() {
    EnumDeclaration result = new EnumDeclaration(this);
    return result;
  }

  /**
   * Creates a new unparented expression statement node owned by this AST,
   * for the given expression.
   * <p>
   * This method can be used to convert an expression
   * (<code>Expression</code>) into a statement (<code>Type</code>)
   * by wrapping it. Note, however, that the result is only legal for
   * limited expression types, including method invocations, assignments,
   * and increment/decrement operations.
   * </p>
   *
   * @param expression the expression
   * @return a new unparented statement node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * </ul>
   */
  public ExpressionStatement newExpressionStatement(Expression expression) {
    ExpressionStatement result = new ExpressionStatement(this);
    result.setExpression(expression);
    return result;
  }

  /**
   * Creates and returns a new unparented field access expression node
   * owned by this AST. By default, the expression and field are both
   * unspecified, but legal, names.
   *
   * @return a new unparented field access expression node
   */
  public FieldAccess newFieldAccess() {
    FieldAccess result = new FieldAccess(this);
    return result;
  }

  /**
   * Creates a new unparented field declaration node owned by this AST,
   * for the given variable declaration fragment. By default, there are no
   * modifiers, no doc comment, and the base type is unspecified
   * (but legal).
   * <p>
   * This method can be used to wrap a variable declaration fragment
   * (<code>VariableDeclarationFragment</code>) into a field declaration
   * suitable for inclusion in the body of a type declaration
   * (<code>FieldDeclaration</code> implements <code>BodyDeclaration</code>).
   * Additional variable declaration fragments can be added afterwards.
   * </p>
   *
   * @param fragment the variable declaration fragment
   * @return a new unparented field declaration node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * <li>the given fragment is null</li>
   * </ul>
   */
  public FieldDeclaration newFieldDeclaration(VariableDeclarationFragment fragment) {
    if (fragment == null) {
      throw new IllegalArgumentException();
    }
    FieldDeclaration result = new FieldDeclaration(this);
    result.fragments().add(fragment);
    return result;
  }

  /**
   * Creates a new unparented for statement node owned by this AST.
   * By default, there are no initializers, no condition expression,
   * no updaters, and the body is an empty block.
   *
   * @return a new unparented for statement node
   */
  public ForStatement newForStatement() {
    return new ForStatement(this);
  }

  /**
   * Creates a new unparented if statement node owned by this AST.
   * By default, the expression is unspecified (but legal),
   * the then statement is an empty block, and there is no else statement.
   *
   * @return a new unparented if statement node
   */
  public IfStatement newIfStatement() {
    return new IfStatement(this);
  }

  /**
   * Creates an unparented import declaration node owned by this AST.
   * The import declaration initially contains a single-type import
   * of a type with an unspecified name.
   *
   * @return the new unparented import declaration node
   */
  public ImportDeclaration newImportDeclaration() {
    ImportDeclaration result = new ImportDeclaration(this);
    return result;
  }

  /**
   * Creates and returns a new unparented infix expression node
   * owned by this AST. By default, the operator and left and right
   * operand are unspecified (but legal), and there are no extended
   * operands.
   *
   * @return a new unparented infix expression node
   */
  public InfixExpression newInfixExpression() {
    InfixExpression result = new InfixExpression(this);
    return result;
  }

  /**
   * Creates an unparented initializer node owned by this AST, with an
   * empty block. By default, the initializer has no modifiers and
   * an empty block.
   *
   * @return a new unparented initializer node
   */
  public Initializer newInitializer() {
    Initializer result = new Initializer(this);
    return result;
  }

  /**
   * Creates and returns a new unparented instanceof expression node
   * owned by this AST. By default, the operator and left and right
   * operand are unspecified (but legal).
   *
   * @return a new unparented instanceof expression node
   */
  public InstanceofExpression newInstanceofExpression() {
    InstanceofExpression result = new InstanceofExpression(this);
    return result;
  }

  /**
   * Creates and returns a new doc comment node.
   * Initially the new node has an empty list of tag elements
   * (and, for backwards compatability, an unspecified, but legal,
   * doc comment string)
   *
   * @return a new unparented doc comment node
   */
  public Javadoc newJavadoc() {
    Javadoc result = new Javadoc(this);
    return result;
  }

  /**
   * Creates a new unparented labeled statement node owned by this AST.
   * By default, the label and statement are both unspecified, but legal.
   *
   * @return a new unparented labeled statement node
   */
  public LabeledStatement newLabeledStatement() {
    return new LabeledStatement(this);
  }

  /**
   * Creates and returns a new line comment placeholder node.
   * <p>
   * Note that this node type is used to recording the source
   * range where a comment was found in the source string.
   * These comment nodes are normally found (only) in
   * {@linkplain CompilationUnit#getCommentList()
   * the comment table} for parsed compilation units.
   * </p>
   *
   * @return a new unparented line comment node
   * @since 3.0
   */
  public LineComment newLineComment() {
    LineComment result = new LineComment(this);
    return result;
  }

  /**
   * Creates and returns a new unparented marker annotation node with
   * an unspecified type name.
   *
   * @return a new unparented marker annotation node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public MarkerAnnotation newMarkerAnnotation() {
    MarkerAnnotation result = new MarkerAnnotation(this);
    return result;
  }

  /**
   * Creates and returns a new member reference node.
   * Initially the new node has no qualifier name and
   * an unspecified, but legal, member name.
   * <p>
   * Note that this node type is used only inside doc comments
   * ({@link Javadoc}).
   * </p>
   *
   * @return a new unparented member reference node
   * @since 3.0
   */
  public MemberRef newMemberRef() {
    MemberRef result = new MemberRef(this);
    return result;
  }

  //=============================== COMMENTS ===========================

  /**
   * Creates and returns a new unparented member value pair node with
   * an unspecified member name and value.
   *
   * @return a new unparented member value pair node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public MemberValuePair newMemberValuePair() {
    MemberValuePair result = new MemberValuePair(this);
    return result;
  }

  /**
   * Creates an unparented method declaration node owned by this AST.
   * By default, the declaration is for a method of an unspecified, but
   * legal, name; no modifiers; no doc comment; no parameters; return
   * type void; no extra array dimensions; no thrown exceptions; and no
   * body (as opposed to an empty body).
   * <p>
   * To create a constructor, use this method and then call
   * <code>MethodDeclaration.setConstructor(true)</code> and
   * <code>MethodDeclaration.setName(className)</code>.
   * </p>
   *
   * @return a new unparented method declaration node
   */
  public MethodDeclaration newMethodDeclaration() {
    MethodDeclaration result = new MethodDeclaration(this);
    result.setConstructor(false);
    return result;
  }

  /**
   * Creates an unparented method invocation expression node owned by this
   * AST. By default, the name of the method is unspecified (but legal)
   * there is no receiver expression, no type arguments, and the list of
   * arguments is empty.
   *
   * @return a new unparented method invocation expression node
   */
  public MethodInvocation newMethodInvocation() {
    MethodInvocation result = new MethodInvocation(this);
    return result;
  }

  /**
   * Creates and returns a new method reference node.
   * Initially the new node has no qualifier name,
   * an unspecified, but legal, method name, and an
   * empty parameter list.
   * <p>
   * Note that this node type is used only inside doc comments
   * ({@link Javadoc Javadoc}).
   * </p>
   *
   * @return a new unparented method reference node
   * @since 3.0
   */
  public MethodRef newMethodRef() {
    MethodRef result = new MethodRef(this);
    return result;
  }

  /**
   * Creates and returns a new method reference node.
   * Initially the new node has an unspecified, but legal,
   * type, not variable arity, and no parameter name.
   * <p>
   * Note that this node type is used only inside doc comments
   * ({@link Javadoc}).
   * </p>
   *
   * @return a new unparented method reference parameter node
   * @since 3.0
   */
  public MethodRefParameter newMethodRefParameter() {
    MethodRefParameter result = new MethodRefParameter(this);
    return result;
  }

  /**
   * Creates and returns a new unparented modifier node for the given
   * modifier.
   *
   * @param keyword one of the modifier keyword constants
   * @return a new unparented modifier node
   * @exception IllegalArgumentException if the primitive type code is invalid
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public Modifier newModifier(Modifier.ModifierKeyword keyword) {
    Modifier result = new Modifier(this);
    result.setKeyword(keyword);
    return result;
  }

  /**
   * Creates and returns a list of new unparented modifier nodes
   * for the given modifier flags. When multiple modifiers are
   * requested the modifiers nodes will appear in the following order:
   * public, protected, private, abstract, static, final, synchronized,
   * native, strictfp, transient, volatile. This order is consistent
   * with the recommendations in JLS2 8.1.1, 8.3.1, and 8.4.3.
   *
   * @param flags bitwise or of modifier flags declared on {@link Modifier}
   * @return a possibly empty list of new unparented modifier nodes
   *   (element type <code>Modifier</code>)
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public List newModifiers(int flags) {
    if (this.apiLevel == AST.JLS2) {
      unsupportedIn2();
    }
    List result = new ArrayList(3); // 3 modifiers is more than average
    if (Modifier.isPublic(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
    }
    if (Modifier.isProtected(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.PROTECTED_KEYWORD));
    }
    if (Modifier.isPrivate(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD));
    }
    if (Modifier.isAbstract(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.ABSTRACT_KEYWORD));
    }
    if (Modifier.isStatic(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD));
    }
    if (Modifier.isFinal(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.FINAL_KEYWORD));
    }
    if (Modifier.isSynchronized(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.SYNCHRONIZED_KEYWORD));
    }
    if (Modifier.isNative(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.NATIVE_KEYWORD));
    }
    if (Modifier.isStrictfp(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.STRICTFP_KEYWORD));
    }
    if (Modifier.isTransient(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.TRANSIENT_KEYWORD));
    }
    if (Modifier.isVolatile(flags)) {
      result.add(newModifier(Modifier.ModifierKeyword.VOLATILE_KEYWORD));
    }
    return result;
  }

  /**
   * Creates and returns a new unparented name node for the given name.
   * The name string must consist of 1 or more name segments separated
   * by single dots '.'. Returns a {@link QualifiedName} if the name has
   * dots, and a {@link SimpleName} otherwise. Each of the name
   * segments should be legal Java identifiers (this constraint may or may
   * not be enforced), and there must be at least one name segment.
   * The string must not contains white space, '&lt;', '&gt;',
   * '[', ']', or other any other characters that are not
   * part of the Java identifiers or separating '.'s.
   *
   * @param qualifiedName string consisting of 1 or more name segments,
   * each of which is a legal Java identifier, separated  by single dots '.'
   * @return a new unparented name node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the string is empty</li>
   * <li>the string begins or ends in a '.'</li>
   * <li>the string has adjacent '.'s</li>
   * <li>the segments between the '.'s are not valid Java identifiers</li>
   * </ul>
   * @since 3.1
   */
  public Name newName(String qualifiedName) {
    StringTokenizer t = new StringTokenizer(qualifiedName, ".", true); //$NON-NLS-1$
    Name result = null;
    // balance is # of name tokens - # of period tokens seen so far
    // initially 0; finally 1; should never drop < 0 or > 1
    int balance = 0;
    while(t.hasMoreTokens()) {
      String s = t.nextToken();
      if (s.indexOf('.') >= 0) {
        // this is a delimiter
        if (s.length() > 1) {
          // too many dots in a row
          throw new IllegalArgumentException();
        }
        balance--;
        if (balance < 0) {
          throw new IllegalArgumentException();
        }
      } else {
        // this is an identifier segment
        balance++;
        SimpleName name = newSimpleName(s);
        if (result == null) {
          result = name;
        } else {
          result = newQualifiedName(result, name);
        }
      }
    }
    if (balance != 1) {
      throw new IllegalArgumentException();
    }
    return result;
  }

  /**
   * Creates and returns a new unparented name node for the given name
   * segments. Returns a simple name if there is only one name segment, and
   * a qualified name if there are multiple name segments. Each of the name
   * segments should be legal Java identifiers (this constraint may or may
   * not be enforced), and there must be at least one name segment.
   *
   * @param identifiers a list of 1 or more name segments, each of which
   *    is a legal Java identifier
   * @return a new unparented name node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the identifier is invalid</li>
   * <li>the list of identifiers is empty</li>
   * </ul>
   */
  public Name newName(String[] identifiers) {
    // update internalSetName(String[] if changed
    int count = identifiers.length;
    if (count == 0) {
      throw new IllegalArgumentException();
    }
    Name result = newSimpleName(identifiers[0]);
    for (int i = 1; i < count; i++) {
      SimpleName name = newSimpleName(identifiers[i]);
      result = newQualifiedName(result, name);
    }
    return result;
  }

  /**
   * Creates and returns a new unparented normal annotation node with
   * an unspecified type name and an empty list of member value
   * pairs.
   *
   * @return a new unparented normal annotation node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public NormalAnnotation newNormalAnnotation() {
    NormalAnnotation result = new NormalAnnotation(this);
    return result;
  }

  /**
   * Creates and returns a new unparented null literal node.
   *
   * @return a new unparented null literal node
   */
  public NullLiteral newNullLiteral() {
    return new NullLiteral(this);
  }

  /**
   * Creates and returns a new unparented number literal node.
   * Initially the number literal token is <code>"0"</code>.
   *
   * @return a new unparented number literal node
   */
  public NumberLiteral newNumberLiteral() {
    NumberLiteral result = new NumberLiteral(this);
    return result;
  }

  /**
   * Creates and returns a new unparented number literal node.
   *
   * @param literal the token for the numeric literal as it would
   *    appear in Java source code
   * @return a new unparented number literal node
   * @exception IllegalArgumentException if the literal is null
   */
  public NumberLiteral newNumberLiteral(String literal) {
    if (literal == null) {
      throw new IllegalArgumentException();
    }
    NumberLiteral result = new NumberLiteral(this);
    result.setToken(literal);
    return result;
  }

  /**
   * Creates an unparented package declaration node owned by this AST.
   * The package declaration initially declares a package with an
   * unspecified name.
   *
   * @return the new unparented package declaration node
   */
  public PackageDeclaration newPackageDeclaration() {
    PackageDeclaration result = new PackageDeclaration(this);
    return result;
  }

  /**
   * Creates and returns a new unparented parameterized type node with the
   * given type and an empty list of type arguments.
   *
   * @param type the type that is parameterized
   * @return a new unparented parameterized type node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * </ul>
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public ParameterizedType newParameterizedType(Type type) {
    ParameterizedType result = new ParameterizedType(this);
    result.setType(type);
    return result;
  }

  /**
   * Creates and returns a new unparented parenthesized expression node
   * owned by this AST. By default, the expression is unspecified (but legal).
   *
   * @return a new unparented parenthesized expression node
   */
  public ParenthesizedExpression newParenthesizedExpression() {
    ParenthesizedExpression result = new ParenthesizedExpression(this);
    return result;
  }

  /**
   * Creates and returns a new unparented postfix expression node
   * owned by this AST. By default, the operator and operand are
   * unspecified (but legal).
   *
   * @return a new unparented postfix expression node
   */
  public PostfixExpression newPostfixExpression() {
    PostfixExpression result = new PostfixExpression(this);
    return result;
  }

  /**
   * Creates and returns a new unparented prefix expression node
   * owned by this AST. By default, the operator and operand are
   * unspecified (but legal).
   *
   * @return a new unparented prefix expression node
   */
  public PrefixExpression newPrefixExpression() {
    PrefixExpression result = new PrefixExpression(this);
    return result;
  }

  /**
   * Creates and returns a new unparented primitive type node with the given
   * type code.
   *
   * @param typeCode one of the primitive type code constants declared in
   *    <code>PrimitiveType</code>
   * @return a new unparented primitive type node
   * @exception IllegalArgumentException if the primitive type code is invalid
   */
  public PrimitiveType newPrimitiveType(PrimitiveType.Code typeCode) {
    PrimitiveType result = new PrimitiveType(this);
    result.setPrimitiveTypeCode(typeCode);
    return result;
  }

  /**
   * Creates and returns a new unparented qualified name node for the given
   * qualifier and simple name child node.
   *
   * @param qualifier the qualifier name node
   * @param name the simple name being qualified
   * @return a new unparented qualified name node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * </ul>
   */
  public QualifiedName newQualifiedName(
    Name qualifier,
    SimpleName name) {
    QualifiedName result = new QualifiedName(this);
    result.setQualifier(qualifier);
    result.setName(name);
    return result;

  }

  /**
   * Creates and returns a new unparented qualified type node with
   * the given qualifier type and name.
   *
   * @param qualifier the qualifier type node
   * @param name the simple name being qualified
   * @return a new unparented qualified type node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * </ul>
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public QualifiedType newQualifiedType(Type qualifier, SimpleName name) {
    QualifiedType result = new QualifiedType(this);
    result.setQualifier(qualifier);
    result.setName(name);
    return result;
  }

  /**
   * Creates a new unparented return statement node owned by this AST.
   * By default, the return statement has no expression.
   *
   * @return a new unparented return statement node
   */
  public ReturnStatement newReturnStatement() {
    return new ReturnStatement(this);
  }

  //=============================== NAMES ===========================
  /**
   * Creates and returns a new unparented simple name node for the given
   * identifier. The identifier should be a legal Java identifier, but not
   * a keyword, boolean literal ("true", "false") or null literal ("null").
   *
   * @param identifier the identifier
   * @return a new unparented simple name node
   * @exception IllegalArgumentException if the identifier is invalid
   */
  public SimpleName newSimpleName(String identifier) {
    if (identifier == null) {
      throw new IllegalArgumentException();
    }
    SimpleName result = new SimpleName(this);
    result.setIdentifier(identifier);
    return result;
  }

  //=============================== TYPES ===========================
  /**
   * Creates and returns a new unparented simple type node with the given
   * type name.
   * <p>
   * This method can be used to convert a name (<code>Name</code>) into a
   * type (<code>Type</code>) by wrapping it.
   * </p>
   *
   * @param typeName the name of the class or interface
   * @return a new unparented simple type node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * </ul>
   */
  public SimpleType newSimpleType(Name typeName) {
    SimpleType result = new SimpleType(this);
    result.setName(typeName);
    return result;
  }

  /**
   * Creates and returns a new unparented single member annotation node with
   * an unspecified type name and value.
   *
   * @return a new unparented single member annotation node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public SingleMemberAnnotation newSingleMemberAnnotation() {
    SingleMemberAnnotation result = new SingleMemberAnnotation(this);
    return result;
  }

  /**
   * Creates an unparented single variable declaration node owned by this AST.
   * By default, the declaration is for a variable with an unspecified, but
   * legal, name and type; no modifiers; no array dimensions after the
   * variable; no initializer; not variable arity.
   *
   * @return a new unparented single variable declaration node
   */
  public SingleVariableDeclaration newSingleVariableDeclaration() {
    SingleVariableDeclaration result = new SingleVariableDeclaration(this);
    return result;
  }

  //=============================== EXPRESSIONS ===========================
  /**
   * Creates and returns a new unparented string literal node for
   * the empty string literal.
   *
   * @return a new unparented string literal node
   */
  public StringLiteral newStringLiteral() {
    return new StringLiteral(this);
  }

  /**
   * Creates an unparented alternate super constructor ("super(...);")
   * invocation statement node owned by this AST. By default, there is no
   * qualifier, no type arguments, and the list of arguments is empty.
   * <p>
   * Note that this type of node is a Statement, whereas a regular
   * super method invocation is an Expression. The only valid use of these
   * statements are as the first statement of a constructor body.
   * </p>
   *
   * @return a new unparented super constructor invocation statement node
   */
  public SuperConstructorInvocation newSuperConstructorInvocation() {
    SuperConstructorInvocation result =
      new SuperConstructorInvocation(this);
    return result;
  }

  /**
   * Creates and returns a new unparented super field access expression node
   * owned by this AST. By default, the expression and field are both
   * unspecified, but legal, names.
   *
   * @return a new unparented super field access expression node
   */
  public SuperFieldAccess newSuperFieldAccess() {
    SuperFieldAccess result = new SuperFieldAccess(this);
    return result;
  }

  /**
   * Creates an unparented "super" method invocation expression node owned by
   * this AST. By default, the name of the method is unspecified (but legal)
   * there is no qualifier, no type arguments, and the list of arguments is empty.
   *
   * @return a new unparented  "super" method invocation
   *    expression node
   */
  public SuperMethodInvocation newSuperMethodInvocation() {
    SuperMethodInvocation result = new SuperMethodInvocation(this);
    return result;
  }

  /**
   * Creates a new unparented switch case statement node owned by
   * this AST. By default, the expression is unspecified, but legal.
   *
   * @return a new unparented switch case node
   */
  public SwitchCase newSwitchCase() {
    return new SwitchCase(this);
  }


  /**
   * Creates a new unparented switch statement node owned by this AST.
   * By default, the expression is unspecified, but legal, and there are
   * no statements or switch cases.
   *
   * @return a new unparented labeled statement node
   */
  public SwitchStatement newSwitchStatement() {
    return new SwitchStatement(this);
  }

  /**
   * Creates a new unparented synchronized statement node owned by this AST.
   * By default, the expression is unspecified, but legal, and the body is
   * an empty block.
   *
   * @return a new unparented synchronized statement node
   */
  public SynchronizedStatement newSynchronizedStatement() {
    return new SynchronizedStatement(this);
  }

  /**
   * Creates and returns a new tag element node.
   * Initially the new node has no tag name and an empty list of fragments.
   * <p>
   * Note that this node type is used only inside doc comments
   * ({@link Javadoc}).
   * </p>
   *
   * @return a new unparented tag element node
   * @since 3.0
   */
  public TagElement newTagElement() {
    TagElement result = new TagElement(this);
    return result;
  }

  /**
   * Creates and returns a new text element node.
   * Initially the new node has an empty text string.
   * <p>
   * Note that this node type is used only inside doc comments
   * ({@link Javadoc Javadoc}).
   * </p>
   *
   * @return a new unparented text element node
   * @since 3.0
   */
  public TextElement newTextElement() {
    TextElement result = new TextElement(this);
    return result;
  }

  /**
   * Creates and returns a new unparented "this" expression node
   * owned by this AST. By default, there is no qualifier.
   *
   * @return a new unparented "this" expression node
   */
  public ThisExpression newThisExpression() {
    ThisExpression result = new ThisExpression(this);
    return result;
  }

  /**
   * Creates a new unparented throw statement node owned by this AST.
   * By default, the expression is unspecified, but legal.
   *
   * @return a new unparented throw statement node
   */
  public ThrowStatement newThrowStatement() {
    return new ThrowStatement(this);
  }

  /**
   * Creates a new unparented try statement node owned by this AST.
   * By default, the try statement has no resources, an empty block, no catch
   * clauses, and no finally block.
   *
   * @return a new unparented try statement node
   */
  public TryStatement newTryStatement() {
    return new TryStatement(this);
  }

  /**
   * Creates an unparented class declaration node owned by this AST.
   * The name of the class is an unspecified, but legal, name;
   * no modifiers; no doc comment; no superclass or superinterfaces;
   * and an empty class body.
   * <p>
   * To create an interface, use this method and then call
   * <code>TypeDeclaration.setInterface(true)</code>.
   * </p>
   *
   * @return a new unparented type declaration node
   */
  public TypeDeclaration newTypeDeclaration() {
    TypeDeclaration result = new TypeDeclaration(this);
    result.setInterface(false);
    return result;
  }

  /**
   * Creates a new unparented local type declaration statement node
   * owned by this AST, for the given type declaration.
   * <p>
   * This method can be used to convert any kind of type declaration
   * (<code>AbstractTypeDeclaration</code>) into a statement
   * (<code>Statement</code>) by wrapping it.
   * </p>
   *
   * @param decl the type declaration
   * @return a new unparented local type declaration statement node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * </ul>
   * @since 3.0
   */
  public TypeDeclarationStatement
      newTypeDeclarationStatement(AbstractTypeDeclaration decl) {
    TypeDeclarationStatement result = new TypeDeclarationStatement(this);
    if (this.apiLevel == AST.JLS2) {
      result.internalSetTypeDeclaration((TypeDeclaration) decl);
    }
    if (this.apiLevel >= AST.JLS3) {
      result.setDeclaration(decl);
    }
    return result;
  }

  /**
   * Creates a new unparented local type declaration statement node
   * owned by this AST, for the given type declaration.
   * <p>
   * This method can be used to convert a type declaration
   * (<code>TypeDeclaration</code>) into a statement
   * (<code>Statement</code>) by wrapping it.
   * </p>
   *
   * @param decl the type declaration
   * @return a new unparented local type declaration statement node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * </ul>
   */
  public TypeDeclarationStatement
      newTypeDeclarationStatement(TypeDeclaration decl) {
    TypeDeclarationStatement result = new TypeDeclarationStatement(this);
    result.setDeclaration(decl);
    return result;
  }

  /**
   * Creates and returns a new unparented type literal expression node
   * owned by this AST. By default, the type is unspecified (but legal).
   *
   * @return a new unparented type literal node
   */
  public TypeLiteral newTypeLiteral() {
    TypeLiteral result = new TypeLiteral(this);
    return result;
  }

  /**
   * Creates and returns a new unparented type parameter type node with an
   * unspecified type variable name and an empty list of type bounds.
   *
   * @return a new unparented type parameter node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public TypeParameter newTypeParameter() {
    TypeParameter result = new TypeParameter(this);
    return result;
  }

  /**
   * Creates a new unparented local variable declaration expression node
   * owned by this AST, for the given variable declaration fragment. By
   * default, there are no modifiers and the base type is unspecified
   * (but legal).
   * <p>
   * This method can be used to convert a variable declaration fragment
   * (<code>VariableDeclarationFragment</code>) into an expression
   * (<code>Expression</code>) by wrapping it. Additional variable
   * declaration fragments can be added afterwards.
   * </p>
   *
   * @param fragment the first variable declaration fragment
   * @return a new unparented variable declaration expression node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * <li>the given fragment is null</li>
   * </ul>
   */
  public VariableDeclarationExpression
      newVariableDeclarationExpression(VariableDeclarationFragment fragment) {
    if (fragment == null) {
      throw new IllegalArgumentException();
    }
    VariableDeclarationExpression result =
      new VariableDeclarationExpression(this);
    result.fragments().add(fragment);
    return result;
  }

  /**
   * Creates an unparented variable declaration fragment node owned by this
   * AST. By default, the fragment is for a variable with an unspecified, but
   * legal, name; no extra array dimensions; and no initializer.
   *
   * @return a new unparented variable declaration fragment node
   */
  public VariableDeclarationFragment newVariableDeclarationFragment() {
    VariableDeclarationFragment result = new VariableDeclarationFragment(this);
    return result;
  }

  //=============================== STATEMENTS ===========================
  /**
   * Creates a new unparented local variable declaration statement node
   * owned by this AST, for the given variable declaration fragment.
   * By default, there are no modifiers and the base type is unspecified
   * (but legal).
   * <p>
   * This method can be used to convert a variable declaration fragment
   * (<code>VariableDeclarationFragment</code>) into a statement
   * (<code>Statement</code>) by wrapping it. Additional variable
   * declaration fragments can be added afterwards.
   * </p>
   *
   * @param fragment the variable declaration fragment
   * @return a new unparented variable declaration statement node
   * @exception IllegalArgumentException if:
   * <ul>
   * <li>the node belongs to a different AST</li>
   * <li>the node already has a parent</li>
   * <li>the variable declaration fragment is null</li>
   * </ul>
   */
  public VariableDeclarationStatement
      newVariableDeclarationStatement(VariableDeclarationFragment fragment) {
    if (fragment == null) {
      throw new IllegalArgumentException();
    }
    VariableDeclarationStatement result =
      new VariableDeclarationStatement(this);
    result.fragments().add(fragment);
    return result;
  }

  /**
   * Creates a new unparented while statement node owned by this AST.
   * By default, the expression is unspecified (but legal), and
   * the body statement is an empty block.
   *
   * @return a new unparented while statement node
   */
  public WhileStatement newWhileStatement() {
    return new WhileStatement(this);
  }

  /**
   * Creates and returns a new unparented wildcard type node with no
   * type bound.
   *
   * @return a new unparented wildcard type node
   * @exception UnsupportedOperationException if this operation is used in
   * a JLS2 AST
   * @since 3.1
   */
  public WildcardType newWildcardType() {
    WildcardType result = new WildcardType(this);
    return result;
  }

  /**
   * Reports that the given node has just gained a child.
   *
   * @param node the node that was modified
   * @param child the node that was added as a child
   * @param property the child or child list property descriptor
   * @since 3.0
   */
  void postAddChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) {
    // IMPORTANT: this method is called by readers during lazy init
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE ADD]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.postAddChildEvent(node, child, property);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has already been changed
    } finally {
      reenableEvents();
    }
  }

  /**
   * Reports that the given node has just been cloned.
   *
   * @param node the node that was cloned
   * @param clone the clone of <code>node</code>
   * @since 3.0
   */
  void postCloneNodeEvent(ASTNode node, ASTNode clone) {
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE CLONE]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.postCloneNodeEvent(node, clone);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has already been changed
    } finally {
      reenableEvents();
    }
  }

  /**
   * Reports that the given node jsut lost a child.
   *
   * @param node the node that was modified
   * @param child the child node that was removed
   * @param property the child or child list property descriptor
   * @since 3.0
   */
  void postRemoveChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) {
    // IMPORTANT: this method is called by readers during lazy init
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE DEL]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.postRemoveChildEvent(node, child, property);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has not been changed yet
    } finally {
      reenableEvents();
    }
  }

  /**
   * Reports that the given node has just had a child replaced.
   *
   * @param node the node modified
   * @param child the child removed
   * @param newChild the replacement child
   * @param property the child or child list property descriptor
   * @since 3.0
   */
  void postReplaceChildEvent(ASTNode node, ASTNode child, ASTNode newChild, StructuralPropertyDescriptor property) {
    // IMPORTANT: this method is called by readers during lazy init
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE REP]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.postReplaceChildEvent(node, child, newChild, property);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has not been changed yet
    } finally {
      reenableEvents();
    }
  }

  /**
   * Reports that the given node has just changed the value of a
   * non-child property.
   *
   * @param node the node that was modified
   * @param property the property descriptor
   * @since 3.0
   */
  void postValueChangeEvent(ASTNode node, SimplePropertyDescriptor property) {
    // IMPORTANT: this method is called by readers during lazy init
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE CHANGE]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.postValueChangeEvent(node, property);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has already been changed
    } finally {
      reenableEvents();
    }
  }

  /**
   * Reports that the given node is about to gain a child.
   *
   * @param node the node that to be modified
   * @param child the node that to be added as a child
   * @param property the child or child list property descriptor
   * @since 3.0
   */
  void preAddChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) {
    // IMPORTANT: this method is called by readers during lazy init
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE ADD]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.preAddChildEvent(node, child, property);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has already been changed
    } finally {
      reenableEvents();
    }
  }

  /**
   * Reports that the given node is about to be cloned.
   *
   * @param node the node to be cloned
   * @since 3.0
   */
  void preCloneNodeEvent(ASTNode node) {
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE CLONE]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.preCloneNodeEvent(node);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has already been changed
    } finally {
      reenableEvents();
    }
  }

  /**
   * Reports that the given node is about to lose a child.
   *
   * @param node the node about to be modified
   * @param child the node about to be removed
   * @param property the child or child list property descriptor
   * @since 3.0
   */
  void preRemoveChildEvent(ASTNode node, ASTNode child, StructuralPropertyDescriptor property) {
    // IMPORTANT: this method is called by readers during lazy init
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE DEL]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.preRemoveChildEvent(node, child, property);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has not been changed yet
    } finally {
      reenableEvents();
    }
  }

  /**
   * Reports that the given node is about have a child replaced.
   *
   * @param node the node about to be modified
   * @param child the child node about to be removed
   * @param newChild the replacement child
   * @param property the child or child list property descriptor
   * @since 3.0
   */
  void preReplaceChildEvent(ASTNode node, ASTNode child, ASTNode newChild, StructuralPropertyDescriptor property) {
    // IMPORTANT: this method is called by readers during lazy init
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE REP]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.preReplaceChildEvent(node, child, newChild, property);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has not been changed yet
    } finally {
      reenableEvents();
    }
  }

  /**
   * Reports that the given node is about to change the value of a
   * non-child property.
   *
   * @param node the node to be modified
   * @param property the property descriptor
   * @since 3.0
   */
  void preValueChangeEvent(ASTNode node, SimplePropertyDescriptor property) {
    // IMPORTANT: this method is called by readers during lazy init
    synchronized (this.internalASTLock) {
      // guard against concurrent access by a reader doing lazy init
      if (this.disableEvents > 0) {
        // doing lazy init OR already processing an event
        // System.out.println("[BOUNCE CHANGE]");
        return;
      } else {
        disableEvents();
      }
    }
    try {
      this.eventHandler.preValueChangeEvent(node, property);
      // N.B. even if event handler blows up, the AST is not
      // corrupted since node has already been changed
    } finally {
      reenableEvents();
    }
  }

  /**
   * Enables the recording of changes to the given compilation
   * unit and its descendents. The compilation unit must have
   * been created by <code>ASTParser</code> and still be in
   * its original state. Once recording is on,
   * arbitrary changes to the subtree rooted at the compilation
   * unit are recorded internally. Once the modification has
   * been completed, call <code>rewrite</code> to get an object
   * representing the corresponding edits to the original
   * source code string.
   *
   * @exception IllegalArgumentException if this compilation unit is
   * marked as unmodifiable, or if this compilation unit has already
   * been tampered with, or if recording has already been enabled,
   * or if <code>root</code> is not owned by this AST
   * @see CompilationUnit#recordModifications()
   * @since 3.0
   */
  void recordModifications(CompilationUnit root) {
    if(this.modificationCount != this.originalModificationCount) {
      throw new IllegalArgumentException("AST is already modified"); //$NON-NLS-1$
    } else if(this.rewriter  != null) {
      throw new IllegalArgumentException("AST modifications are already recorded"); //$NON-NLS-1$
    } else if((root.getFlags() & ASTNode.PROTECT) != 0) {
      throw new IllegalArgumentException("Root node is unmodifiable"); //$NON-NLS-1$
    } else if(root.getAST() != this) {
      throw new IllegalArgumentException("Root node is not owned by this ast"); //$NON-NLS-1$
    }

    this.rewriter = new InternalASTRewrite(root);
    setEventHandler(this.rewriter);
  }

  //=============================== ANNOTATIONS ====================

  /**
     * Reenable events.
   * This method is thread-safe for AST readers.
   *
   * @see #disableEvents()
     * @since 3.0
     */
  final void reenableEvents() {
    synchronized (this.internalASTLock) {
      // guard against concurrent access by another reader
      this.disableEvents--;
    }
  }

  /**
   * Returns the type binding for a "well known" type.
   * <p>
   * Note that bindings are generally unavailable unless requested when the
   * AST is being built.
   * </p>
   * <p>
   * The following type names are supported:
   * <ul>
   * <li><code>"boolean"</code></li>
   * <li><code>"byte"</code></li>
   * <li><code>"char"</code></li>
   * <li><code>"double"</code></li>
   * <li><code>"float"</code></li>
   * <li><code>"int"</code></li>
   * <li><code>"long"</code></li>
   * <li><code>"short"</code></li>
   * <li><code>"void"</code></li>
   * <li><code>"java.lang.AssertionError"</code> (since 3.7)</li>
   * <li><code>"java.lang.Boolean"</code> (since 3.1)</li>
   * <li><code>"java.lang.Byte"</code> (since 3.1)</li>
   * <li><code>"java.lang.Character"</code> (since 3.1)</li>
   * <li><code>"java.lang.Class"</code></li>
   * <li><code>"java.lang.Cloneable"</code></li>
   * <li><code>"java.lang.Double"</code> (since 3.1)</li>
   * <li><code>"java.lang.Error"</code></li>
   * <li><code>"java.lang.Exception"</code></li>
   * <li><code>"java.lang.Float"</code> (since 3.1)</li>
   * <li><code>"java.lang.Integer"</code> (since 3.1)</li>
   * <li><code>"java.lang.Long"</code> (since 3.1)</li>
   * <li><code>"java.lang.Object"</code></li>
   * <li><code>"java.lang.RuntimeException"</code></li>
   * <li><code>"java.lang.Short"</code> (since 3.1)</li>
   * <li><code>"java.lang.String"</code></li>
   * <li><code>"java.lang.StringBuffer"</code></li>
   * <li><code>"java.lang.Throwable"</code></li>
   * <li><code>"java.lang.Void"</code> (since 3.1)</li>
   * <li><code>"java.io.Serializable"</code></li>
   * </ul>
   * </p>
   *
   * @param name the name of a well known type
   * @return the corresponding type binding, or <code>null</code> if the
   *   named type is not considered well known or if no binding can be found
   *   for it
   */
  public ITypeBinding resolveWellKnownType(String name) {
    if (name == null) {
      return null;
    }
    return getBindingResolver().resolveWellKnownType(name);
  }

  /**
   * Converts all modifications recorded into an object
   * representing the corresponding text edits to the
   * given document containing the original source
   * code for the compilation unit that gave rise to
   * this AST.
   *
   * @param document original document containing source code
   * for the compilation unit
   * @param options the table of formatter options
   * (key type: <code>String</code>; value type: <code>String</code>);
   * or <code>null</code> to use the standard global options
   * {@link JavaCore#getOptions() JavaCore.getOptions()}.
   * @return text edit object describing the changes to the
   * document corresponding to the recorded AST modifications
   * @exception IllegalArgumentException if the document passed is
   * <code>null</code> or does not correspond to this AST
   * @exception IllegalStateException if <code>recordModifications</code>
   * was not called to enable recording
   * @see CompilationUnit#rewrite(IDocument, Map)
   * @since 3.0
   */
  TextEdit rewrite(IDocument document, Map options) {
    if (document == null) {
      throw new IllegalArgumentException();
    }
    if (this.rewriter  == null) {
      throw new IllegalStateException("Modifications record is not enabled"); //$NON-NLS-1$
    }
    return this.rewriter.rewriteAST(document, options);
  }

  /**
   * Sets the binding resolver for this AST.
   *
   * @param resolver the new binding resolver for this AST
   */
  void setBindingResolver(BindingResolver resolver) {
    if (resolver == null) {
      throw new IllegalArgumentException();
    }
    this.resolver = resolver;
  }

  /**
   * Sets default node flags of new nodes of this AST.
   *
   * @param flag node flags of new nodes of this AST
   * @since 3.0
   */
  void setDefaultNodeFlag(int flag) {
    this.defaultNodeFlag = flag;
  }

  /**
   * Sets the event handler for this AST.
   *
   * @param eventHandler the event handler for this AST
   * @since 3.0
   */
  void setEventHandler(NodeEventHandler eventHandler) {
    if (this.eventHandler == null) {
      throw new IllegalArgumentException();
    }
    this.eventHandler = eventHandler;
  }

  void setFlag(int newValue) {
    this.bits |= newValue;
  }

  /**
   * Set <code>originalModificationCount</code> to the current modification count
   *
   * @since 3.0
   */
  void setOriginalModificationCount(long count) {
    this.originalModificationCount = count;
  }

  /**
     * Checks that this AST operation is only used when
     * building level JLS2 ASTs.

     * @exception UnsupportedOperationException
   * @since 3.0
     */
  void supportedOnlyIn2() {
    if (this.apiLevel != AST.JLS2) {
      throw new UnsupportedOperationException("Operation not supported in JLS2 AST"); //$NON-NLS-1$
    }
  }

  /**
     * Checks that this AST operation is not used when
     * building level JLS2 ASTs.

     * @exception UnsupportedOperationException
   * @since 3.0
     */
  void unsupportedIn2() {
    if (this.apiLevel == AST.JLS2) {
      throw new UnsupportedOperationException("Operation not supported in JLS2 AST"); //$NON-NLS-1$
    }
  }
}
TOP

Related Classes of org.eclipse.jdt.core.dom.AST

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.