Copyright (c) 2004, 2019 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Stephan Herrmann - Contribution for Bug 458577 - IClassFile.getWorkingCopy() may lead to NPE in BecomeWorkingCopyOperation
/******************************************************************************* * Copyright (c) 2004, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Stephan Herrmann - Contribution for * Bug 458577 - IClassFile.getWorkingCopy() may lead to NPE in BecomeWorkingCopyOperation *******************************************************************************/
package org.eclipse.jdt.core.dom; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.jdt.core.IClassFile; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.WorkingCopyOwner; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; import org.eclipse.jdt.internal.compiler.batch.Main; import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; import org.eclipse.jdt.internal.compiler.env.IBinaryType; import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; import org.eclipse.jdt.internal.compiler.parser.Scanner; import org.eclipse.jdt.internal.compiler.util.SuffixConstants; import org.eclipse.jdt.internal.core.*; import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil; import org.eclipse.jdt.internal.core.util.RecordedParsingInformation; import org.eclipse.jdt.internal.core.util.Util;
A Java language parser for creating abstract syntax trees (ASTs).

Example: Create basic AST from source string

char[] source = ...;
ASTParser parser = ASTParser.newParser(AST.JLS3);  // handles JDK 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6
parser.setSource(source);
// In order to parse 1.5 code, some compiler options need to be set to 1.5
Map options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_5, options);
parser.setCompilerOptions(options);
CompilationUnit result = (CompilationUnit) parser.createAST(null);

Once a configured parser instance has been used to create an AST, the settings are automatically reset to their defaults, ready for the parser instance to be reused.

There are a number of configurable features:

Since:3.0
@noinstantiateThis class is not intended to be instantiated by clients.
/** * A Java language parser for creating abstract syntax trees (ASTs). * <p> * Example: Create basic AST from source string * <pre> * char[] source = ...; * ASTParser parser = ASTParser.newParser(AST.JLS3); // handles JDK 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6 * parser.setSource(source); * // In order to parse 1.5 code, some compiler options need to be set to 1.5 * Map options = JavaCore.getOptions(); * JavaCore.setComplianceOptions(JavaCore.VERSION_1_5, options); * parser.setCompilerOptions(options); * CompilationUnit result = (CompilationUnit) parser.createAST(null); * </pre> * <p> * Once a configured parser instance has been used to create an AST, * the settings are automatically reset to their defaults, * ready for the parser instance to be reused. * </p> * <p> * There are a number of configurable features: * <ul> * <li>Source string from {@link #setSource(char[]) char[]}, * {@link #setSource(ICompilationUnit) ICompilationUnit}, * or {@link #setSource(IClassFile) IClassFile}, and limited * to a specified {@linkplain #setSourceRange(int,int) subrange}.</li> * <li>Whether {@linkplain #setResolveBindings(boolean) bindings} will be created.</li> * <li>Which {@linkplain #setWorkingCopyOwner(WorkingCopyOwner) * working copy owner} to use when resolving bindings.</li> * <li>A hypothetical {@linkplain #setUnitName(String) compilation unit file name} * and {@linkplain #setProject(IJavaProject) Java project} * for locating a raw source string in the Java model (when * resolving bindings)</li> * <li>Which {@linkplain #setCompilerOptions(Map) compiler options} * to use. This is especially important to use if the parsing/scanning of the source code requires a * different version than the default of the workspace. For example, the workspace defaults are 1.4 and * you want to create an AST for a source code that is using 1.5 constructs.</li> * <li>Whether to parse just {@linkplain #setKind(int) an expression, statements, * or body declarations} rather than an entire compilation unit.</li> * <li>Whether to return a {@linkplain #setFocalPosition(int) abridged AST} * focused on the declaration containing a given source position.</li> * </ul> * * @since 3.0 * @noinstantiate This class is not intended to be instantiated by clients. */
@SuppressWarnings({"rawtypes"}) public class ASTParser {
Kind constant used to request that the source be parsed as a single expression.
/** * Kind constant used to request that the source be parsed * as a single expression. */
public static final int K_EXPRESSION = 0x01;
Kind constant used to request that the source be parsed as a sequence of statements.
/** * Kind constant used to request that the source be parsed * as a sequence of statements. */
public static final int K_STATEMENTS = 0x02;
Kind constant used to request that the source be parsed as a sequence of class body declarations.
/** * Kind constant used to request that the source be parsed * as a sequence of class body declarations. */
public static final int K_CLASS_BODY_DECLARATIONS = 0x04;
Kind constant used to request that the source be parsed as a compilation unit.
/** * Kind constant used to request that the source be parsed * as a compilation unit. */
public static final int K_COMPILATION_UNIT = 0x08;
Creates a new object for creating a Java abstract syntax tree (AST) following the specified set of API rules.
Params:
  • level – the API level; one of the .JLS* level constants declared on AST
Returns:new ASTParser instance
/** * Creates a new object for creating a 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 * declared on {@link AST} * @return new ASTParser instance */
public static ASTParser newParser(int level) { return new ASTParser(level); }
Level of AST API desired.
/** * Level of AST API desired. */
private final int apiLevel;
Kind of parse requested. Defaults to an entire compilation unit.
/** * Kind of parse requested. Defaults to an entire compilation unit. */
private int astKind;
Compiler options. Defaults to JavaCore.getOptions().
/** * Compiler options. Defaults to JavaCore.getOptions(). */
private Map<String, String> compilerOptions;
The focal point for a partial AST request. Only used when partial is true.
/** * The focal point for a partial AST request. * Only used when <code>partial</code> is <code>true</code>. */
private int focalPointPosition;
Source string.
/** * Source string. */
private char[] rawSource = null;
Java model class file or compilation unit supplying the source.
/** * Java model class file or compilation unit supplying the source. */
private ITypeRoot typeRoot = null;
Character-based offset into the source string where parsing is to begin. Defaults to 0.
/** * Character-based offset into the source string where parsing is to * begin. Defaults to 0. */
private int sourceOffset = 0;
Character-based length limit, or -1 if unlimited. All characters in the source string between offset and offset+length-1 inclusive are parsed. Defaults to -1, which means the rest of the source string.
/** * Character-based length limit, or -1 if unlimited. * All characters in the source string between <code>offset</code> * and <code>offset+length-1</code> inclusive are parsed. Defaults to -1, * which means the rest of the source string. */
private int sourceLength = -1;
Working copy owner. Defaults to primary owner.
/** * Working copy owner. Defaults to primary owner. */
private WorkingCopyOwner workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
Java project used to resolve names, or null if none. Defaults to none.
/** * Java project used to resolve names, or <code>null</code> if none. * Defaults to none. */
private IJavaProject project = null;
Name of the compilation unit for resolving bindings, or null if none. Defaults to none.
/** * Name of the compilation unit for resolving bindings, or * <code>null</code> if none. Defaults to none. */
private String unitName = null;
Classpath entries to use to resolve bindings when no java project are available.
/** * Classpath entries to use to resolve bindings when no java project are available. */
private String[] classpaths;
Sourcepath entries to use to resolve bindings when no java project are available.
/** * Sourcepath entries to use to resolve bindings when no java project are available. */
private String[] sourcepaths;
Encoding of the given sourcepaths entries.
/** * Encoding of the given sourcepaths entries. */
private String[] sourcepathsEncodings;
Bits used to set the different values from CompilationUnitResolver values.
/** * Bits used to set the different values from CompilationUnitResolver values. */
private int bits;
Creates a new AST parser for the given API level.

N.B. This constructor is package-private.

Params:
  • level – the API level; one of the JLS* level constants declared on AST
/** * Creates a new AST parser for the given API level. * <p> * N.B. This constructor is package-private. * </p> * * @param level the API level; one of the <code>JLS*</code> level constants * declared on {@link AST} */
ASTParser(int level) { switch(level) { case AST.JLS2_INTERNAL: case AST.JLS3_INTERNAL: case AST.JLS4_INTERNAL: case AST.JLS8_INTERNAL: case AST.JLS9_INTERNAL: case AST.JLS10_INTERNAL: case AST.JLS11_INTERNAL: case AST.JLS12_INTERNAL: case AST.JLS13_INTERNAL: break; default: throw new IllegalArgumentException(); } this.apiLevel = level; initializeDefaults(); } private List<Classpath> getClasspath() throws IllegalStateException { Main main = new Main(new PrintWriter(System.out), new PrintWriter(System.err), false/*systemExit*/, null/*options*/, null/*progress*/); ArrayList<Classpath> allClasspaths = new ArrayList<Classpath>(); try { if ((this.bits & CompilationUnitResolver.INCLUDE_RUNNING_VM_BOOTCLASSPATH) != 0) { org.eclipse.jdt.internal.compiler.util.Util.collectRunningVMBootclasspath(allClasspaths); } if (this.sourcepaths != null) { for (int i = 0, max = this.sourcepaths.length; i < max; i++) { String encoding = this.sourcepathsEncodings == null ? null : this.sourcepathsEncodings[i]; main.processPathEntries( Main.DEFAULT_SIZE_CLASSPATH, allClasspaths, this.sourcepaths[i], encoding, true, false); } } if (this.classpaths != null) { for (int i = 0, max = this.classpaths.length; i < max; i++) { main.processPathEntries( Main.DEFAULT_SIZE_CLASSPATH, allClasspaths, this.classpaths[i], null, false, false); } } ArrayList pendingErrors = main.pendingErrors; if (pendingErrors != null && pendingErrors.size() != 0) { throw new IllegalStateException("invalid environment settings"); //$NON-NLS-1$ } } catch (IllegalArgumentException e) { throw new IllegalStateException("invalid environment settings", e); //$NON-NLS-1$ } return allClasspaths; }
Sets all the setting to their default values.
/** * Sets all the setting to their default values. */
private void initializeDefaults() { this.astKind = K_COMPILATION_UNIT; this.rawSource = null; this.typeRoot = null; this.bits = 0; this.sourceLength = -1; this.sourceOffset = 0; this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY; this.unitName = null; this.project = null; this.classpaths = null; this.sourcepaths = null; this.sourcepathsEncodings = null; Map<String, String> options = JavaCore.getOptions(); options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags this.compilerOptions = options; }
Requests that the compiler should perform bindings recovery. When bindings recovery is enabled the compiler returns incomplete bindings.

Default to false.

This should be set to true only if bindings are resolved. It has no effect if there is no binding resolution.

Params:
  • enabled – true if incomplete bindings are expected, and false if only complete bindings are expected.
See Also:
Since:3.3
/** * Requests that the compiler should perform bindings recovery. * When bindings recovery is enabled the compiler returns incomplete bindings. * <p> * Default to <code>false</code>. * </p> * <p>This should be set to true only if bindings are resolved. It has no effect if there is no binding * resolution.</p> * * @param enabled <code>true</code> if incomplete bindings are expected, * and <code>false</code> if only complete bindings are expected. * * @see IBinding#isRecovered() * @since 3.3 */
public void setBindingsRecovery(boolean enabled) { if (enabled) { this.bits |= CompilationUnitResolver.BINDING_RECOVERY; } else { this.bits &= ~CompilationUnitResolver.BINDING_RECOVERY; } }
Sets the environment to be used when no IJavaProject is available.

The user has to make sure that all the required types are included either in the classpath or source paths. All the paths containing binary types must be included in the classpathEntries whereas all paths containing source types must be included in the sourcepathEntries.

All paths in the classpathEntries and sourcepathEntries are absolute paths.

If the source paths contain units using a specific encoding (other than the platform encoding), then the given encodings must be set. When the encodings is set to non null, its length must match the length of sourcepathEntries or an IllegalArgumentException will be thrown.

If encodings is not null, the given sourcepathEntries must not be null.

Params:
  • classpathEntries – the given classpath entries to be used to resolve bindings
  • sourcepathEntries – the given sourcepath entries to be used to resolve bindings
  • encodings – the encodings of the corresponding sourcepath entries or null if the platform encoding can be used.
  • includeRunningVMBootclasspath – true if the bootclasspath of the running VM must be prepended to the given classpath and false if the bootclasspath of the running VM should be ignored.
Throws:
  • IllegalArgumentException – if the size of the given encodings is not equals to the size of the given sourcepathEntries
Since:3.6
/** * Sets the environment to be used when no {@link IJavaProject} is available. * * <p>The user has to make sure that all the required types are included either in the classpath or source paths. * All the paths containing binary types must be included in the <code>classpathEntries</code> whereas all paths containing * source types must be included in the <code>sourcepathEntries</code>.</p> * <p>All paths in the <code>classpathEntries</code> and <code>sourcepathEntries</code> are absolute paths.</p> * <p>If the source paths contain units using a specific encoding (other than the platform encoding), then the * given <code>encodings</code> must be set. When the <code>encodings</code> is set to non <code>null</code>, its length must * match the length of <code>sourcepathEntries</code> or an IllegalArgumentException will be thrown.</p> * <p>If <code>encodings</code> is not <code>null</code>, the given <code>sourcepathEntries</code> must not be <code>null</code>.</p> * * @param classpathEntries the given classpath entries to be used to resolve bindings * @param sourcepathEntries the given sourcepath entries to be used to resolve bindings * @param encodings the encodings of the corresponding sourcepath entries or <code>null</code> if the platform encoding * can be used. * @param includeRunningVMBootclasspath <code>true</code> if the bootclasspath of the running VM must be prepended to the * given classpath and <code>false</code> if the bootclasspath of the running VM should be ignored. * @throws IllegalArgumentException if the size of the given encodings is not equals to the size of the given <code> * sourcepathEntries</code> * @since 3.6 */
public void setEnvironment(String[] classpathEntries, String[] sourcepathEntries, String[] encodings, boolean includeRunningVMBootclasspath) { this.classpaths = classpathEntries; this.sourcepaths = sourcepathEntries; this.sourcepathsEncodings = encodings; if (encodings != null) { if (sourcepathEntries == null || sourcepathEntries.length != encodings.length) { throw new IllegalArgumentException(); } } if (includeRunningVMBootclasspath) { this.bits |= CompilationUnitResolver.INCLUDE_RUNNING_VM_BOOTCLASSPATH; } }
Sets the compiler options to be used when parsing.

Note that setSource(IClassFile), setSource(ICompilationUnit), and setProject(IJavaProject) reset the compiler options based on the Java project. In other cases, compiler options default to JavaCore.getOptions(). In either case, and especially in the latter, the caller should carefully weight the consequences of allowing compiler options to be defaulted as opposed to being explicitly specified for the ASTParser instance. For instance, there is a compiler option called "Source Compatibility Mode" which determines which JDK level the source code is expected to meet. If you specify "1.4", then "assert" is treated as a keyword and disallowed as an identifier; if you specify "1.3", then "assert" is allowed as an identifier. So this particular setting has a major bearing on what is considered syntactically legal. By explicitly specifying the setting, the client control exactly how the parser works. On the other hand, allowing default settings means the parsing behaves like other JDT tools.

Params:
  • options – the table of options (key type: String; value type: String), or null to set it back to the default
/** * Sets the compiler options to be used when parsing. * <p> * Note that {@link #setSource(IClassFile)}, * {@link #setSource(ICompilationUnit)}, * and {@link #setProject(IJavaProject)} reset the compiler options * based on the Java project. In other cases, compiler options default * to {@link JavaCore#getOptions()}. In either case, and especially * in the latter, the caller should carefully weight the consequences of * allowing compiler options to be defaulted as opposed to being * explicitly specified for the {@link ASTParser} instance. * For instance, there is a compiler option called "Source Compatibility Mode" * which determines which JDK level the source code is expected to meet. * If you specify "1.4", then "assert" is treated as a keyword and disallowed * as an identifier; if you specify "1.3", then "assert" is allowed as an * identifier. So this particular setting has a major bearing on what is * considered syntactically legal. By explicitly specifying the setting, * the client control exactly how the parser works. On the other hand, * allowing default settings means the parsing behaves like other JDT tools. * </p> * * @param options the table of options (key type: <code>String</code>; * value type: <code>String</code>), or <code>null</code> * to set it back to the default */
public void setCompilerOptions(Map<String, String> options) { if (options == null) { options = JavaCore.getOptions(); } else { // copy client's options so as to not do any side effect on them options = new HashMap<>(options); } options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags this.compilerOptions = options; }
Requests that the compiler should provide binding information for the AST nodes it creates.

Defaults to false (no bindings).

If setResolveBindings(true), the various names and types appearing in the AST can be resolved to "bindings" by calling the resolveBinding 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 resolveBinding 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 setResolveBindings(false), (the default), the analysis does not go beyond parsing and building the tree, and all resolveBinding methods return null from the outset.

When bindings are requested, instead of considering compilation units on disk only, one can also supply a WorkingCopyOwner. Working copies owned by this owner take precedence over the underlying compilation units when looking up names and drawing the connections.

Note that working copy owners are used only if the org.eclipse.jdt.core bundle is initialized.

Binding information is obtained from the Java model. This means that the compilation unit must be located relative to the Java model. This happens automatically when the source code comes from either setSource(ICompilationUnit) or setSource(IClassFile). When source is supplied by setSource(char[]), the location must be established explicitly by setting an environment using setProject(IJavaProject) or setEnvironment(String[], String[], String[], boolean) and a unit name setUnitName(String). Note that the compiler options that affect doc comment checking may also affect whether any bindings are resolved for nodes within doc comments.

Params:
  • enabled – true if bindings are wanted, and false if bindings are not of interest
/** * Requests that the compiler should provide binding information for * the AST nodes it creates. * <p> * Defaults to <code>false</code> (no bindings). * </p> * <p> * If {@link #setResolveBindings(boolean) setResolveBindings(true)}, the various names * and types appearing in the AST 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 {@link #setResolveBindings(boolean) setResolveBindings(false)}, (the default), 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> * When bindings are requested, instead of considering compilation units on disk only, * one can also supply a <code>WorkingCopyOwner</code>. Working copies owned * by this owner take precedence over the underlying compilation units when looking * up names and drawing the connections. * </p> * <p>Note that working copy owners are used only if the <code>org.eclipse.jdt.core</code> * bundle is initialized.</p> * <p> * Binding information is obtained from the Java model. * This means that the compilation unit must be located relative to the * Java model. This happens automatically when the source code comes from * either {@link #setSource(ICompilationUnit) setSource(ICompilationUnit)} * or {@link #setSource(IClassFile) setSource(IClassFile)}. * When source is supplied by {@link #setSource(char[]) setSource(char[])}, * the location must be established explicitly by setting an environment using * {@link #setProject(IJavaProject)} or {@link #setEnvironment(String[], String[], String[], boolean)} * and a unit name {@link #setUnitName(String)}. * Note that the compiler options that affect doc comment checking may also * affect whether any bindings are resolved for nodes within doc comments. * </p> * * @param enabled <code>true</code> if bindings are wanted, * and <code>false</code> if bindings are not of interest */
public void setResolveBindings(boolean enabled) { if (enabled) { this.bits |= CompilationUnitResolver.RESOLVE_BINDING; } else { this.bits &= ~CompilationUnitResolver.RESOLVE_BINDING; } }
Requests an abridged abstract syntax tree. By default, complete ASTs are returned.

When the given position is a valid position within the source code of the compilation unit, the resulting AST does not have nodes for the entire compilation unit. Rather, the AST is only fleshed out for the node that include the given source position. This kind of limited AST is sufficient for certain purposes but totally unsuitable for others. In places where it can be used, the limited AST offers the advantage of being smaller and faster to construct.

The AST will include nodes for all of the compilation unit's package, import, and top-level type declarations. It will also always contain nodes for all the body declarations for those top-level types, as well as body declarations for any member types. However, some of the body declarations may be abridged. In particular, the statements ordinarily found in the body of a method declaration node will not be included (the block will be empty) unless the source position falls somewhere within the source range of that method declaration node. The same is true for initializer declarations; the statements ordinarily found in the body of initializer node will not be included unless the source position falls somewhere within the source range of that initializer declaration node. Field declarations are never abridged. Note that the AST for the body of that one unabridged method (or initializer) is 100% complete; it has all its statements, including any local or anonymous type declarations embedded within them. When the given position is not located within the source range of any body declaration of a top-level type, the AST returned will be a skeleton that includes nodes for all and only the major declarations; this kind of AST is still quite useful because it contains all the constructs that introduce names visible to the world outside the compilation unit.

This focal position is not used when the AST is built using createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor).

Params:
  • position – a position into the corresponding body declaration
/** * Requests an abridged abstract syntax tree. * By default, complete ASTs are returned. * <p> * When the given <code>position</code> is a valid position within the source code of * the compilation unit, the resulting AST does not have nodes for * the entire compilation unit. Rather, the AST is only fleshed out * for the node that include the given source position. This kind of limited * AST is sufficient for certain purposes but totally unsuitable for others. * In places where it can be used, the limited AST offers the advantage of * being smaller and faster to construct. * </p> * <p> * The AST will include nodes for all of the compilation unit's * package, import, and top-level type declarations. It will also always contain * nodes for all the body declarations for those top-level types, as well * as body declarations for any member types. However, some of the body * declarations may be abridged. In particular, the statements ordinarily * found in the body of a method declaration node will not be included * (the block will be empty) unless the source position falls somewhere * within the source range of that method declaration node. The same is true * for initializer declarations; the statements ordinarily found in the body * of initializer node will not be included unless the source position falls * somewhere within the source range of that initializer declaration node. * Field declarations are never abridged. Note that the AST for the body of * that one unabridged method (or initializer) is 100% complete; it has all * its statements, including any local or anonymous type declarations * embedded within them. When the given <code>position</code> is not located within * the source range of any body declaration of a top-level type, the AST * returned will be a skeleton that includes nodes for all and only the major * declarations; this kind of AST is still quite useful because it contains * all the constructs that introduce names visible to the world outside the * compilation unit. * </p> * * <p>This focal position is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> * * @param position a position into the corresponding body declaration */
public void setFocalPosition(int position) { this.bits |= CompilationUnitResolver.PARTIAL; this.focalPointPosition = position; }
Sets the kind of constructs to be parsed from the source. Defaults to an entire compilation unit.

When the parse is successful the result returned includes the ASTs for the requested source:

The resulting AST node is rooted under (possibly contrived) CompilationUnit node, to allow the client to retrieve the following pieces of information available there:

The contrived nodes do not have source positions. Other aspects of the CompilationUnit node are unspecified, including the exact arrangement of intervening nodes.

Lexical or syntax errors detected while parsing can result in a result node being marked as MALFORMED. In more severe failure cases where the parser is unable to recognize the input, this method returns a CompilationUnit node with at least the compiler messages.

Each node in the subtree (other than the contrived nodes) carries source range(s) information relating back to positions in the given source (the given source 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 not included. The source range usually extends through the last character of the last token corresponding to the node; trailing whitespace and comments are not included. There are a handful of exceptions (including 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.

Binding information is only computed when kind is K_COMPILATION_UNIT.

This kind is not used when the AST is built using createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor).

Params:
/** * Sets the kind of constructs to be parsed from the source. * Defaults to an entire compilation unit. * <p> * When the parse is successful the result returned includes the ASTs for the * requested source: * <ul> * <li>{@link #K_COMPILATION_UNIT K_COMPILATION_UNIT}: The result node * is a {@link CompilationUnit}.</li> * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result node * is a {@link TypeDeclaration} whose * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations} * are the new trees. Other aspects of the type declaration are unspecified.</li> * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a * {@link Block Block} whose {@link Block#statements() statements} * are the new trees. Other aspects of the block are unspecified.</li> * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of * {@link Expression Expression}. Other aspects of the expression are unspecified.</li> * </ul> * <p> * The resulting AST node is rooted under (possibly contrived) * {@link CompilationUnit CompilationUnit} node, to allow the * client to retrieve the following pieces of information * available there: * </p> * <ul> * <li>{@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line * numbers start at 1 and only cover the subrange scanned * (<code>source[offset]</code> through <code>source[offset+length-1]</code>).</li> * <li>{@linkplain CompilationUnit#getMessages() Compiler messages} * and {@linkplain CompilationUnit#getProblems() detailed problem reports}. * Character positions are relative to the start of * <code>source</code>; line positions are for the subrange scanned.</li> * <li>{@linkplain CompilationUnit#getCommentList() Comment list} * for the subrange scanned.</li> * </ul> * <p> * The contrived nodes do not have source positions. Other aspects of the * {@link CompilationUnit CompilationUnit} node are unspecified, including * the exact arrangement of intervening nodes. * </p> * <p> * Lexical or syntax errors detected while parsing can result in * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}. * In more severe failure cases where the parser is unable to * recognize the input, this method returns * a {@link CompilationUnit CompilationUnit} node with at least the * compiler messages. * </p> * <p>Each node in the subtree (other than the contrived nodes) * carries source range(s) information relating back * to positions in the given source (the given source 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 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. * </p> * <p> * Binding information is only computed when <code>kind</code> is * {@link #K_COMPILATION_UNIT}. * </p> * * <p>This kind is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> * * @param kind the kind of construct to parse: one of * {@link #K_COMPILATION_UNIT}, * {@link #K_CLASS_BODY_DECLARATIONS}, * {@link #K_EXPRESSION}, * {@link #K_STATEMENTS} */
public void setKind(int kind) { if ((kind != K_COMPILATION_UNIT) && (kind != K_CLASS_BODY_DECLARATIONS) && (kind != K_EXPRESSION) && (kind != K_STATEMENTS)) { throw new IllegalArgumentException(); } this.astKind = kind; }
Sets the source code to be parsed.

This source is not used when the AST is built using createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor).

If this method is used, the user needs to specify compiler options explicitly using setCompilerOptions(Map<String,String>) as 1.5 code will not be properly parsed without setting the appropriate values for the compiler options: JavaCore.COMPILER_SOURCE, JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, and JavaCore.COMPILER_COMPLIANCE.

Otherwise the default values for the compiler options will be used to parse the given source.

Params:
  • source – the source string to be parsed, or null if none
See Also:
/** * Sets the source code to be parsed. * * <p>This source is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> * * <p>If this method is used, the user needs to specify compiler options explicitly using * {@link #setCompilerOptions(Map)} as 1.5 code will not be properly parsed without setting * the appropriate values for the compiler options: {@link JavaCore#COMPILER_SOURCE}, * {@link JavaCore#COMPILER_CODEGEN_TARGET_PLATFORM}, and {@link JavaCore#COMPILER_COMPLIANCE}.</p> * <p>Otherwise the default values for the compiler options will be used to parse the given source.</p> * * @param source the source string to be parsed, * or <code>null</code> if none * @see JavaCore#setComplianceOptions(String, Map) */
public void setSource(char[] source) { this.rawSource = source; // clear the type root this.typeRoot = null; }
Sets the source code to be parsed.

This method automatically sets the project (and compiler options) based on the given compilation unit, in a manner equivalent to setProject(source.getJavaProject()).

This source is not used when the AST is built using createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor).

Params:
  • source – the Java model compilation unit whose source code is to be parsed, or null if none
/** * Sets the source code to be parsed. * * <p>This method automatically sets the project (and compiler * options) based on the given compilation unit, in a manner * equivalent to {@link #setProject(IJavaProject) setProject(source.getJavaProject())}.</p> * * <p>This source is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> * * @param source the Java model compilation unit whose source code * is to be parsed, or <code>null</code> if none */
public void setSource(ICompilationUnit source) { setSource((ITypeRoot)source); }
Sets the source code to be parsed.

This method automatically sets the project (and compiler options) based on the given compilation unit, in a manner equivalent to setProject(source.getJavaProject()).

If the given class file has no source attachment, the creation of the ast will fail with an IllegalStateException.

This source is not used when the AST is built using createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor).

Params:
  • source – the Java model class file whose corresponding source code is to be parsed, or null if none
/** * Sets the source code to be parsed. * * <p>This method automatically sets the project (and compiler * options) based on the given compilation unit, in a manner * equivalent to {@link #setProject(IJavaProject) setProject(source.getJavaProject())}.</p> * <p>If the given class file has no source attachment, the creation of the * ast will fail with an {@link IllegalStateException}.</p> * * <p>This source is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> * * @param source the Java model class file whose corresponding source code * is to be parsed, or <code>null</code> if none */
public void setSource(IClassFile source) { setSource((ITypeRoot)source); }
Sets the source code to be parsed.

This method automatically sets the project (and compiler options) based on the given compilation unit of class file, in a manner equivalent to setProject(source.getJavaProject()).

If the source is a class file without source attachment, the creation of the ast will fail with an IllegalStateException.

This source is not used when the AST is built using createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor).

Params:
  • source – the Java model compilation unit or class file whose corresponding source code is to be parsed, or null if none
Since:3.3
/** * Sets the source code to be parsed. * * <p>This method automatically sets the project (and compiler * options) based on the given compilation unit of class file, in a manner * equivalent to {@link #setProject(IJavaProject) setProject(source.getJavaProject())}.</p> * <p>If the source is a class file without source attachment, the creation of the * ast will fail with an {@link IllegalStateException}.</p> * * <p>This source is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> * * @param source the Java model compilation unit or class file whose corresponding source code * is to be parsed, or <code>null</code> if none * @since 3.3 */
public void setSource(ITypeRoot source) { this.typeRoot = source; // clear the raw source this.rawSource = null; if (source != null) { this.project = source.getJavaProject(); Map<String, String> options = this.project.getOptions(true); options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags this.compilerOptions = options; } }
Sets the subrange of the source code to be parsed. By default, the entire source string will be parsed (offset 0 and length -1).

This range is not used when the AST is built using createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor).

Params:
  • offset – the index of the first character to parse
  • length – the number of characters to parse, or -1 if the remainder of the source string is to be parsed
/** * Sets the subrange of the source code to be parsed. * By default, the entire source string will be parsed * (<code>offset</code> 0 and <code>length</code> -1). * * <p>This range is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> * * @param offset the index of the first character to parse * @param length the number of characters to parse, or -1 if * the remainder of the source string is to be parsed */
public void setSourceRange(int offset, int length) { if (offset < 0 || length < -1) { throw new IllegalArgumentException(); } this.sourceOffset = offset; this.sourceLength = length; }
Requests that the compiler should perform statements recovery. When statements recovery is enabled the compiler tries to create statement nodes from code containing syntax errors

Default to false.

Params:
  • enabled – true if statements containing syntax errors are wanted, and false if these statements aren't wanted.
Since:3.2
/** * Requests that the compiler should perform statements recovery. * When statements recovery is enabled the compiler tries to create statement nodes * from code containing syntax errors * <p> * Default to <code>false</code>. * </p> * * @param enabled <code>true</code> if statements containing syntax errors are wanted, * and <code>false</code> if these statements aren't wanted. * * @since 3.2 */
public void setStatementsRecovery(boolean enabled) { if (enabled) { this.bits |= CompilationUnitResolver.STATEMENT_RECOVERY; } else { this.bits &= ~CompilationUnitResolver.STATEMENT_RECOVERY; } }
Requests an abstract syntax tree without method bodies.

When ignore method bodies is enabled, all method bodies are discarded. This has no impact on the binding resolution.

This setting is not used when the kind used in setKind(int) is either K_EXPRESSION or K_STATEMENTS.

Since:3.5.2
/** * Requests an abstract syntax tree without method bodies. * * <p>When ignore method bodies is enabled, all method bodies are discarded. * This has no impact on the binding resolution.</p> * * <p>This setting is not used when the kind used in {@link #setKind(int)} is either * {@link #K_EXPRESSION} or {@link #K_STATEMENTS}.</p> * @since 3.5.2 */
public void setIgnoreMethodBodies(boolean enabled) { if (enabled) { this.bits |= CompilationUnitResolver.IGNORE_METHOD_BODIES; } else { this.bits &= ~CompilationUnitResolver.IGNORE_METHOD_BODIES; } }
Sets the working copy owner used when resolving bindings, where null means the primary owner. Defaults to the primary owner.
Params:
  • owner – the owner of working copies that take precedence over underlying compilation units, or null if the primary owner should be used
/** * Sets the working copy owner used when resolving bindings, where * <code>null</code> means the primary owner. Defaults to the primary owner. * * @param owner the owner of working copies that take precedence over underlying * compilation units, or <code>null</code> if the primary owner should be used */
public void setWorkingCopyOwner(WorkingCopyOwner owner) { if (owner == null) { this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY; } else { this.workingCopyOwner = owner; } }
Sets the name of the compilation unit that would hypothetically contains the source string.

This is used in conjunction with setSource(char[]) and setProject(IJavaProject) to locate the compilation unit relative to a Java project. Defaults to none (null).

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 Java-like extensions and match the name of the main (public) class or interface declared in the source.

For compilation of a module-info.java file (since Java 9), the name of the compilation unit must be supplied. Otherwise, module-info.java will be compiled as an ordinary Java file resulting in compilation errors.

This name must represent the full path of the unit inside the given project. For example, if the source declares a public class named "Foo" in a project "P" where the source folder is the project itself, the name of the compilation unit must be "/P/Foo.java". If the source declares a public class name "Bar" in a package "p1.p2" in a project "P" in a source folder "src", the name of the compilation unit must be "/P/src/p1/p2/Bar.java".

This unit name is not used when the AST is built using createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor).

Params:
  • unitName – the name of the compilation unit that would contain the source string, or null if none
/** * Sets the name of the compilation unit that would hypothetically contains the * source string. * * <p>This is used in conjunction with {@link #setSource(char[])} * and {@link #setProject(IJavaProject)} to locate the compilation unit relative to a Java project. * Defaults to none (<code>null</code>).</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.</p> * * <p> * For compilation of a module-info.java file (since Java 9), the name of the compilation unit must be supplied. * Otherwise, module-info.java will be compiled as an ordinary Java file resulting in compilation errors.</p> * * <p>This name must represent the full path of the unit inside the given project. For example, if the source * declares a public class named "Foo" in a project "P" where the source folder is the project itself, the name * of the compilation unit must be "/P/Foo.java". * If the source declares a public class name "Bar" in a package "p1.p2" in a project "P" in a source folder "src", * the name of the compilation unit must be "/P/src/p1/p2/Bar.java".</p> * * <p>This unit name is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.</p> * * @param unitName the name of the compilation unit that would contain the source * string, or <code>null</code> if none */
public void setUnitName(String unitName) { this.unitName = unitName; }
Sets the Java project used when resolving bindings.

This method automatically sets the compiler options based on the given project:

setCompilerOptions(project.getOptions(true));

See setCompilerOptions(Map<String,String>) for a discussion of the pros and cons of using these options vs specifying compiler options explicitly.

This setting is used in conjunction with setSource(char[]). For the purposes of resolving bindings, types declared in the source string will hide types by the same name available through the classpath of the given project.

Defaults to none (null).

Params:
  • project – the Java project used to resolve names, or null if none
/** * Sets the Java project used when resolving bindings. * * <p>This method automatically sets the compiler * options based on the given project:</p> * <pre> * setCompilerOptions(project.getOptions(true)); * </pre> * <p>See {@link #setCompilerOptions(Map)} for a discussion of * the pros and cons of using these options vs specifying * compiler options explicitly.</p> * <p>This setting is used in conjunction with {@link #setSource(char[])}. * For the purposes of resolving bindings, types declared in the * source string will hide types by the same name available * through the classpath of the given project.</p> * <p>Defaults to none (<code>null</code>).</p> * * @param project the Java project used to resolve names, or * <code>null</code> if none */
public void setProject(IJavaProject project) { this.project = project; if (project != null) { Map<String, String> options = project.getOptions(true); options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags this.compilerOptions = options; } }
Creates an abstract syntax tree.

A successful call to this method returns all settings to their default values so the object is ready to be reused.

For identifying a module-info.java file as a special file instead of an ordinary Java file (Since Java 9), a call to this should be preceded by a call to setUnitName(String) that sets the unit name as module-info.java

Params:
  • monitor – the progress monitor used to report progress and request cancellation, or null if none
Throws:
  • IllegalStateException – if the settings provided are insufficient, contradictory, or otherwise unsupported
Returns:an AST node whose type depends on the kind of parse requested, with a fallback to a CompilationUnit in the case of severe parsing errors
/** * Creates an abstract syntax tree. * <p> * A successful call to this method returns all settings to their * default values so the object is ready to be reused. * </p> * <p>For identifying a module-info.java file as a special file instead of an ordinary * Java file (Since Java 9), a call to this should be preceded by a call to * {@link #setUnitName(String)} that sets the unit name as module-info.java</p> * * @param monitor the progress monitor used to report progress and request cancellation, * or <code>null</code> if none * @return an AST node whose type depends on the kind of parse * requested, with a fallback to a <code>CompilationUnit</code> * in the case of severe parsing errors * @exception IllegalStateException if the settings provided * are insufficient, contradictory, or otherwise unsupported */
public ASTNode createAST(IProgressMonitor monitor) { SubMonitor subMonitor = SubMonitor.convert(monitor, 1); ASTNode result = null; try { if (this.rawSource == null && this.typeRoot == null) { throw new IllegalStateException("source not specified"); //$NON-NLS-1$ } result = internalCreateAST(subMonitor.split(1)); } finally { // reset to defaults to allow reuse (and avoid leaking) initializeDefaults(); } return result; }
Creates ASTs for a batch of compilation units.

When bindings are being resolved, processing a batch of compilation units is more efficient because much of the work involved in resolving bindings can be shared.

When bindings are being resolved, all compilation units must come from the same Java project, which must be set beforehand with setProject.

The compilation units are processed one at a time in no specified order. For each of the compilation units in turn,

Note only ASTs from the given compilation units are reported to the requestor. If additional compilation units are required to resolve the original ones, the corresponding ASTs are not reported to the requestor.

Note also the following parser parameters are used, regardless of what may have been specified:

The bindingKeys parameter specifies bindings keys (IBinding.getKey()) that are to be looked up. These keys may be for elements either inside or outside the set of compilation units being processed. When bindings are being resolved, the keys and corresponding bindings (or null if none) are passed to ASTRequestor.acceptBinding. Note that binding keys for elements outside the set of compilation units being processed are looked up after all ASTRequestor.acceptAST callbacks have been made. Binding keys for elements inside the set of compilation units being processed are looked up and reported right after the corresponding ASTRequestor.acceptAST callback has been made. No ASTRequestor.acceptBinding callbacks are made unless bindings are being resolved.

A successful call to this method returns all settings to their default values so the object is ready to be reused.

Params:
  • compilationUnits – the compilation units to create ASTs for
  • bindingKeys – the binding keys to create bindings for
  • requestor – the AST requestor that collects abstract syntax trees and bindings
  • monitor – the progress monitor used to report progress and request cancellation, or null if none
Throws:
  • IllegalStateException – if the settings provided are insufficient, contradictory, or otherwise unsupported
Since:3.1
/** * Creates ASTs for a batch of compilation units. * <p>When bindings are being resolved, processing a * batch of compilation units is more efficient because much * of the work involved in resolving bindings can be shared.</p> * <p> * When bindings are being resolved, all compilation units must * come from the same Java project, which must be set beforehand * with {@link #setProject(IJavaProject) setProject}.</p> * <p>The compilation units are processed one at a time in no * specified order. For each of the compilation units in turn,</p> * <ul> * <li>{@link #createAST(IProgressMonitor) ASTParser.createAST} is called to parse it * and create a corresponding AST. The calls to * {@link #createAST(IProgressMonitor) ASTParser.createAST} all employ the same settings.</li> * <li>{@link ASTRequestor#acceptAST(ICompilationUnit, CompilationUnit) ASTRequestor.acceptAST} * is called passing the compilation unit and the corresponding AST to <code>requestor</code>. * </li> * </ul> * <p> * Note only ASTs from the given compilation units are reported * to the requestor. If additional compilation units are required to * resolve the original ones, the corresponding ASTs are <b>not</b> * reported to the requestor. * </p> * <p> * Note also the following parser parameters are used, regardless of what * may have been specified: * <ul> * <li>The {@linkplain #setKind(int) parser kind} is <code>K_COMPILATION_UNIT</code></li> * <li>The {@linkplain #setSourceRange(int,int) source range} is <code>(0, -1)</code></li> * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li> * </ul> * <p> * The <code>bindingKeys</code> parameter specifies bindings keys * ({@link IBinding#getKey()}) that are to be looked up. These keys may * be for elements either inside or outside the set of compilation * units being processed. When bindings are being resolved, * the keys and corresponding bindings (or <code>null</code> if none) are * passed to {@link ASTRequestor#acceptBinding(String, IBinding) ASTRequestor.acceptBinding}. * Note that binding keys for elements outside the set of compilation units being processed * are looked up after all {@link ASTRequestor#acceptAST(ICompilationUnit, CompilationUnit) ASTRequestor.acceptAST} * callbacks have been made. * Binding keys for elements inside the set of compilation units being processed * are looked up and reported right after the corresponding * {@link ASTRequestor#acceptAST(ICompilationUnit, CompilationUnit) ASTRequestor.acceptAST} callback has been made. * No {@link ASTRequestor#acceptBinding(String, IBinding) ASTRequestor.acceptBinding} callbacks are made unless * bindings are being resolved. * </p> * <p> * A successful call to this method returns all settings to their * default values so the object is ready to be reused. * </p> * * @param compilationUnits the compilation units to create ASTs for * @param bindingKeys the binding keys to create bindings for * @param requestor the AST requestor that collects abstract syntax trees and bindings * @param monitor the progress monitor used to report progress and request cancellation, * or <code>null</code> if none * @exception IllegalStateException if the settings provided * are insufficient, contradictory, or otherwise unsupported * @since 3.1 */
public void createASTs(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor requestor, IProgressMonitor monitor) { try { int flags = 0; if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; } if ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0) { flags |= ICompilationUnit.IGNORE_METHOD_BODIES; } if ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0) { if (this.project == null) throw new IllegalStateException("project not specified"); //$NON-NLS-1$ if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) { flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; } CompilationUnitResolver.resolve(compilationUnits, bindingKeys, requestor, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, flags, monitor); } else { CompilationUnitResolver.parse(compilationUnits, requestor, this.apiLevel, this.compilerOptions, flags, monitor); } } finally { // reset to defaults to allow reuse (and avoid leaking) initializeDefaults(); } }
Creates ASTs for a batch of compilation units. When bindings are being resolved, processing a batch of compilation units is more efficient because much of the work involved in resolving bindings can be shared.

When bindings are being resolved, all compilation units are resolved using the same environment, which must be set beforehand with setEnvironment. The compilation units are processed one at a time in no specified order. For each of the compilation units in turn,

  • ASTParser.createAST is called to parse it and create a corresponding AST. The calls to ASTParser.createAST all employ the same settings.
  • FileASTRequestor.acceptAST is called passing the compilation unit path and the corresponding AST to requestor. The compilation unit path is the same path that is passed into the given sourceFilePaths parameter.

Note only ASTs from the given compilation units are reported to the requestor. If additional compilation units are required to resolve the original ones, the corresponding ASTs are not reported to the requestor.

Note also the following parser parameters are used, regardless of what may have been specified:

The bindingKeys parameter specifies bindings keys (IBinding.getKey()) that are to be looked up. These keys may be for elements either inside or outside the set of compilation units being processed. When bindings are being resolved, the keys and corresponding bindings (or null if none) are passed to FileASTRequestor.acceptBinding. Note that binding keys for elements outside the set of compilation units being processed are looked up after all ASTRequestor.acceptAST callbacks have been made. Binding keys for elements inside the set of compilation units being processed are looked up and reported right after the corresponding FileASTRequestor.acceptAST callback has been made. No FileASTRequestor.acceptBinding callbacks are made unless bindings are being resolved.

A successful call to this method returns all settings to their default values so the object is ready to be reused.

The given encodings are used to properly parse the given source units. If the platform encoding is sufficient, then the given encodings can be set to null.

Params:
  • sourceFilePaths – the compilation units to create ASTs for
  • encodings – the given encoding for the source units
  • bindingKeys – the binding keys to create bindings for
  • requestor – the AST requestor that collects abstract syntax trees and bindings
  • monitor – the progress monitor used to report progress and request cancellation, or null if none
Throws:
  • IllegalStateException – if the settings provided are insufficient, contradictory, or otherwise unsupported
Since:3.6
/** * Creates ASTs for a batch of compilation units. * When bindings are being resolved, processing a * batch of compilation units is more efficient because much * of the work involved in resolving bindings can be shared. * <p> * When bindings are being resolved, all compilation units are resolved using * the same environment, which must be set beforehand * with {@link #setEnvironment(String[], String[], String[], boolean) setEnvironment}. * The compilation units are processed one at a time in no * specified order. For each of the compilation units in turn, * <ul> * <li>{@link ASTParser#createAST(IProgressMonitor) ASTParser.createAST} is called to parse it * and create a corresponding AST. The calls to * {@link ASTParser#createAST(IProgressMonitor) ASTParser.createAST} all employ the same settings.</li> * <li>{@link FileASTRequestor#acceptAST(String, CompilationUnit) FileASTRequestor.acceptAST} is called passing * the compilation unit path and the corresponding AST to <code>requestor</code>. The compilation unit path is the same * path that is passed into the given <code>sourceFilePaths</code> parameter. * </li> * </ul> * <p> * Note only ASTs from the given compilation units are reported * to the requestor. If additional compilation units are required to * resolve the original ones, the corresponding ASTs are <b>not</b> * reported to the requestor. * </p> * <p> * Note also the following parser parameters are used, regardless of what * may have been specified: * </p> * <ul> * <li>The {@linkplain #setKind(int) parser kind} is <code>K_COMPILATION_UNIT</code></li> * <li>The {@linkplain #setSourceRange(int,int) source range} is <code>(0, -1)</code></li> * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li> * </ul> * <p> * The <code>bindingKeys</code> parameter specifies bindings keys * ({@link IBinding#getKey()}) that are to be looked up. These keys may * be for elements either inside or outside the set of compilation * units being processed. When bindings are being resolved, * the keys and corresponding bindings (or <code>null</code> if none) are * passed to {@link FileASTRequestor#acceptBinding(String, IBinding) FileASTRequestor.acceptBinding}. Note that binding keys * for elements outside the set of compilation units being processed are looked up * after all {@link FileASTRequestor#acceptAST(String, CompilationUnit) ASTRequestor.acceptAST} * callbacks have been made. * Binding keys for elements inside the set of compilation units being processed * are looked up and reported right after the corresponding * {@link FileASTRequestor#acceptAST(String, CompilationUnit) FileASTRequestor.acceptAST} callback has been made. * No {@link FileASTRequestor#acceptBinding(String, IBinding) FileASTRequestor.acceptBinding} callbacks are made unless * bindings are being resolved. * </p> * <p> * A successful call to this method returns all settings to their * default values so the object is ready to be reused. * </p> * <p>The given <code>encodings</code> are used to properly parse the given source units. If the platform encoding is sufficient, * then the given encodings can be set to <code>null</code>.</p> * * @param sourceFilePaths the compilation units to create ASTs for * @param encodings the given encoding for the source units * @param bindingKeys the binding keys to create bindings for * @param requestor the AST requestor that collects abstract syntax trees and bindings * @param monitor the progress monitor used to report progress and request cancellation, * or <code>null</code> if none * @exception IllegalStateException if the settings provided * are insufficient, contradictory, or otherwise unsupported * @since 3.6 */
public void createASTs(String[] sourceFilePaths, String[] encodings, String[] bindingKeys, FileASTRequestor requestor, IProgressMonitor monitor) { try { int flags = 0; if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; } if ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0) { flags |= ICompilationUnit.IGNORE_METHOD_BODIES; } if ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0) { if (this.classpaths == null && this.sourcepaths == null && ((this.bits & CompilationUnitResolver.INCLUDE_RUNNING_VM_BOOTCLASSPATH) == 0)) { throw new IllegalStateException("no environment is specified"); //$NON-NLS-1$ } if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) { flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; } CompilationUnitResolver.resolve(sourceFilePaths, encodings, bindingKeys, requestor, this.apiLevel, this.compilerOptions, getClasspath(), flags, monitor); } else { CompilationUnitResolver.parse(sourceFilePaths, encodings, requestor, this.apiLevel, this.compilerOptions, flags, monitor); } } finally { // reset to defaults to allow reuse (and avoid leaking) initializeDefaults(); } }
Creates bindings for a batch of Java elements.

These elements are either enclosed in ICompilationUnits or in IClassFiles.

All enclosing compilation units and class files must come from the same Java project, which must be set beforehand with setProject.

All elements must exist. If one doesn't exist, an IllegalStateException is thrown.

The returned array has the same size as the given elements array. At a given position it contains the binding of the corresponding Java element, or null if no binding could be created.

Note also the following parser parameters are used, regardless of what may have been specified:

A successful call to this method returns all settings to their default values so the object is ready to be reused.

Params:
  • elements – the Java elements to create bindings for
Throws:
  • IllegalStateException – if the settings provided are insufficient, contradictory, or otherwise unsupported
Returns:the bindings for the given Java elements, possibly containing nulls if some bindings could not be created
Since:3.1
/** * Creates bindings for a batch of Java elements. * * <p>These elements are either * enclosed in {@link ICompilationUnit ICompilationUnits} or in {@link IClassFile IClassFiles}.</p> * <p> * All enclosing compilation units and class files must * come from the same Java project, which must be set beforehand * with {@link #setProject(IJavaProject) setProject}. * </p> * <p> * All elements must exist. If one doesn't exist, an {@link IllegalStateException} * is thrown. * </p> * <p> * The returned array has the same size as the given elements array. At a given position * it contains the binding of the corresponding Java element, or <code>null</code> * if no binding could be created. * </p> * <p> * Note also the following parser parameters are used, regardless of what * may have been specified: * <ul> * <li>The {@linkplain #setResolveBindings(boolean) binding resolution flag} is <code>true</code></li> * <li>The {@linkplain #setKind(int) parser kind} is <code>K_COMPILATION_UNIT</code></li> * <li>The {@linkplain #setSourceRange(int,int) source range} is <code>(0, -1)</code></li> * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li> * </ul> * <p> * A successful call to this method returns all settings to their * default values so the object is ready to be reused. * </p> * * @param elements the Java elements to create bindings for * @return the bindings for the given Java elements, possibly containing <code>null</code>s * if some bindings could not be created * @exception IllegalStateException if the settings provided * are insufficient, contradictory, or otherwise unsupported * @since 3.1 */
public IBinding[] createBindings(IJavaElement[] elements, IProgressMonitor monitor) { try { if (this.project == null) throw new IllegalStateException("project or classpath not specified"); //$NON-NLS-1$ int flags = 0; if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; } if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) { flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; } if ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0) { flags |= ICompilationUnit.IGNORE_METHOD_BODIES; } return CompilationUnitResolver.resolve(elements, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, flags, monitor); } finally { // reset to defaults to allow reuse (and avoid leaking) initializeDefaults(); } } private ASTNode internalCreateAST(IProgressMonitor monitor) { boolean needToResolveBindings = (this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0; switch(this.astKind) { case K_CLASS_BODY_DECLARATIONS : case K_EXPRESSION : case K_STATEMENTS : if (this.rawSource == null) { if (this.typeRoot != null) { // get the source from the type root if (this.typeRoot instanceof ICompilationUnit) { org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) this.typeRoot; this.rawSource = sourceUnit.getContents(); } else if (this.typeRoot instanceof IClassFile) { try { String sourceString = this.typeRoot.getSource(); if (sourceString != null) { this.rawSource = sourceString.toCharArray(); } } catch(JavaModelException e) { // an error occured accessing the java element StringWriter stringWriter = new StringWriter(); PrintWriter writer = null; try { writer = new PrintWriter(stringWriter); e.printStackTrace(writer); } finally { if (writer != null) writer.close(); } throw new IllegalStateException(String.valueOf(stringWriter.getBuffer())); } } } } if (this.rawSource != null) { if (this.sourceOffset + this.sourceLength > this.rawSource.length) { throw new IllegalStateException(); } return internalCreateASTForKind(); } break; case K_COMPILATION_UNIT : CompilationUnitDeclaration compilationUnitDeclaration = null; try { NodeSearcher searcher = null; org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = null; WorkingCopyOwner wcOwner = this.workingCopyOwner; if (this.typeRoot instanceof ClassFileWorkingCopy) { // special case: class file mimics as compilation unit, but that would use a wrong file name below, so better unwrap now: this.typeRoot = ((ClassFileWorkingCopy) this.typeRoot).classFile; } if (this.typeRoot instanceof ICompilationUnit) { /* * this.compilationUnitSource is an instance of org.eclipse.jdt.internal.core.CompilationUnit that implements * both org.eclipse.jdt.core.ICompilationUnit and org.eclipse.jdt.internal.compiler.env.ICompilationUnit */ sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) this.typeRoot; /* * use a BasicCompilation that caches the source instead of using the compilationUnitSource directly * (if it is a working copy, the source can change between the parse and the AST convertion) * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=75632) */ sourceUnit = new BasicCompilationUnit(sourceUnit.getContents(), sourceUnit.getPackageName(), new String(sourceUnit.getFileName()), this.project); wcOwner = ((ICompilationUnit) this.typeRoot).getOwner(); } else if (this.typeRoot instanceof IClassFile) { try { String sourceString = this.typeRoot.getSource(); if (sourceString == null) { throw new IllegalStateException(); } PackageFragment packageFragment = (PackageFragment) this.typeRoot.getParent(); BinaryType type = (BinaryType) this.typeRoot.findPrimaryType(); String fileNameString = null; if (type != null) { IBinaryType binaryType = (IBinaryType) type.getElementInfo(); // file name is used to recreate the Java element, so it has to be the toplevel .class file name char[] fileName = binaryType.getFileName(); int firstDollar = CharOperation.indexOf('$', fileName); if (firstDollar != -1) { char[] suffix = SuffixConstants.SUFFIX_class; int suffixLength = suffix.length; char[] newFileName = new char[firstDollar + suffixLength]; System.arraycopy(fileName, 0, newFileName, 0, firstDollar); System.arraycopy(suffix, 0, newFileName, firstDollar, suffixLength); fileName = newFileName; } fileNameString = new String(fileName); } else { // assumed to be "module-info.class" (which has no type): fileNameString = this.typeRoot.getElementName(); } sourceUnit = new BasicCompilationUnit(sourceString.toCharArray(), Util.toCharArrays(packageFragment.names), fileNameString, this.typeRoot); } catch(JavaModelException e) { // an error occured accessing the java element StringWriter stringWriter = new StringWriter(); PrintWriter writer = null; try { writer = new PrintWriter(stringWriter); e.printStackTrace(writer); } finally { if (writer != null) writer.close(); } throw new IllegalStateException(String.valueOf(stringWriter.getBuffer())); } } else if (this.rawSource != null) { needToResolveBindings = ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0) && this.unitName != null && (this.project != null || this.classpaths != null || this.sourcepaths != null || ((this.bits & CompilationUnitResolver.INCLUDE_RUNNING_VM_BOOTCLASSPATH) != 0)) && this.compilerOptions != null; sourceUnit = new BasicCompilationUnit(this.rawSource, null, this.unitName == null ? "" : this.unitName, this.project); //$NON-NLS-1$ } else { throw new IllegalStateException(); } if ((this.bits & CompilationUnitResolver.PARTIAL) != 0) { searcher = new NodeSearcher(this.focalPointPosition); } int flags = 0; if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; } if (searcher == null && ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0)) { flags |= ICompilationUnit.IGNORE_METHOD_BODIES; } if (needToResolveBindings) { if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) { flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; } try { // parse and resolve compilationUnitDeclaration = CompilationUnitResolver.resolve( sourceUnit, this.project, getClasspath(), searcher, this.compilerOptions, this.workingCopyOwner, flags, monitor); } catch (JavaModelException e) { flags &= ~ICompilationUnit.ENABLE_BINDINGS_RECOVERY; compilationUnitDeclaration = CompilationUnitResolver.parse( sourceUnit, searcher, this.compilerOptions, flags); needToResolveBindings = false; } } else { compilationUnitDeclaration = CompilationUnitResolver.parse( sourceUnit, searcher, this.compilerOptions, flags); needToResolveBindings = false; } CompilationUnit result = CompilationUnitResolver.convert( compilationUnitDeclaration, sourceUnit.getContents(), this.apiLevel, this.compilerOptions, needToResolveBindings, wcOwner, needToResolveBindings ? new DefaultBindingResolver.BindingTables() : null, flags, monitor, this.project != null); result.setTypeRoot(this.typeRoot); return result; } finally { if (compilationUnitDeclaration != null && ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0)) { compilationUnitDeclaration.cleanUp(); } } } throw new IllegalStateException(); }
Parses the given source between the bounds specified by the given offset (inclusive) and the given length and creates and returns a corresponding abstract syntax tree.

When the parse is successful the result returned includes the ASTs for the requested source:

The resulting AST node is rooted under an contrived CompilationUnit node, to allow the client to retrieve the following pieces of information available there:

The contrived nodes do not have source positions. Other aspects of the CompilationUnit node are unspecified, including the exact arrangment of intervening nodes.

Lexical or syntax errors detected while parsing can result in a result node being marked as MALFORMED. In more severe failure cases where the parser is unable to recognize the input, this method returns a CompilationUnit node with at least the compiler messages.

Each node in the subtree (other than the contrived nodes) carries source range(s) information relating back to positions in the given source (the given source 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 not included. The source range usually extends through the last character of the last token corresponding to the node; trailing whitespace and comments are not included. There are a handful of exceptions (including 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.

This method does not compute binding information; all resolveBinding methods applied to nodes of the resulting AST return null.

See Also:
Returns:an AST node whose type depends on the kind of parse requested, with a fallback to a CompilationUnit in the case of severe parsing errors
/** * Parses the given source between the bounds specified by the given offset (inclusive) * and the given length and creates and returns a corresponding abstract syntax tree. * <p> * When the parse is successful the result returned includes the ASTs for the * requested source: * <ul> * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result node * is a {@link TypeDeclaration TypeDeclaration} whose * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations} * are the new trees. Other aspects of the type declaration are unspecified.</li> * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a * {@link Block Block} whose {@link Block#statements() statements} * are the new trees. Other aspects of the block are unspecified.</li> * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of * {@link Expression Expression}. Other aspects of the expression are unspecified.</li> * </ul> * The resulting AST node is rooted under an contrived * {@link CompilationUnit CompilationUnit} node, to allow the * client to retrieve the following pieces of information * available there: * <ul> * <li>{@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line * numbers start at 1 and only cover the subrange scanned * (<code>source[offset]</code> through <code>source[offset+length-1]</code>).</li> * <li>{@linkplain CompilationUnit#getMessages() Compiler messages} * and {@linkplain CompilationUnit#getProblems() detailed problem reports}. * Character positions are relative to the start of * <code>source</code>; line positions are for the subrange scanned.</li> * <li>{@linkplain CompilationUnit#getCommentList() Comment list} * for the subrange scanned.</li> * </ul> * <p> * The contrived nodes do not have source positions. Other aspects of the * {@link CompilationUnit CompilationUnit} node are unspecified, including * the exact arrangment of intervening nodes. * </p> * <p> * Lexical or syntax errors detected while parsing can result in * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}. * In more severe failure cases where the parser is unable to * recognize the input, this method returns * a {@link CompilationUnit CompilationUnit} node with at least the * compiler messages. * </p> * <p>Each node in the subtree (other than the contrived nodes) * carries source range(s) information relating back * to positions in the given source (the given source 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 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. * </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> * * @return an AST node whose type depends on the kind of parse * requested, with a fallback to a <code>CompilationUnit</code> * in the case of severe parsing errors * @see ASTNode#getStartPosition() * @see ASTNode#getLength() */
private ASTNode internalCreateASTForKind() { final ASTConverter converter = new ASTConverter(this.compilerOptions, false, null); converter.compilationUnitSource = this.rawSource; converter.compilationUnitSourceLength = this.rawSource.length; converter.scanner.setSource(this.rawSource); AST ast = AST.newAST(this.apiLevel, JavaCore.ENABLED.equals(this.compilerOptions.get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES))); ast.setDefaultNodeFlag(ASTNode.ORIGINAL); ast.setBindingResolver(new BindingResolver()); if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { ast.setFlag(ICompilationUnit.ENABLE_STATEMENTS_RECOVERY); } ast.scanner.previewEnabled = JavaCore.ENABLED.equals(this.compilerOptions.get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES)); converter.setAST(ast); CodeSnippetParsingUtil codeSnippetParsingUtil = new CodeSnippetParsingUtil((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0); CompilationUnit compilationUnit = ast.newCompilationUnit(); if (this.sourceLength == -1) { this.sourceLength = this.rawSource.length; } switch(this.astKind) { case K_STATEMENTS : ConstructorDeclaration constructorDeclaration = codeSnippetParsingUtil.parseStatements( this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true, (this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0); RecoveryScannerData data = constructorDeclaration.compilationResult.recoveryScannerData; if(data != null) { Scanner scanner = converter.scanner; converter.scanner = new RecoveryScanner(scanner, data.removeUnused()); converter.docParser.scanner = converter.scanner; converter.scanner.setSource(scanner.source); compilationUnit.setStatementsRecoveryData(data); } RecordedParsingInformation recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation; int[][] comments = recordedParsingInformation.commentPositions; if (comments != null) { converter.buildCommentsTable(compilationUnit, comments); } compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); Block block = ast.newBlock(); block.setSourceRange(this.sourceOffset, this.sourceOffset + this.sourceLength); ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall; if (constructorCall != null && constructorCall.accessMode != org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall.ImplicitSuper) { block.statements().add(converter.convert(constructorCall)); } org.eclipse.jdt.internal.compiler.ast.Statement[] statements = constructorDeclaration.statements; if (statements != null) { int statementsLength = statements.length; for (int i = 0; i < statementsLength; i++) { if (statements[i] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) { converter.checkAndAddMultipleLocalDeclaration(statements, i, block.statements()); } else { Statement statement = converter.convert(statements[i]); if (statement != null) { block.statements().add(statement); } } } } rootNodeToCompilationUnit(ast, compilationUnit, block, recordedParsingInformation, data); ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); return block; case K_EXPRESSION : org.eclipse.jdt.internal.compiler.ast.Expression expression = codeSnippetParsingUtil.parseExpression(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true); recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation; comments = recordedParsingInformation.commentPositions; if (comments != null) { converter.buildCommentsTable(compilationUnit, comments); } compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); if (expression != null) { Expression expression2 = converter.convert(expression); rootNodeToCompilationUnit(expression2.getAST(), compilationUnit, expression2, codeSnippetParsingUtil.recordedParsingInformation, null); ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); return expression2; } else { CategorizedProblem[] problems = recordedParsingInformation.problems; if (problems != null) { compilationUnit.setProblems(problems); } ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); return compilationUnit; } case K_CLASS_BODY_DECLARATIONS : final org.eclipse.jdt.internal.compiler.ast.ASTNode[] nodes = codeSnippetParsingUtil.parseClassBodyDeclarations( this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true, (this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0); recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation; comments = recordedParsingInformation.commentPositions; if (comments != null) { converter.buildCommentsTable(compilationUnit, comments); } compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); if (nodes != null) { // source has no syntax error or the statement recovery is enabled TypeDeclaration typeDeclaration = converter.convert(nodes); typeDeclaration.setSourceRange(this.sourceOffset, this.sourceOffset + this.sourceLength); rootNodeToCompilationUnit(typeDeclaration.getAST(), compilationUnit, typeDeclaration, codeSnippetParsingUtil.recordedParsingInformation, null); ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); return typeDeclaration; } else { // source has syntax error and the statement recovery is disabled CategorizedProblem[] problems = recordedParsingInformation.problems; if (problems != null) { compilationUnit.setProblems(problems); } ast.setDefaultNodeFlag(0); ast.setOriginalModificationCount(ast.modificationCount()); return compilationUnit; } } throw new IllegalStateException(); } private void propagateErrors(ASTNode astNode, CategorizedProblem[] problems, RecoveryScannerData data) { astNode.accept(new ASTSyntaxErrorPropagator(problems)); if (data != null) { astNode.accept(new ASTRecoveryPropagator(problems, data)); } } private void rootNodeToCompilationUnit(AST ast, CompilationUnit compilationUnit, ASTNode node, RecordedParsingInformation recordedParsingInformation, RecoveryScannerData data) { final int problemsCount = recordedParsingInformation.problemsCount; switch(node.getNodeType()) { case ASTNode.BLOCK : { Block block = (Block) node; if (problemsCount != 0) { // propagate and record problems final CategorizedProblem[] problems = recordedParsingInformation.problems; propagateErrors(block, problems, data); compilationUnit.setProblems(problems); } TypeDeclaration typeDeclaration = ast.newTypeDeclaration(); Initializer initializer = ast.newInitializer(); initializer.setBody(block); typeDeclaration.bodyDeclarations().add(initializer); compilationUnit.types().add(typeDeclaration); } break; case ASTNode.TYPE_DECLARATION : { TypeDeclaration typeDeclaration = (TypeDeclaration) node; if (problemsCount != 0) { // propagate and record problems final CategorizedProblem[] problems = recordedParsingInformation.problems; propagateErrors(typeDeclaration, problems, data); compilationUnit.setProblems(problems); } compilationUnit.types().add(typeDeclaration); } break; default : if (node instanceof Expression) { Expression expression = (Expression) node; if (problemsCount != 0) { // propagate and record problems final CategorizedProblem[] problems = recordedParsingInformation.problems; propagateErrors(expression, problems, data); compilationUnit.setProblems(problems); } ExpressionStatement expressionStatement = ast.newExpressionStatement(expression); Block block = ast.newBlock(); block.statements().add(expressionStatement); Initializer initializer = ast.newInitializer(); initializer.setBody(block); TypeDeclaration typeDeclaration = ast.newTypeDeclaration(); typeDeclaration.bodyDeclarations().add(initializer); compilationUnit.types().add(typeDeclaration); } } } }