blob: ba294a69f9259094b27e0b674a0c41b1ae98c021 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.core.dom;
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.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.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Statement;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
import org.eclipse.jdt.internal.core.util.RecordedParsingInformation;
/**
* A Java language parser for creating abstract syntax trees (ASTs).
* <p>
* Example: Create basic AST from source string
* <pre>
* char[] source = ...;
* ASTParser parser = ASTParser.newParser3(); // handles JLS3 (J2SE 1.5)
* parser.setSource(source);
* CompilationUnit result = (CompilationUnit) parser.createAST(null);
* </pre>
* Once a configured parser instance has been used to create an AST,
* the settings are automicatically returned 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 set 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.</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>
*
* @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>
*/
public static ASTParser newParser(int level) {
return new ASTParser(level);
}
/**
* Level of AST API desired.
*/
private final int API_LEVEL;
/**
* Kind of parse requested. Defaults to an entire compilation unit.
*/
private int astKind;
/**
* Compiler options. Defaults to JavaCore.getOptions().
*/
private Map compilerOptions;
/**
* Request for bindings. Defaults to <code>false</code>.
*/
private boolean resolveBindings;
/**
* Request for a partial AST. Defaults to <code>false</code>.
*/
private boolean partial = false;
/**
* 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;
/**
* Java mode compilation unit supplying the source.
*/
private ICompilationUnit compilationUnitSource = null;
/**
* Java model class file supplying the source.
*/
private IClassFile classFileSource = 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;
/**
* Working copy owner. Defaults to primary owner.
*/
private WorkingCopyOwner workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
/**
* Java project used to resolve names, or <code>null</code> if none.
* Defaults to none.
*/
private IJavaProject project = null;
/**
* Name of the compilation unit for resolving bindings, or
* <code>null</code> if none. Defaults to none.
*/
private String unitName = null;
/**
* 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) {
if ((level != AST.LEVEL_2_0)
&& (level != AST.LEVEL_3_0)) {
throw new IllegalArgumentException();
}
this.API_LEVEL = level;
initializeDefaults();
}
/**
* Sets all the setting to their default values.
*/
private void initializeDefaults() {
this.astKind = K_COMPILATION_UNIT;
this.rawSource = null;
this.classFileSource = null;
this.compilationUnitSource = null;
this.resolveBindings = false;
this.sourceLength = -1;
this.sourceOffset = 0;
this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
this.unitName = null;
this.project = null;
this.partial = false;
this.compilerOptions = JavaCore.getOptions();
}
/**
* Sets the compiler options to be used when parsing.
* <p>
* The compiler options default to {@link JavaCore#getOptions()}.
* </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) {
this.compilerOptions = JavaCore.getOptions();
}
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 <code>setResolveBindings(true)</code>, 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 <code>setResolveBindings(false)</code> (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>
* Binding information is obtained from the Java model.
* This means that the compilation unit must be located
* relative to the Java model via [TBD].
* 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 bindings <code>true</code> if bindings are wanted,
* and <code>false</code> if bindings are not of interest
*/
public void setResolveBindings(boolean bindings) {
this.resolveBindings = bindings;
}
/**
* Requests an abridged abstract syntax tree.
* By default, complete ASTs are returned.
*
* When <code>true</code> 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 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 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.
* </p>
*
* @param position a position into the corresponding body declaration
*/
public void setFocalPosition(int position) {
this.partial = true;
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}: The result node
* is a {@link CompilationUnit}.</li>
* <li>{@link #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}: 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}: 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#lineNumber(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#getCommentTable() Comment table}
* 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>
* Binding information is only computed when <code>kind</code> is
* <code>K_COMPILATION_UNIT</code>.
* </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.
*
* @param source the source string to be parsed,
* or <code>null</code> if none
*/
public void setSource(char[] source) {
this.rawSource = source;
// clear the others
this.compilationUnitSource = null;
this.classFileSource = null;
}
/**
* Sets the source code to be parsed.
*
* @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) {
this.compilationUnitSource = source;
// clear the others
this.rawSource = null;
this.classFileSource = null;
}
/**
* Sets the source code to be parsed.
*
* @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) {
this.classFileSource = source;
// clear the others
this.rawSource = null;
this.compilationUnitSource = null;
}
/**
* 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).
*
* @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
*/
public void setSourceRange(int offset, int length) {
if (offset < 0 || length < -1) {
throw new IllegalArgumentException();
}
this.sourceOffset = offset;
this.sourceLength = length;
}
/**
* Sets the working copy owner using when resolving bindings, where
* <code>null</code> means the primary owner. Defaults to the primary owner.
*
* @param owner the owner of working copies that take precedence over underlying
* compilation units, or <code>null</code> if the primary owner should be used
*/
public void setWorkingCopyOwner(WorkingCopyOwner owner) {
if (owner == null) {
this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
} else {
this.workingCopyOwner = owner;
}
}
/**
* Sets the name of the compilation unit that would hypothetically contains
* the source string. This is used in conjunction with
* <code>setSource(char[])</code> and <code>setProject</code> to locate the
* compilation unit relative to a Java project.
* Defaults to none (<code>null</code>).
* <p>
* The name of the compilation unit must be supplied for resolving bindings.
* This name should include the ".java" suffix and match the name of the main
* (public) class or interface declared in the source. For example, if the source
* declares a public class named "Foo", the name of the compilation should be
* "Foo.java".
* </p>
*
* @param unitName the name of the compilation unit that would contain the source
* string, or <code>null</code> if none
*/
public void setUnitName(String unitName) {
this.unitName = unitName;
}
/**
* Sets the Java project used when resolving bindings.
* This setting is used in conjunction with <code>setSource(char[])</code>;
* it is ignored if the source code comes from
* <code>setSource(ICompilationUnit)</code>
* or <code>setSource(IClassFile)</code>.
* 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 (<code>null</code>).
*
* @param project the Java project used to resolve names, or
* <code>null</code> if none
*/
public void setProject(IJavaProject project) {
this.project = project;
}
/**
* 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 cancelation,
* or <code>null</code> if none
* @return an AST node whose type depends on the kind of parse
* requested, with a fallback to a <code>CompilationUnit</code>
* in the case of severe parsing errors
* @exception IllegalStateException if the settings provided
* are insufficient, contradictory, or otherwise unsupported
*/
public ASTNode createAST(IProgressMonitor monitor) {
if ((this.rawSource == null)
&& (this.compilationUnitSource == null)
&& (this.classFileSource == null)) {
throw new IllegalStateException("source not specified"); //$NON-NLS-1$
}
ASTNode result;
if (this.API_LEVEL == AST.LEVEL_2_0) {
result = temporaryCreateASTDispatch(monitor);
} else {
throw new RuntimeException("J2SE 1.5 parser not implemented yet"); //$NON-NLS-1$
}
// if successful, re-init defaults to allow reuse (and avoid leaking)
initializeDefaults();
return result;
}
private ASTNode temporaryCreateASTDispatch(IProgressMonitor monitor) {
// old AST.parse(...)
if (this.astKind != K_COMPILATION_UNIT) {
return parse(this.astKind, this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions);
}
// old AST.parsePartialCompilationUnit(...)
if (this.partial) {
if (this.compilationUnitSource != null) {
return parsePartialCompilationUnit(this.compilationUnitSource, this.focalPointPosition, this.resolveBindings, this.workingCopyOwner, monitor);
}
if (this.classFileSource != null) {
return parsePartialCompilationUnit(this.classFileSource, this.focalPointPosition, this.resolveBindings, this.workingCopyOwner, monitor);
}
throw new RuntimeException("partial parses of raw sources not implemented yet"); //$NON-NLS-1$
}
// old AST.parseCompilationUnit(...)
if (this.rawSource != null) {
if (unitName != null || project != null) {
return parseCompilationUnit(this.rawSource, this.unitName, this.project, this.workingCopyOwner, monitor);
} else {
return parseCompilationUnit(this.rawSource, this.compilerOptions);
}
}
if (this.compilationUnitSource != null) {
return parseCompilationUnit(this.compilationUnitSource, this.resolveBindings, this.workingCopyOwner, monitor);
}
if (this.classFileSource != null) {
return parseCompilationUnit(this.classFileSource, this.resolveBindings, this.workingCopyOwner, monitor);
}
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#lineNumber(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#getCommentTable() Comment table}
* 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>
*
* @param kind the kind of construct to parse: one of
* {@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS},
* {@link #K_EXPRESSION K_EXPRESSION},
* {@link #K_STATEMENTS K_STATEMENTS}
* @param source the source to be parsed
* @param offset the index of the first byte to decode
* @param length the number of bytes to decode
* @param options the options; if null, <code>JavaCore.getOptions()</code> is used
* @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 IndexOutOfBoundsException
* if the <code>offset</code> and the <code>length</code>
* arguments index characters outside the bounds of
* <code>source</code>
* @see ASTNode#getStartPosition()
* @see ASTNode#getLength()
* @see JavaCore#getOptions()
*/
private static ASTNode parse(int kind, char[] source, int offset, int length, Map options) {
if (kind != K_CLASS_BODY_DECLARATIONS
&& kind != K_EXPRESSION
&& kind != K_STATEMENTS) {
throw new IllegalArgumentException();
}
if (source == null) {
throw new IllegalArgumentException();
}
if (length < 0 || offset < 0 || offset > source.length - length) {
throw new IndexOutOfBoundsException();
}
if (options == null) {
options = JavaCore.getOptions();
}
ASTConverter converter = new ASTConverter(options, false, null);
converter.compilationUnitSource = source;
converter.scanner.setSource(source);
AST ast = AST.newAST(AST.LEVEL_2_0);
ast.setBindingResolver(new BindingResolver());
converter.setAST(ast);
CodeSnippetParsingUtil codeSnippetParsingUtil = new CodeSnippetParsingUtil();
CompilationUnit compilationUnit = ast.newCompilationUnit();
switch(kind) {
case K_STATEMENTS :
ConstructorDeclaration constructorDeclaration = codeSnippetParsingUtil.parseStatements(source, offset, length, options, true);
RecordedParsingInformation recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation;
int[][] comments = recordedParsingInformation.commentPositions;
if (comments != null) {
converter.buildCommentsTable(compilationUnit, comments);
}
compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds);
if (constructorDeclaration != null) {
Block block = ast.newBlock();
Statement[] statements = constructorDeclaration.statements;
if (statements != null) {
int statementsLength = statements.length;
for (int i = 0; i < statementsLength; i++) {
block.statements().add(converter.convert(statements[i]));
}
}
rootNodeToCompilationUnit(ast, converter, compilationUnit, block, recordedParsingInformation);
return block;
} else {
IProblem[] problems = recordedParsingInformation.problems;
if (problems != null) {
compilationUnit.setProblems(problems);
}
return compilationUnit;
}
case K_EXPRESSION :
org.eclipse.jdt.internal.compiler.ast.Expression expression = codeSnippetParsingUtil.parseExpression(source, offset, length, options, 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(ast, converter, compilationUnit, expression2, codeSnippetParsingUtil.recordedParsingInformation);
return expression2;
} else {
IProblem[] problems = recordedParsingInformation.problems;
if (problems != null) {
compilationUnit.setProblems(problems);
}
return compilationUnit;
}
case K_CLASS_BODY_DECLARATIONS :
final org.eclipse.jdt.internal.compiler.ast.ASTNode[] nodes = codeSnippetParsingUtil.parseClassBodyDeclarations(source, offset, length, options, true);
recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation;
comments = recordedParsingInformation.commentPositions;
if (comments != null) {
converter.buildCommentsTable(compilationUnit, comments);
}
compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds);
if (nodes != null) {
TypeDeclaration typeDeclaration = converter.convert(nodes);
rootNodeToCompilationUnit(ast, converter, compilationUnit, typeDeclaration, codeSnippetParsingUtil.recordedParsingInformation);
return typeDeclaration;
} else {
IProblem[] problems = recordedParsingInformation.problems;
if (problems != null) {
compilationUnit.setProblems(problems);
}
return compilationUnit;
}
}
throw new IllegalArgumentException();
}
/**
* Parses the source string of the given Java model compilation unit element
* and creates and returns a corresponding abstract syntax tree. The source
* string is obtained from the Java model element using
* <code>ICompilationUnit.getSource()</code>.
* <p>
* The returned compilation unit node is the root node of a new AST.
* Each node in the subtree carries source range(s) information relating back
* to positions in the source string (the source string is not remembered
* with the AST).
* The source range usually begins at the first character of the first token
* corresponding to the node; leading whitespace and comments are <b>not</b>
* included. The source range usually extends through the last character of
* the last token corresponding to the node; trailing whitespace and
* comments are <b>not</b> included. There are a handful of exceptions
* (including compilation units and the various body declarations); the
* specification for these node type spells out the details.
* Source ranges nest properly: the source range for a child is always
* within the source range of its parent, and the source ranges of sibling
* nodes never overlap.
* If a syntax error is detected while parsing, the relevant node(s) of the
* tree will be flagged as <code>MALFORMED</code>.
* </p>
* <p>
* If <code>resolveBindings</code> is <code>true</code>, the various names
* and types appearing in the compilation unit can be resolved to "bindings"
* by calling the <code>resolveBinding</code> methods. These bindings
* draw connections between the different parts of a program, and
* generally afford a more powerful vantage point for clients who wish to
* analyze a program's structure more deeply. These bindings come at a
* considerable cost in both time and space, however, and should not be
* requested frivolously. The additional space is not reclaimed until the
* AST, all its nodes, and all its bindings become garbage. So it is very
* important to not retain any of these objects longer than absolutely
* necessary. Bindings are resolved at the time the AST is created. Subsequent
* modifications to the AST do not affect the bindings returned by
* <code>resolveBinding</code> methods in any way; these methods return the
* same binding as before the AST was modified (including modifications
* that rearrange subtrees by reparenting nodes).
* If <code>resolveBindings</code> is <code>false</code>, the analysis
* does not go beyond parsing and building the tree, and all
* <code>resolveBinding</code> methods return <code>null</code> from the
* outset.
* </p>
* <p>
* When bindings are created, 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 the compiler options that affect doc comment checking may also
* affect whether any bindings are resolved for nodes within doc comments.
* </p>
*
* @param unit the Java model compilation unit whose source code is to be parsed
* @param resolveBindings <code>true</code> if bindings are wanted,
* and <code>false</code> if bindings are not of interest
* @param owner the owner of working copies that take precedence over underlying
* compilation units, or <code>null</code> if the primary owner should be used
* @param monitor the progress monitor used to report progress and request cancelation,
* or <code>null</code> if none
* @return the compilation unit node
* @exception IllegalArgumentException if the given Java element does not
* exist or if its source string cannot be obtained
* @see ASTNode#getFlags()
* @see ASTNode#MALFORMED
* @see ASTNode#getStartPosition()
* @see ASTNode#getLength()
* @see WorkingCopyOwner
*/
private static CompilationUnit parseCompilationUnit(
ICompilationUnit unit,
boolean resolveBindings,
WorkingCopyOwner owner,
IProgressMonitor monitor) {
if (unit == null) {
throw new IllegalArgumentException();
}
if (owner == null) {
owner = DefaultWorkingCopyOwner.PRIMARY;
}
char[] source = null;
try {
source = unit.getSource().toCharArray();
} catch(JavaModelException e) {
// no source, then we cannot build anything
throw new IllegalArgumentException();
}
if (resolveBindings) {
CompilationUnitDeclaration compilationUnitDeclaration = null;
try {
// parse and resolve
compilationUnitDeclaration = CompilationUnitResolver.resolve(unit, false/*don't cleanup*/, source, owner, monitor);
ASTConverter converter = new ASTConverter(unit.getJavaProject().getOptions(true), true, monitor);
AST ast = AST.newAST(AST.LEVEL_2_0);
BindingResolver resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope);
ast.setBindingResolver(resolver);
converter.setAST(ast);
CompilationUnit cu = converter.convert(compilationUnitDeclaration, source);
cu.setLineEndTable(compilationUnitDeclaration.compilationResult.lineSeparatorPositions);
resolver.storeModificationCount(ast.modificationCount());
return cu;
} catch(JavaModelException e) {
/* if a JavaModelException is thrown trying to retrieve the name environment
* then we simply do a parsing without creating bindings.
* Therefore all binding resolution will return null.
*/
return parseCompilationUnit(source);
} finally {
if (compilationUnitDeclaration != null) {
compilationUnitDeclaration.cleanUp();
}
}
} else {
return parseCompilationUnit(source);
}
}
/**
* Parses the source string corresponding to the given Java class file
* element and creates and returns a corresponding abstract syntax tree.
* The source string is obtained from the Java model element using
* <code>IClassFile.getSource()</code>, and is only available for a class
* files with attached source.
* In all other respects, this method works the same as
* {@link #parseCompilationUnit(ICompilationUnit,boolean,WorkingCopyOwner,IProgressMonitor)
* parseCompilationUnit(ICompilationUnit,boolean,WorkingCopyOwner,IProgressMonitor)}.
* <p>
* 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 classFile the Java model class file whose corresponding source code is to be parsed
* @param resolveBindings <code>true</code> if bindings are wanted,
* and <code>false</code> if bindings are not of interest
* @param owner the owner of working copies that take precedence over underlying
* compilation units, or <code>null</code> if the primary owner should be used
* @param monitor the progress monitor used to report progress and request cancelation,
* or <code>null</code> if none
* @return the compilation unit node
* @exception IllegalArgumentException if the given Java element does not
* exist or if its source string cannot be obtained
* @see ASTNode#getFlags()
* @see ASTNode#MALFORMED
* @see ASTNode#getStartPosition()
* @see ASTNode#getLength()
* @see WorkingCopyOwner
*/
private static CompilationUnit parseCompilationUnit(
IClassFile classFile,
boolean resolveBindings,
WorkingCopyOwner owner,
IProgressMonitor monitor) {
if (classFile == null) {
throw new IllegalArgumentException();
}
if (owner == null) {
owner = DefaultWorkingCopyOwner.PRIMARY;
}
char[] source = null;
String sourceString = null;
try {
sourceString = classFile.getSource();
} catch (JavaModelException e) {
throw new IllegalArgumentException();
}
if (sourceString == null) {
throw new IllegalArgumentException();
}
source = sourceString.toCharArray();
if (!resolveBindings) {
return parseCompilationUnit(source);
}
StringBuffer buffer = new StringBuffer(SuffixConstants.SUFFIX_STRING_java);
String classFileName = classFile.getElementName(); // this includes the trailing .class
buffer.insert(0, classFileName.toCharArray(), 0, classFileName.indexOf('.'));
IJavaProject project = classFile.getJavaProject();
CompilationUnitDeclaration compilationUnitDeclaration = null;
try {
// parse and resolve
compilationUnitDeclaration =
CompilationUnitResolver.resolve(
source,
CharOperation.splitOn('.', classFile.getType().getPackageFragment().getElementName().toCharArray()),
buffer.toString(),
project,
null/*no node searcher*/,
false/*don't cleanup*/,
owner,
monitor);
ASTConverter converter = new ASTConverter(project.getOptions(true), true, monitor);
AST ast = AST.newAST(AST.LEVEL_2_0);
BindingResolver resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope);
ast.setBindingResolver(resolver);
converter.setAST(ast);
CompilationUnit cu = converter.convert(compilationUnitDeclaration, source);
cu.setLineEndTable(compilationUnitDeclaration.compilationResult.lineSeparatorPositions);
resolver.storeModificationCount(ast.modificationCount());
return cu;
} catch(JavaModelException e) {
/* if a JavaModelException is thrown trying to retrieve the name environment
* then we simply do a parsing without creating bindings.
* Therefore all binding resolution will return null.
*/
return parseCompilationUnit(source);
} finally {
if (compilationUnitDeclaration != null) {
compilationUnitDeclaration.cleanUp();
}
}
}
/**
* Parses the given string as the hypothetical contents of the named
* compilation unit and creates and returns a corresponding abstract syntax tree.
* <p>
* The returned compilation unit node is the root node of a new AST.
* Each node in the subtree carries source range(s) information relating back
* to positions in the given source string (the given source string itself
* is not remembered with the AST).
* The source range usually begins at the first character of the first token
* corresponding to the node; leading whitespace and comments are <b>not</b>
* included. The source range usually extends through the last character of
* the last token corresponding to the node; trailing whitespace and
* comments are <b>not</b> included. There are a handful of exceptions
* (including compilation units and the various body declarations); the
* specification for these node type spells out the details.
* Source ranges nest properly: the source range for a child is always
* within the source range of its parent, and the source ranges of sibling
* nodes never overlap.
* If a syntax error is detected while parsing, the relevant node(s) of the
* tree will be flagged as <code>MALFORMED</code>.
* </p>
* <p>
* If the given project is not <code>null</code>, the various names
* and types appearing in the compilation unit can be resolved to "bindings"
* by calling the <code>resolveBinding</code> methods. These bindings
* draw connections between the different parts of a program, and
* generally afford a more powerful vantage point for clients who wish to
* analyze a program's structure more deeply. These bindings come at a
* considerable cost in both time and space, however, and should not be
* requested frivolously. The additional space is not reclaimed until the
* AST, all its nodes, and all its bindings become garbage. So it is very
* important to not retain any of these objects longer than absolutely
* necessary. Bindings are resolved at the time the AST is created. Subsequent
* modifications to the AST do not affect the bindings returned by
* <code>resolveBinding</code> methods in any way; these methods return the
* same binding as before the AST was modified (including modifications
* that rearrange subtrees by reparenting nodes).
* If the given project is <code>null</code>, the analysis
* does not go beyond parsing and building the tree, and all
* <code>resolveBinding</code> methods return <code>null</code> from the
* outset.
* </p>
* <p>
* When bindings are created, 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>
* The name of the compilation unit must be supplied for resolving bindings.
* This name should include the ".java" suffix and match the name of the main
* (public) class or interface declared in the source. For example, if the source
* declares a public class named "Foo", the name of the compilation should be
* "Foo.java". For the purposes of resolving bindings, types declared in the
* source string hide types by the same name available through the classpath
* of the given project.
* </p>
*
* @param source the string to be parsed as a Java compilation unit
* @param unitName the name of the compilation unit that would contain the source
* string, or <code>null</code> if <code>javaProject</code> is also <code>null</code>
* @param project the Java project used to resolve names, or
* <code>null</code> if bindings are not resolved
* @param owner the owner of working copies that take precedence over underlying
* compilation units, or <code>null</code> if the primary owner should be used
* @param monitor the progress monitor used to report progress and request cancelation,
* or <code>null</code> if none
* @return the compilation unit node
* @see ASTNode#getFlags()
* @see ASTNode#MALFORMED
* @see ASTNode#getStartPosition()
* @see ASTNode#getLength()
* @see WorkingCopyOwner
*/
private static CompilationUnit parseCompilationUnit(
char[] source,
String unitName,
IJavaProject project,
WorkingCopyOwner owner,
IProgressMonitor monitor) {
if (source == null) {
throw new IllegalArgumentException();
}
if (unitName == null && project != null) {
throw new IllegalArgumentException();
}
if (project == null) {
// this just reduces to the other simplest case
return parseCompilationUnit(source);
}
if (owner == null) {
owner = DefaultWorkingCopyOwner.PRIMARY;
}
CompilationUnitDeclaration compilationUnitDeclaration = null;
try {
// parse and resolve
compilationUnitDeclaration =
CompilationUnitResolver.resolve(
source,
unitName,
project,
false/*don't cleanup*/,
owner,
monitor);
ASTConverter converter = new ASTConverter(project.getOptions(true), true, monitor);
AST ast = AST.newAST(AST.LEVEL_2_0);
BindingResolver resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope);
ast.setBindingResolver(resolver);
converter.setAST(ast);
CompilationUnit cu = converter.convert(compilationUnitDeclaration, source);
cu.setLineEndTable(compilationUnitDeclaration.compilationResult.lineSeparatorPositions);
resolver.storeModificationCount(ast.modificationCount());
return cu;
} catch(JavaModelException e) {
/* if a JavaModelException is thrown trying to retrieve the name environment
* then we simply do a parsing without creating bindings.
* Therefore all binding resolution will return null.
*/
return parseCompilationUnit(source);
} finally {
if (compilationUnitDeclaration != null) {
compilationUnitDeclaration.cleanUp();
}
}
}
/**
* Parses the given string as a Java compilation unit and creates and
* returns a corresponding abstract syntax tree.
* <p>
* The returned compilation unit node is the root node of a new AST.
* Each node in the subtree carries source range(s) information relating back
* to positions in the given source string (the given source string itself
* is not remembered with the AST).
* The source range usually begins at the first character of the first token
* corresponding to the node; leading whitespace and comments are <b>not</b>
* included. The source range usually extends through the last character of
* the last token corresponding to the node; trailing whitespace and
* comments are <b>not</b> included. There are a handful of exceptions
* (including compilation units and the various body declarations); the
* specification for these node type spells out the details.
* Source ranges nest properly: the source range for a child is always
* within the source range of its parent, and the source ranges of sibling
* nodes never overlap.
* If a syntax error is detected while parsing, the relevant node(s) of the
* tree will be flagged as <code>MALFORMED</code>.
* </p>
* <p>
* This method does not compute binding information; all <code>resolveBinding</code>
* methods applied to nodes of the resulting AST return <code>null</code>.
* </p>
*
* @param source the string to be parsed as a Java compilation unit
* @return the compilation unit node
* @see ASTNode#getFlags()
* @see ASTNode#MALFORMED
* @see ASTNode#getStartPosition()
* @see ASTNode#getLength()
*/
private static CompilationUnit parseCompilationUnit(char[] source) {
return parseCompilationUnit(source, null);
}
/**
* Parses the given string as a Java compilation unit and creates and
* returns a corresponding abstract syntax tree.
* <p>
* The given options are used to find out the compiler options to use while parsing.
* This could implies the settings for the assertion support. See the <code>JavaCore.getOptions()</code>
* methods for further details.
* </p>
* <p>
* The returned compilation unit node is the root node of a new AST.
* Each node in the subtree carries source range(s) information relating back
* to positions in the given source string (the given source string itself
* is not remembered with the AST).
* The source range usually begins at the first character of the first token
* corresponding to the node; leading whitespace and comments are <b>not</b>
* included. The source range usually extends through the last character of
* the last token corresponding to the node; trailing whitespace and
* comments are <b>not</b> included. There are a handful of exceptions
* (including compilation units and the various body declarations); the
* specification for these node type spells out the details.
* Source ranges nest properly: the source range for a child is always
* within the source range of its parent, and the source ranges of sibling
* nodes never overlap.
* If a syntax error is detected while parsing, the relevant node(s) of the
* tree will be flagged as <code>MALFORMED</code>.
* </p>
* <p>
* This method does not compute binding information; all <code>resolveBinding</code>
* methods applied to nodes of the resulting AST return <code>null</code>.
* </p>
*
* @param source the string to be parsed as a Java compilation unit
* @param options options to use while parsing the file. If null, <code>JavaCore.getOptions()</code> is used.
* @return the compilation unit node
* @see ASTNode#getFlags()
* @see ASTNode#MALFORMED
* @see ASTNode#getStartPosition()
* @see ASTNode#getLength()
* @see JavaCore#getOptions()
*/
private static CompilationUnit parseCompilationUnit(char[] source, Map options) {
if (options == null) {
options = JavaCore.getOptions();
}
if (source == null) {
throw new IllegalArgumentException();
}
CompilationUnitDeclaration compilationUnitDeclaration =
CompilationUnitResolver.parse(source, options);
ASTConverter converter = new ASTConverter(options, false, null);
AST ast = AST.newAST(AST.LEVEL_2_0);
ast.setBindingResolver(new BindingResolver());
converter.setAST(ast);
CompilationUnit cu = converter.convert(compilationUnitDeclaration, source);
// line end table should be extracted from scanner
cu.setLineEndTable(compilationUnitDeclaration.compilationResult.lineSeparatorPositions);
return cu;
}
/**
* Parses the source string of the given Java model compilation unit element
* and creates and returns an abridged abstract syntax tree. This method
* differs from
* {@link #parseCompilationUnit(ICompilationUnit,boolean,WorkingCopyOwner)
* parseCompilationUnit(ICompilationUnit,boolean,WorkingCopyOwner)} only in
* that 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 faster to construct.
* </p>
* <p>
* The resulting AST always includes nodes for all of the compilation unit's
* package, import, and top-level type declarations. It also always contains
* 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 the given position is not located within
* the source range of any body declaration of a top-level type, the AST
* returned is 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>
* In all other respects, this method works the same as
* {@link #parseCompilationUnit(ICompilationUnit,boolean,WorkingCopyOwner)
* parseCompilationUnit(ICompilationUnit,boolean,WorkingCopyOwner)}.
* The source string is obtained from the Java model element using
* <code>ICompilationUnit.getSource()</code>.
* </p>
* <p>
* The returned compilation unit node is the root node of a new AST.
* Each node in the subtree carries source range(s) information relating back
* to positions in the source string (the source string is not remembered
* with the AST).
* The source range usually begins at the first character of the first token
* corresponding to the node; leading whitespace and comments are <b>not</b>
* included. The source range usually extends through the last character of
* the last token corresponding to the node; trailing whitespace and
* comments are <b>not</b> included.
* If a syntax error is detected while parsing, the relevant node(s) of the
* tree will be flagged as <code>MALFORMED</code>.
* </p>
* <p>
* If <code>resolveBindings</code> is <code>true</code>, the various names
* and types appearing in the method declaration can be resolved to "bindings"
* by calling the <code>resolveBinding</code> methods. These bindings
* draw connections between the different parts of a program, and
* generally afford a more powerful vantage point for clients who wish to
* analyze a program's structure more deeply. These bindings come at a
* considerable cost in both time and space, however, and should not be
* requested frivolously. The additional space is not reclaimed until the
* AST, all its nodes, and all its bindings become garbage. So it is very
* important to not retain any of these objects longer than absolutely
* necessary. Bindings are resolved at the time the AST is created. Subsequent
* modifications to the AST do not affect the bindings returned by
* <code>resolveBinding</code> methods in any way; these methods return the
* same binding as before the AST was modified (including modifications
* that rearrange subtrees by reparenting nodes).
* If <code>resolveBindings</code> is <code>false</code>, the analysis
* does not go beyond parsing and building the tree, and all
* <code>resolveBinding</code> methods return <code>null</code> from the
* outset.
* </p>
* <p>
* When bindings are created, 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 the compiler options that affect doc comment checking may also
* affect whether any bindings are resolved for nodes within doc comments.
* </p>
*
* @param unit the Java model compilation unit whose source code is to be parsed
* @param position a position into the corresponding body declaration
* @param resolveBindings <code>true</code> if bindings are wanted,
* and <code>false</code> if bindings are not of interest
* @param owner the owner of working copies that take precedence over underlying
* compilation units, or <code>null</code> if the primary owner should be used
* @param monitor the progress monitor used to report progress and request cancelation,
* or <code>null</code> if none
* @return the abridged compilation unit node
* @exception IllegalArgumentException if the given Java element does not
* exist or the source range is null or if its source string cannot be obtained
* @see ASTNode#getFlags()
* @see ASTNode#MALFORMED
* @see ASTNode#getStartPosition()
* @see ASTNode#getLength()
*/
private static CompilationUnit parsePartialCompilationUnit(
ICompilationUnit unit,
int position,
boolean resolveBindings,
WorkingCopyOwner owner,
IProgressMonitor monitor) {
if (unit == null) {
throw new IllegalArgumentException();
}
if (owner == null) {
owner = DefaultWorkingCopyOwner.PRIMARY;
}
char[] source = null;
try {
source = unit.getSource().toCharArray();
} catch(JavaModelException e) {
// no source, then we cannot build anything
throw new IllegalArgumentException();
}
NodeSearcher searcher = new NodeSearcher(position);
final Map options = unit.getJavaProject().getOptions(true);
if (resolveBindings) {
CompilationUnitDeclaration compilationUnitDeclaration = null;
try {
// parse and resolve
compilationUnitDeclaration = CompilationUnitResolver.resolve(
unit,
searcher,
false/*don't cleanup*/,
source,
owner,
monitor);
ASTConverter converter = new ASTConverter(options, true, monitor);
AST ast = AST.newAST(AST.LEVEL_2_0);
BindingResolver resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope);
ast.setBindingResolver(resolver);
converter.setAST(ast);
CompilationUnit compilationUnit = converter.convert(compilationUnitDeclaration, source);
compilationUnit.setLineEndTable(compilationUnitDeclaration.compilationResult.lineSeparatorPositions);
resolver.storeModificationCount(ast.modificationCount());
return compilationUnit;
} catch(JavaModelException e) {
/* if a JavaModelException is thrown trying to retrieve the name environment
* then we simply do a parsing without creating bindings.
* Therefore all binding resolution will return null.
*/
CompilationUnitDeclaration compilationUnitDeclaration2 = CompilationUnitResolver.parse(
source,
searcher,
options);
ASTConverter converter = new ASTConverter(options, false, monitor);
AST ast = AST.newAST(AST.LEVEL_2_0);
final BindingResolver resolver = new BindingResolver();
ast.setBindingResolver(resolver);
converter.setAST(ast);
CompilationUnit compilationUnit = converter.convert(compilationUnitDeclaration2, source);
compilationUnit.setLineEndTable(compilationUnitDeclaration2.compilationResult.lineSeparatorPositions);
resolver.storeModificationCount(ast.modificationCount());
return compilationUnit;
} finally {
if (compilationUnitDeclaration != null) {
compilationUnitDeclaration.cleanUp();
}
}
} else {
CompilationUnitDeclaration compilationUnitDeclaration = CompilationUnitResolver.parse(
source,
searcher,
options);
ASTConverter converter = new ASTConverter(options, false, monitor);
AST ast = AST.newAST(AST.LEVEL_2_0);
final BindingResolver resolver = new BindingResolver();
ast.setBindingResolver(resolver);
converter.setAST(ast);
CompilationUnit compilationUnit = converter.convert(compilationUnitDeclaration, source);
compilationUnit.setLineEndTable(compilationUnitDeclaration.compilationResult.lineSeparatorPositions);
resolver.storeModificationCount(ast.modificationCount());
return compilationUnit;
}
}
/**
* Parses the source string corresponding to the given Java class file
* element and creates and returns a corresponding abstract syntax tree.
* The source string is obtained from the Java model element using
* <code>IClassFile.getSource()</code>, and is only available for a class
* files with attached source.
* In all other respects, this method works the same as
* {@link #parsePartialCompilationUnit(ICompilationUnit,int,boolean,WorkingCopyOwner,IProgressMonitor)
* parsePartialCompilationUnit(ICompilationUnit,int,boolean,WorkingCopyOwner,IProgressMonitor)}.
*
* @param classFile the Java model class file whose corresponding source code is to be parsed
* @param position a position into the corresponding body declaration
* @param resolveBindings <code>true</code> if bindings are wanted,
* and <code>false</code> if bindings are not of interest
* @param owner the owner of working copies that take precedence over underlying
* compilation units, or <code>null</code> if the primary owner should be used
* @param monitor the progress monitor used to report progress and request cancelation,
* or <code>null</code> if none
* @return the abridged compilation unit node
* @exception IllegalArgumentException if the given Java element does not
* exist or the source range is null or if its source string cannot be obtained
* @see ASTNode#getFlags()
* @see ASTNode#MALFORMED
* @see ASTNode#getStartPosition()
* @see ASTNode#getLength()
*/
private static CompilationUnit parsePartialCompilationUnit(
IClassFile classFile,
int position,
boolean resolveBindings,
WorkingCopyOwner owner,
IProgressMonitor monitor) {
if (classFile == null) {
throw new IllegalArgumentException();
}
if (owner == null) {
owner = DefaultWorkingCopyOwner.PRIMARY;
}
char[] source = null;
String sourceString = null;
try {
sourceString = classFile.getSource();
} catch (JavaModelException e) {
throw new IllegalArgumentException();
}
if (sourceString == null) {
throw new IllegalArgumentException();
}
source = sourceString.toCharArray();
NodeSearcher searcher = new NodeSearcher(position);
final Map options = classFile.getJavaProject().getOptions(true);
if (resolveBindings) {
CompilationUnitDeclaration compilationUnitDeclaration = null;
try {
// parse and resolve
compilationUnitDeclaration = CompilationUnitResolver.resolve(
classFile,
searcher,
false/*don't cleanup*/,
source,
owner,
monitor);
ASTConverter converter = new ASTConverter(options, true, monitor);
AST ast = AST.newAST(AST.LEVEL_2_0);
BindingResolver resolver = new DefaultBindingResolver(compilationUnitDeclaration.scope);
ast.setBindingResolver(resolver);
converter.setAST(ast);
CompilationUnit compilationUnit = converter.convert(compilationUnitDeclaration, source);
compilationUnit.setLineEndTable(compilationUnitDeclaration.compilationResult.lineSeparatorPositions);
resolver.storeModificationCount(ast.modificationCount());
return compilationUnit;
} catch(JavaModelException e) {
/* if a JavaModelException is thrown trying to retrieve the name environment
* then we simply do a parsing without creating bindings.
* Therefore all binding resolution will return null.
*/
CompilationUnitDeclaration compilationUnitDeclaration2 = CompilationUnitResolver.parse(
source,
searcher,
options);
ASTConverter converter = new ASTConverter(options, false, monitor);
AST ast = AST.newAST(AST.LEVEL_2_0);
final BindingResolver resolver = new BindingResolver();
ast.setBindingResolver(resolver);
converter.setAST(ast);
CompilationUnit compilationUnit = converter.convert(compilationUnitDeclaration2, source);
compilationUnit.setLineEndTable(compilationUnitDeclaration2.compilationResult.lineSeparatorPositions);
resolver.storeModificationCount(ast.modificationCount());
return compilationUnit;
} finally {
if (compilationUnitDeclaration != null) {
compilationUnitDeclaration.cleanUp();
}
}
} else {
CompilationUnitDeclaration compilationUnitDeclaration = CompilationUnitResolver.parse(
source,
searcher,
options);
ASTConverter converter = new ASTConverter(options, false, monitor);
AST ast = AST.newAST(AST.LEVEL_2_0);
final BindingResolver resolver = new BindingResolver();
ast.setBindingResolver(resolver);
converter.setAST(ast);
CompilationUnit compilationUnit = converter.convert(compilationUnitDeclaration, source);
compilationUnit.setLineEndTable(compilationUnitDeclaration.compilationResult.lineSeparatorPositions);
resolver.storeModificationCount(ast.modificationCount());
return compilationUnit;
}
}
private static void rootNodeToCompilationUnit(AST ast, ASTConverter converter, CompilationUnit compilationUnit, ASTNode node, RecordedParsingInformation recordedParsingInformation) {
final int problemsCount = recordedParsingInformation.problemsCount;
switch(node.getNodeType()) {
case ASTNode.BLOCK :
{
Block block = (Block) node;
if (problemsCount != 0) {
// propagate and record problems
final IProblem[] problems = recordedParsingInformation.problems;
for (int i = 0, max = block.statements().size(); i < max; i++) {
converter.propagateErrors((ASTNode) block.statements().get(i), problems);
}
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 IProblem[] problems = recordedParsingInformation.problems;
for (int i = 0, max = typeDeclaration.bodyDeclarations().size(); i < max; i++) {
converter.propagateErrors((ASTNode) typeDeclaration.bodyDeclarations().get(i), problems);
}
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 IProblem[] problems = recordedParsingInformation.problems;
converter.propagateErrors(expression, problems);
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);
}
}
}
}