| /******************************************************************************* |
| * Copyright (c) 2000, 2013 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. |
| */ |
| @SuppressWarnings({ "rawtypes", "unchecked" }) |
| // AspectJ Extension - made non-final |
| public 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 #JLS8} 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 #JLS8} 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 |
| * @deprecated Clients should use the {@link #JLS8} AST API instead. |
| */ |
| public static final int JLS4 = 4; |
| |
| /** |
| * Internal synonym for {@link #JLS4}. Use to alleviate |
| * deprecation warnings. |
| * @since 3.10 |
| */ |
| /*package*/ static final int JLS4_INTERNAL = JLS4; |
| |
| /** |
| * Constant for indicating the AST API that handles JLS8. |
| * <p> |
| * This API is capable of handling all constructs in the |
| * Java language as described in the Java Language |
| * Specification, Java SE 8 Edition (JLS8) as specified by JSR337. |
| * JLS8 is a superset of all earlier versions of the |
| * Java language, and the JLS8 API can be used to manipulate |
| * programs written in all versions of the Java language |
| * up to and including Java SE 8 (aka JDK 1.8). |
| * </p> |
| * |
| * @since 3.10 |
| */ |
| public static final int JLS8 = 8; |
| |
| /* |
| * 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) { |
| |
| // AspectJ extension - use the factory |
| // old code: |
| // ASTConverter converter = new ASTConverter(options, isResolved, monitor); |
| // new code: |
| ASTConverter converter = ASTConverter.getASTConverter(options,isResolved,monitor); |
| // End AspectJ Extension |
| 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 #JLS8} 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.10 // Up'd from 3.0 because of @since check due to raising visibility |
| */ |
| protected AST(int level) { // AspectJ - raised to protected |
| 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_INTERNAL : |
| 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; |
| case JLS8 : |
| this.apiLevel = level; |
| // initialize a scanner |
| this.scanner = new Scanner( |
| true /*comment*/, |
| true /*whitespace*/, |
| false /*nls*/, |
| ClassFileConstants.JDK1_8 /*sourceLevel*/, |
| ClassFileConstants.JDK1_8 /*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 |
| * or is not supported for this AST's API level |
| * @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 |
| IllegalArgumentException iae = new IllegalArgumentException(); |
| iae.initCause(e.getCause()); |
| throw iae; |
| } |
| } |
| |
| /** |
| * 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 or if it's not supported for this AST's API level |
| * @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++; |
| } |
| |
| /** |
| * A local method to workaround calling deprecated method in array type. |
| * @deprecated |
| */ |
| private void setArrayComponentType(ArrayType arrayType, Type type) { |
| arrayType.setComponentType(type); |
| } |
| |
| /** |
| * 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 |
| * element type, which cannot be an array type for API levels JLS8 and later. |
| * By default, the array type has one non-annotated dimension. |
| * <p> |
| * For JLS4 and before, the given component type may be another array type. |
| * |
| * @param elementType element type for API level JLS8 and later, or the |
| * component type (possibly another array type) for levels less than JLS8 |
| * @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>API level is JLS8 or later and type is an array type</li> |
| * </ul> |
| */ |
| public ArrayType newArrayType(Type elementType) { |
| ArrayType result; |
| if (this.apiLevel < AST.JLS8) { |
| result = new ArrayType(this); |
| setArrayComponentType(result, elementType); |
| return result; |
| } |
| if (elementType.isArrayType()) { |
| throw new IllegalArgumentException(); |
| } |
| result = new ArrayType(this); |
| result.setElementType(elementType); |
| return result; |
| } |
| |
| /** |
| * Creates and returns a new unparented array type node with the given |
| * element type and number of dimensions. |
| * <p> |
| * For JLS4 and before, the element type passed in can be an array type, but in that case, the |
| * element type of the result will not be the same as what was passed in. |
| * For JLS4 and before, the dimensions cannot be 0. |
| * </p> |
| * |
| * @param elementType the element type (cannot be an array type for JLS8 and later) |
| * @param dimensions the number of dimensions, a non-negative 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 0 (for JLS4 and before: lower than 1)</li> |
| * <li>the number of dimensions is greater than 255</li> |
| * <li>for levels from JLS8 and later, if the element type is an array type </li> |
| * </ul> |
| */ |
| public ArrayType newArrayType(Type elementType, int dimensions) { |
| if (elementType == null) { |
| throw new IllegalArgumentException(); |
| } |
| if (dimensions < 0 || dimensions > 255) { |
| // max as per Java VM spec |
| throw new IllegalArgumentException(); |
| } |
| ArrayType result; |
| if (this.apiLevel < AST.JLS8) { |
| if (dimensions < 1) { |
| throw new IllegalArgumentException(); |
| } |
| result = new ArrayType(this); |
| setArrayComponentType(result, elementType); |
| for (int i = 2; i <= dimensions; i++) { |
| result = newArrayType(result); |
| } |
| return result; |
| } |
| //level >= JLS8 |
| if (elementType.isArrayType()) { |
| throw new IllegalArgumentException(); |
| } |
| result = new ArrayType(this, 0); |
| result.setElementType(elementType); |
| for (int i = 0; i < dimensions; ++i) { |
| result.dimensions().add(new Dimension(this)); |
| } |
| 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 an unparented creation reference node owned by this AST. |
| * By default, the type is unspecified (but legal), and there are no type arguments. |
| * |
| * @return a new unparented creation reference expression node |
| * @exception UnsupportedOperationException if this operation is used in a JLS2, JLS3 or JLS4 AST |
| * @since 3.10 |
| */ |
| public CreationReference newCreationReference() { |
| CreationReference result = new CreationReference(this); |
| return result; |
| } |
| |
| /** |
| * 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 an unparented expression method reference node owned by this AST. |
| * By default, the expression and method name are unspecified (but legal), |
| * and there are no type arguments. |
| * |
| * @return a new unparented expression method reference expression node |
| * @exception UnsupportedOperationException if this operation is used in a JLS2, JLS3 or JLS4 AST |
| * @since 3.10 |
| */ |
| public ExpressionMethodReference newExpressionMethodReference() { |
| ExpressionMethodReference result = new ExpressionMethodReference(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 annotatable dimension node |
| * (Supported only in JLS8 level). |
| * |
| * @return a new unparented annotatable dimension 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, JLS3 or JLS4 AST |
| * @since 3.10 |
| */ |
| public Dimension newDimension() { |
| Dimension result = new Dimension(this); |
| 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 an unparented lambda expression node owned by this AST. |
| * By default, the new lambda expression has parentheses enabled, contains an empty argument |
| * list, and the body is an empty block. |
| * |
| * @return a new unparented lambda expression node |
| * @exception UnsupportedOperationException if this operation is used in a JLS2, JLS3 or JLS4 AST |
| * @since 3.10 |
| */ |
| public LambdaExpression newLambdaExpression() { |
| LambdaExpression result = new LambdaExpression(this); |
| return result; |
| } |
| |
| /** |
| * 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 modifier nodes will appear in the following order: |
| * <pre> public protected private |
| * abstract default static final synchronized native strictfp transient volatile</pre> |
| * <p> |
| * This order is consistent with the recommendations in JLS8 ("*Modifier:" rules in chapters 8 and 9). |
| * </p> |
| * |
| * @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.isDefault(flags)) { |
| result.add(newModifier(Modifier.ModifierKeyword.DEFAULT_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, '<', '>', |
| * '[', ']', 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 name qualified type node with |
| * the given qualifier and name. |
| * |
| * @param qualifier the name qualifier name 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, JLS3 and JLS4 AST |
| * @since 3.10 |
| */ |
| public NameQualifiedType newNameQualifiedType(Name qualifier, SimpleName name) { |
| NameQualifiedType result = new NameQualifiedType(this); |
| result.setQualifier(qualifier); |
| result.setName(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 and returns a new unparented super method reference node owned by |
| * this AST. By default, the name of the method is unspecified (but legal), |
| * and there is no qualifier and no type arguments. |
| * |
| * @return a new unparented super method reference node |
| * @since 3.10 |
| */ |
| public SuperMethodReference newSuperMethodReference() { |
| SuperMethodReference result = new SuperMethodReference(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() { |
| // AspectJ Extension - use factory rather than ctor |
| // old code: |
| // TypeDeclaration result = new TypeDeclaration(this); |
| // new code: |
| TypeDeclaration result = TypeDeclaration.getTypeDeclaration(this); |
| // End AspectJ Extension |
| 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 an unparented type method reference node owned by this AST. |
| * By default, the type and method name are unspecified (but legal), |
| * and there are no type arguments. |
| * |
| * @return a new unparented type method reference node |
| * @exception UnsupportedOperationException if this operation is used in a JLS2, JLS3 or JLS4 AST |
| * @since 3.10 |
| */ |
| public TypeMethodReference newTypeMethodReference() { |
| TypeMethodReference result = new TypeMethodReference(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 union type node owned by this AST. |
| * By default, the union type has no types. |
| * |
| * @return a new unparented UnionType node |
| * @exception UnsupportedOperationException if this operation is used in |
| * a JLS2 or JLS3 AST |
| * @since 3.7.1 |
| */ |
| public UnionType newUnionType() { |
| return new UnionType(this); |
| } |
| |
| /** |
| * Creates a new unparented intersection type node owned by this AST. |
| * By default, the intersection type has no types. |
| * |
| * @return a new unparented IntersectionType node |
| * @exception UnsupportedOperationException if this operation is used in |
| * a JLS2, JLS3 or JLS4 AST |
| * @since 3.10 |
| */ |
| public IntersectionType newIntersectionType() { |
| return new IntersectionType(this); |
| } |
| |
| /** |
| * 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$ |
| } |
| } |
| } |
| |