/*******************************************************************************
* Copyright (c) 2004, 2011 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ext.java.jdt.core.dom;
import org.eclipse.che.ide.ext.java.jdt.core.JavaCore;
import org.eclipse.che.ide.ext.java.jdt.core.compiler.CategorizedProblem;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.env.INameEnvironment;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.parser.RecoveryScanner;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.parser.RecoveryScannerData;
import org.eclipse.che.ide.ext.java.jdt.internal.compiler.parser.Scanner;
import org.eclipse.che.ide.ext.java.jdt.internal.core.BasicCompilationUnit;
import org.eclipse.che.ide.ext.java.jdt.internal.core.util.CodeSnippetParsingUtil;
import org.eclipse.che.ide.ext.java.jdt.internal.core.util.RecordedParsingInformation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* A Java language parser for creating abstract syntax trees (ASTs).
* <p>
* Example: Create basic AST from source string
* <p/>
* <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>
* </p>
*
* @noinstantiate This class is not intended to be instantiated by clients.
* @since 3.0
*/
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 LEVEL constants declared on <code>AST</code>
* @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 <code>partial</code> is <code>true</code>. */
private int focalPointPosition;
/** Source string. */
private char[] rawSource = 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 <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;
/** 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. */
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;
private INameEnvironment nameEnvironment;
/**
* 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 LEVEL constants declared on <code>AST</code>
*/
ASTParser(int level) {
switch (level) {
case AST.JLS2_INTERNAL:
case AST.JLS3:
case AST.JLS4:
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();
// //TODO find 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"); //$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.bits = 0;
this.sourceLength = -1;
this.sourceOffset = 0;
this.unitName = 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.
* <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 {@link IJavaProject} is available.
* <p/>
* <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;
}
}
/**
* @param nameEnvironment
* the nameEnvironment to set
*/
public void setNameEnvironment(INameEnvironment nameEnvironment) {
this.nameEnvironment = nameEnvironment;
}
/**
* 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 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.
* <p>
* Default 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 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 owner 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.
* <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/>
* <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.
* <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>
* 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:
* <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>
* 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/>
* <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.
* <p/>
* <p>
* This source is not used when the AST is built using
* {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)} .
* </p>
* <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;
}
// /**
// * 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.
// *
// * <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.
// *
// * <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 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 (<code>offset</code>
* 0 and <code>length</code> -1).
* <p/>
* <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
* <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.
* <p/>
* <p>
* When ignore method bodies is enabled, all method bodies are discarded. This has no impact on the binding resolution.
* </p>
* <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 name of the compilation unit that would hypothetically contains the source string.
* <p/>
* <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/>
* <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/>
* <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.
// *
// * <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 options = project.getOptions(true);
// options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags
// this.compilerOptions = options;
// }
// }
/**
* 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>
*
* @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
* @throws IllegalStateException
* if the settings provided are insufficient, contradictory, or otherwise unsupported
*/
public ASTNode createAST() {
ASTNode result = null;
try {
if (this.rawSource == null) {
throw new IllegalStateException("source not specified"); //$NON-NLS-1$
}
result = internalCreateAST();
} finally {
// reset to defaults to allow reuse (and avoid leaking)
initializeDefaults();
}
return result;
}
// /**
// * 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>
// * 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>
// * <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, 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.
// * <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>
// * 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>
// * <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.
// *
// * <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>
// * <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, flags,
// monitor);
// }
// finally
// {
// // reset to defaults to allow reuse (and avoid leaking)
// initializeDefaults();
// }
// }
private ASTNode internalCreateAST() {
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.che.ide.ext.java.jdt.internal.compiler.env.ICompilationUnit sourceUnit = null;
if (this.rawSource != null) {
needToResolveBindings = ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0);
sourceUnit =
new BasicCompilationUnit(this.rawSource, null, this.unitName == null ? "" : this.unitName); //$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 |= CompilationUnitResolver.ENABLE_STATEMENTS_RECOVERY;
}
if (searcher == null && ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0)) {
flags |= CompilationUnitResolver.IGNORE_METHOD_BODIES;
}
if (needToResolveBindings) {
if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) {
flags |= CompilationUnitResolver.ENABLE_BINDINGS_RECOVERY;
}
try {
// parse and resolve
compilationUnitDeclaration =
CompilationUnitResolver.resolve(sourceUnit, getClasspath(), searcher, this.compilerOptions,
flags, nameEnvironment);
} catch (Exception e) {
flags &= ~CompilationUnitResolver.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, needToResolveBindings
? new DefaultBindingResolver
.BindingTables()
: null, flags, false);
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.
* <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>
* 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);
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(CompilationUnitResolver.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);
org.eclipse.che.ide.ext.java.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.che.ide.ext.java.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.che.ide.ext.java.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.che.ide.ext.java.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);
}
}
}
/** @param string */
public void setSource(String string) {
this.rawSource = string.toCharArray();
}
}