All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jdt.core.dom.ASTParser Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2004, 2015 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
 *     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.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.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: *

    *
  • 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}.
  • *
  • Whether {@linkplain #setResolveBindings(boolean) bindings} will be created.
  • *
  • Which {@linkplain #setWorkingCopyOwner(WorkingCopyOwner) * working copy owner} to use when resolving bindings.
  • *
  • 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)
  • *
  • 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.
  • *
  • Whether to parse just {@linkplain #setKind(int) an expression, statements, * or body declarations} rather than an entire compilation unit.
  • *
  • Whether to return a {@linkplain #setFocalPosition(int) abridged AST} * focused on the declaration containing a given source position.
  • *
*

* * @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. */ public static final int K_EXPRESSION = 0x01; /** * 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. */ public static final int K_CLASS_BODY_DECLARATIONS = 0x04; /** * 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. * * @param level the API level; one of the .JLS* 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. */ private final int apiLevel; /** * Kind of parse requested. Defaults to an entire compilation unit. */ private int astKind; /** * Compiler options. Defaults to JavaCore.getOptions(). */ private Map compilerOptions; /** * The focal point for a partial AST request. * Only used when partial is true. */ private int focalPointPosition; /** * Source string. */ private char[] rawSource = null; /** * 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. */ 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. */ private int sourceLength = -1; /** * 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. */ private IJavaProject project = null; /** * Name of the compilation unit for resolving bindings, or * null if none. Defaults to none. */ private String unitName = null; /** * 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. */ private String[] sourcepaths; /** * Encoding of the given sourcepaths entries. */ private String[] sourcepathsEncodings; /** * 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. *

* * @param level the API level; one of the JLS* 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: break; default: throw new IllegalArgumentException(); } this.apiLevel = level; initializeDefaults(); } private List getClasspath() throws IllegalStateException { Main main = new Main(new PrintWriter(System.out), new PrintWriter(System.err), false/*systemExit*/, null/*options*/, null/*progress*/); ArrayList allClasspaths = new ArrayList(); 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"); //$NON-NLS-1$ } return allClasspaths; } /** * 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 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.

* * @param enabled true if incomplete bindings are expected, * and false 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 {@link 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.

* * @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 null if the platform encoding * can be used. * @param 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 */ 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 {@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. *

* * @param options the table of options (key type: String; * value type: String), or null * to set it back to the default */ public void setCompilerOptions(Map 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 {@link #setResolveBindings(boolean) 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 {@link #setResolveBindings(boolean) 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 {@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. *

* * @param enabled true if bindings are wanted, * and false 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 * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.

* * @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: *

    *
  • {@link #K_COMPILATION_UNIT K_COMPILATION_UNIT}: The result node * is a {@link CompilationUnit}.
  • *
  • {@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.
  • *
  • {@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.
  • *
  • {@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of * {@link Expression Expression}. Other aspects of the expression are unspecified.
  • *
* 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: *
    *
  • {@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line * numbers start at 1 and only cover the subrange scanned * (source[offset] through source[offset+length-1]).
  • *
  • {@linkplain CompilationUnit#getMessages() Compiler messages} * and {@linkplain CompilationUnit#getProblems() detailed problem reports}. * Character positions are relative to the start of * source; line positions are for the subrange scanned.
  • *
  • {@linkplain CompilationUnit#getCommentList() Comment list} * for the subrange scanned.
  • *
* 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. *

*

* 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. *

*

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 * {@link #K_COMPILATION_UNIT}. *

* *

This kind is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.

* * @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 * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.

* *

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}.

*

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

* * @param source the source string to be parsed, * or null 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 {@link #setProject(IJavaProject) setProject(source.getJavaProject())}.

* *

This source is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.

* * @param source the Java model compilation unit whose source code * is to be parsed, or null 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 {@link #setProject(IJavaProject) setProject(source.getJavaProject())}.

*

If the given class file has no source attachment, the creation of the * ast will fail with an {@link IllegalStateException}.

* *

This source is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.

* * @param source the Java model class file whose corresponding source code * is to be parsed, or null 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 {@link #setProject(IJavaProject) setProject(source.getJavaProject())}.

*

If the source is a class file without source attachment, the creation of the * ast will fail with an {@link IllegalStateException}.

* *

This source is not used when the AST is built using * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.

* * @param source the Java model compilation unit or class file whose corresponding source code * is to be parsed, or null 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 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 * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.

* * @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. *

* * @param enabled true if statements containing syntax errors are wanted, * and false 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 {@link #setKind(int)} is either * {@link #K_EXPRESSION} or {@link #K_STATEMENTS}.

* @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. * * @param owner the owner of working copies that take precedence over underlying * compilation units, or null 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 {@link #setSource(char[])} * and {@link #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 * {@link JavaCore#getJavaLikeExtensions() Java-like extensions} * and match the name of the main (public) class or interface declared in the source.

* *

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 * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}.

* * @param unitName the name of the compilation unit that would contain the source * string, or null 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 {@link #setCompilerOptions(Map)} for a discussion of * the pros and cons of using these options vs specifying * compiler options explicitly.

*

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.

*

Defaults to none (null).

* * @param project the Java project used to resolve names, or * null if none */ public void setProject(IJavaProject project) { this.project = project; if (project != null) { Map 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. *

* * @param monitor the progress monitor used to report progress and request cancellation, * or null if none * @return 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 * @exception IllegalStateException if the settings provided * are insufficient, contradictory, or otherwise unsupported */ public ASTNode createAST(IProgressMonitor monitor) { ASTNode result = null; if (monitor != null) monitor.beginTask("", 1); //$NON-NLS-1$ try { if (this.rawSource == null && this.typeRoot == null) { throw new IllegalStateException("source not specified"); //$NON-NLS-1$ } result = internalCreateAST(monitor); } finally { // reset to defaults to allow reuse (and avoid leaking) initializeDefaults(); if (monitor != null) monitor.done(); } 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 {@link #setProject(IJavaProject) setProject}.

*

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

*
    *
  • {@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.
  • *
  • {@link ASTRequestor#acceptAST(ICompilationUnit, CompilationUnit) ASTRequestor.acceptAST} * is called passing the compilation unit and the corresponding AST to requestor. *
  • *
* 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 {@linkplain #setKind(int) parser kind} is K_COMPILATION_UNIT
  • *
  • The {@linkplain #setSourceRange(int,int) source range} is (0, -1)
  • *
  • The {@linkplain #setFocalPosition(int) focal position} is not set
  • *
*

*

* The bindingKeys 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 null 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. *

*

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

* * @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 null 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 {@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, *

    *
  • {@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.
  • *
  • {@link FileASTRequestor#acceptAST(String, CompilationUnit) 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 {@linkplain #setKind(int) parser kind} is K_COMPILATION_UNIT
  • *
  • The {@linkplain #setSourceRange(int,int) source range} is (0, -1)
  • *
  • The {@linkplain #setFocalPosition(int) focal position} is not set
  • *
*

*

* The bindingKeys 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 null 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. *

*

* 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.

* * @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 null 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 {@link ICompilationUnit ICompilationUnits} or in {@link IClassFile IClassFiles}.

*

* All enclosing compilation units and class files must * come from the same Java project, which must be set beforehand * with {@link #setProject(IJavaProject) setProject}. *

*

* All elements must exist. If one doesn't exist, an {@link 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: *

    *
  • The {@linkplain #setResolveBindings(boolean) binding resolution flag} is true
  • *
  • The {@linkplain #setKind(int) parser kind} is K_COMPILATION_UNIT
  • *
  • The {@linkplain #setSourceRange(int,int) source range} is (0, -1)
  • *
  • The {@linkplain #setFocalPosition(int) focal position} is not set
  • *
*

*

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

* * @param elements the Java elements to create bindings for * @return the bindings for the given Java elements, possibly containing nulls * 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(); 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; } sourceUnit = new BasicCompilationUnit(sourceString.toCharArray(), Util.toCharArrays(packageFragment.names), new String(fileName), this.project); } 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: *

    *
  • {@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.
  • *
  • {@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.
  • *
  • {@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of * {@link Expression Expression}. Other aspects of the expression are unspecified.
  • *
* 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: *
    *
  • {@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line * numbers start at 1 and only cover the subrange scanned * (source[offset] through source[offset+length-1]).
  • *
  • {@linkplain CompilationUnit#getMessages() Compiler messages} * and {@linkplain CompilationUnit#getProblems() detailed problem reports}. * Character positions are relative to the start of * source; line positions are for the subrange scanned.
  • *
  • {@linkplain CompilationUnit#getCommentList() Comment list} * for the subrange scanned.
  • *
* 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. *

*

* 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. *

*

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. *

* * @return 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 * @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); ast.setDefaultNodeFlag(ASTNode.ORIGINAL); ast.setBindingResolver(new BindingResolver()); if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { ast.setFlag(ICompilationUnit.ENABLE_STATEMENTS_RECOVERY); } 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); } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy