1 /*******************************************************************************
2 * Copyright (c) 2004, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.core.dom;
13 import java.io.PrintWriter;
14 import java.io.StringWriter;
15 import java.util.HashMap;
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import net.sourceforge.phpdt.core.IClassFile;
20 import net.sourceforge.phpdt.core.ICompilationUnit;
21 import net.sourceforge.phpdt.core.IJavaElement;
22 import net.sourceforge.phpdt.core.ITypeRoot;
23 import net.sourceforge.phpdt.core.IJavaProject;
24 import net.sourceforge.phpdt.core.JavaCore;
25 import net.sourceforge.phpdt.core.JavaModelException;
26 import net.sourceforge.phpdt.core.WorkingCopyOwner;
27 import net.sourceforge.phpdt.core.compiler.CategorizedProblem;
28 import net.sourceforge.phpdt.core.compiler.CharOperation;
29 import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration;
30 import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration;
31 import net.sourceforge.phpdt.internal.compiler.env.IBinaryType;
32 import net.sourceforge.phpdt.internal.compiler.parser.RecoveryScanner;
33 import net.sourceforge.phpdt.internal.compiler.parser.RecoveryScannerData;
34 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
35 import net.sourceforge.phpdt.internal.compiler.util.SuffixConstants;
36 import net.sourceforge.phpdt.internal.core.*;
37 import net.sourceforge.phpdt.internal.core.util.CodeSnippetParsingUtil;
38 import net.sourceforge.phpdt.internal.core.util.RecordedParsingInformation;
39 import net.sourceforge.phpdt.internal.core.util.Util;
42 * A Java language parser for creating abstract syntax trees (ASTs).
44 * Example: Create basic AST from source string
46 * char[] source = ...;
47 * ASTParser parser = ASTParser.newParser(AST.JLS3); // handles JDK 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6
48 * parser.setSource(source);
49 * CompilationUnit result = (CompilationUnit) parser.createAST(null);
51 * Once a configured parser instance has been used to create an AST,
52 * the settings are automatically reset to their defaults,
53 * ready for the parser instance to be reused.
56 * There are a number of configurable features:
58 * <li>Source string from {@link #setSource(char[]) char[]},
59 * {@link #setSource(ICompilationUnit) ICompilationUnit},
60 * or {@link #setSource(IClassFile) IClassFile}, and limited
61 * to a specified {@linkplain #setSourceRange(int,int) subrange}.</li>
62 * <li>Whether {@linkplain #setResolveBindings(boolean) bindings} will be created.</li>
63 * <li>Which {@linkplain #setWorkingCopyOwner(WorkingCopyOwner)
64 * working copy owner} to use when resolving bindings.</li>
65 * <li>A hypothetical {@linkplain #setUnitName(String) compilation unit file name}
66 * and {@linkplain #setProject(IJavaProject) Java project}
67 * for locating a raw source string in the Java model (when
68 * resolving bindings)</li>
69 * <li>Which {@linkplain #setCompilerOptions(Map) compiler options}
70 * to use. This is especially important to use if the parsing/scanning of the source code requires a
71 * different version than the default of the workspace. For example, the workspace defaults are 1.4 and
72 * you want to create an AST for a source code that is using 1.5 constructs.</li>
73 * <li>Whether to parse just {@linkplain #setKind(int) an expression, statements,
74 * or body declarations} rather than an entire compilation unit.</li>
75 * <li>Whether to return a {@linkplain #setFocalPosition(int) abridged AST}
76 * focused on the declaration containing a given source position.</li>
81 * @noinstantiate This class is not intended to be instantiated by clients.
83 public class ASTParser {
86 * Kind constant used to request that the source be parsed
87 * as a single expression.
89 public static final int K_EXPRESSION = 0x01;
92 * Kind constant used to request that the source be parsed
93 * as a sequence of statements.
95 public static final int K_STATEMENTS = 0x02;
98 * Kind constant used to request that the source be parsed
99 * as a sequence of class body declarations.
101 public static final int K_CLASS_BODY_DECLARATIONS = 0x04;
104 * Kind constant used to request that the source be parsed
105 * as a compilation unit.
107 public static final int K_COMPILATION_UNIT = 0x08;
110 * Creates a new object for creating a Java abstract syntax tree
111 * (AST) following the specified set of API rules.
113 * @param level the API level; one of the LEVEL constants
114 * declared on <code>AST</code>
115 * @return new ASTParser instance
117 public static ASTParser newParser(int level) {
118 return new ASTParser(level);
122 * Level of AST API desired.
124 private final int apiLevel;
127 * Kind of parse requested. Defaults to an entire compilation unit.
132 * Compiler options. Defaults to JavaCore.getOptions().
134 private Map compilerOptions;
137 * Request for bindings. Defaults to <code>false</code>.
139 private boolean resolveBindings;
142 * Request for a partial AST. Defaults to <code>false</code>.
144 private boolean partial = false;
147 * Request for a statements recovery. Defaults to <code>false</code>.
149 private boolean statementsRecovery;
152 * Request for a bindings recovery. Defaults to <code>false</code>.
154 private boolean bindingsRecovery;
157 * The focal point for a partial AST request.
158 * Only used when <code>partial</code> is <code>true</code>.
160 private int focalPointPosition;
165 private char[] rawSource = null;
168 * Java model class file or compilation unit supplying the source.
170 private ITypeRoot typeRoot = null;
173 * Character-based offset into the source string where parsing is to
174 * begin. Defaults to 0.
176 private int sourceOffset = 0;
179 * Character-based length limit, or -1 if unlimited.
180 * All characters in the source string between <code>offset</code>
181 * and <code>offset+length-1</code> inclusive are parsed. Defaults to -1,
182 * which means the rest of the source string.
184 private int sourceLength = -1;
187 * Working copy owner. Defaults to primary owner.
189 private WorkingCopyOwner workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
192 * Java project used to resolve names, or <code>null</code> if none.
195 private IJavaProject project = null;
198 * Name of the compilation unit for resolving bindings, or
199 * <code>null</code> if none. Defaults to none.
201 private String unitName = null;
204 * Creates a new AST parser for the given API level.
206 * N.B. This constructor is package-private.
209 * @param level the API level; one of the LEVEL constants
210 * declared on <code>AST</code>
212 ASTParser(int level) {
213 if ((level != AST.JLS2_INTERNAL)
214 && (level != AST.JLS3)) {
215 throw new IllegalArgumentException();
217 this.apiLevel = level;
218 initializeDefaults();
222 * Sets all the setting to their default values.
224 private void initializeDefaults() {
225 this.astKind = K_COMPILATION_UNIT;
226 this.rawSource = null;
227 this.typeRoot = null;
228 this.resolveBindings = false;
229 this.sourceLength = -1;
230 this.sourceOffset = 0;
231 this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
232 this.unitName = null;
234 this.partial = false;
235 Map options = JavaCore.getOptions();
236 options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags
237 this.compilerOptions = options;
241 * Requests that the compiler should perform bindings recovery.
242 * When bindings recovery is enabled the compiler returns incomplete bindings.
244 * Default to <code>false</code>.
246 * <p>This should be set to true only if bindings are resolved. It has no effect if there is no binding
249 * @param enabled <code>true</code> if incomplete bindings are expected,
250 * and <code>false</code> if only complete bindings are expected.
252 * @see IBinding#isRecovered()
255 public void setBindingsRecovery(boolean enabled) {
256 this.bindingsRecovery = enabled;
259 * Sets the compiler options to be used when parsing.
261 * Note that {@link #setSource(IClassFile)},
262 * {@link #setSource(ICompilationUnit)},
263 * and {@link #setProject(IJavaProject)} reset the compiler options
264 * based on the Java project. In other cases, compiler options default
265 * to {@link JavaCore#getOptions()}. In either case, and especially
266 * in the latter, the caller should carefully weight the consequences of
267 * allowing compiler options to be defaulted as opposed to being
268 * explicitly specified for the <code>ASTParser</code> instance.
269 * For instance, there is a compiler option called "Source Compatibility Mode"
270 * which determines which JDK level the source code is expected to meet.
271 * If you specify "1.4", then "assert" is treated as a keyword and disallowed
272 * as an identifier; if you specify "1.3", then "assert" is allowed as an
273 * identifier. So this particular setting has a major bearing on what is
274 * considered syntactically legal. By explicitly specifying the setting,
275 * the client control exactly how the parser works. On the other hand,
276 * allowing default settings means the parsing behaves like other JDT tools.
279 * @param options the table of options (key type: <code>String</code>;
280 * value type: <code>String</code>), or <code>null</code>
281 * to set it back to the default
283 public void setCompilerOptions(Map options) {
284 if (options == null) {
285 options = JavaCore.getOptions();
287 // copy client's options so as to not do any side effect on them
288 options = new HashMap(options);
290 options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags
291 this.compilerOptions = options;
295 * Requests that the compiler should provide binding information for
296 * the AST nodes it creates.
298 * Default to <code>false</code> (no bindings).
301 * If <code>setResolveBindings(true)</code>, the various names
302 * and types appearing in the AST can be resolved to "bindings"
303 * by calling the <code>resolveBinding</code> methods. These bindings
304 * draw connections between the different parts of a program, and
305 * generally afford a more powerful vantage point for clients who wish to
306 * analyze a program's structure more deeply. These bindings come at a
307 * considerable cost in both time and space, however, and should not be
308 * requested frivolously. The additional space is not reclaimed until the
309 * AST, all its nodes, and all its bindings become garbage. So it is very
310 * important to not retain any of these objects longer than absolutely
311 * necessary. Bindings are resolved at the time the AST is created. Subsequent
312 * modifications to the AST do not affect the bindings returned by
313 * <code>resolveBinding</code> methods in any way; these methods return the
314 * same binding as before the AST was modified (including modifications
315 * that rearrange subtrees by reparenting nodes).
316 * If <code>setResolveBindings(false)</code> (the default), the analysis
317 * does not go beyond parsing and building the tree, and all
318 * <code>resolveBinding</code> methods return <code>null</code> from the
322 * When bindings are requested, instead of considering compilation units on disk only
323 * one can supply a <code>WorkingCopyOwner</code>. Working copies owned
324 * by this owner take precedence over the underlying compilation units when looking
325 * up names and drawing the connections.
328 * Binding information is obtained from the Java model.
329 * This means that the compilation unit must be located relative to the
330 * Java model. This happens automatically when the source code comes from
331 * either {@link #setSource(ICompilationUnit) setSource(ICompilationUnit)}
332 * or {@link #setSource(IClassFile) setSource(IClassFile)}.
333 * When source is supplied by {@link #setSource(char[]) setSource(char[])},
334 * the location must be extablished explicitly by calling
335 * {@link #setProject(IJavaProject)} and {@link #setUnitName(String)}.
336 * Note that the compiler options that affect doc comment checking may also
337 * affect whether any bindings are resolved for nodes within doc comments.
340 * @param bindings <code>true</code> if bindings are wanted,
341 * and <code>false</code> if bindings are not of interest
343 public void setResolveBindings(boolean bindings) {
344 this.resolveBindings = bindings;
348 * Requests an abridged abstract syntax tree.
349 * By default, complete ASTs are returned.
351 * When <code>true</code> the resulting AST does not have nodes for
352 * the entire compilation unit. Rather, the AST is only fleshed out
353 * for the node that include the given source position. This kind of limited
354 * AST is sufficient for certain purposes but totally unsuitable for others.
355 * In places where it can be used, the limited AST offers the advantage of
356 * being smaller and faster to construct.
359 * The AST will include nodes for all of the compilation unit's
360 * package, import, and top-level type declarations. It will also always contain
361 * nodes for all the body declarations for those top-level types, as well
362 * as body declarations for any member types. However, some of the body
363 * declarations may be abridged. In particular, the statements ordinarily
364 * found in the body of a method declaration node will not be included
365 * (the block will be empty) unless the source position falls somewhere
366 * within the source range of that method declaration node. The same is true
367 * for initializer declarations; the statements ordinarily found in the body
368 * of initializer node will not be included unless the source position falls
369 * somewhere within the source range of that initializer declaration node.
370 * Field declarations are never abridged. Note that the AST for the body of
371 * that one unabridged method (or initializer) is 100% complete; it has all
372 * its statements, including any local or anonymous type declarations
373 * embedded within them. When the the given position is not located within
374 * the source range of any body declaration of a top-level type, the AST
375 * returned will be a skeleton that includes nodes for all and only the major
376 * declarations; this kind of AST is still quite useful because it contains
377 * all the constructs that introduce names visible to the world outside the
381 * @param position a position into the corresponding body declaration
383 public void setFocalPosition(int position) {
385 this.focalPointPosition = position;
389 * Sets the kind of constructs to be parsed from the source.
390 * Defaults to an entire compilation unit.
392 * When the parse is successful the result returned includes the ASTs for the
395 * <li>{@link #K_COMPILATION_UNIT K_COMPILATION_UNIT}: The result node
396 * is a {@link CompilationUnit}.</li>
397 * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result node
398 * is a {@link TypeDeclaration} whose
399 * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations}
400 * are the new trees. Other aspects of the type declaration are unspecified.</li>
401 * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a
402 * {@link Block Block} whose {@link Block#statements() statements}
403 * are the new trees. Other aspects of the block are unspecified.</li>
404 * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of
405 * {@link Expression Expression}. Other aspects of the expression are unspecified.</li>
407 * The resulting AST node is rooted under (possibly contrived)
408 * {@link CompilationUnit CompilationUnit} node, to allow the
409 * client to retrieve the following pieces of information
412 * <li>{@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line
413 * numbers start at 1 and only cover the subrange scanned
414 * (<code>source[offset]</code> through <code>source[offset+length-1]</code>).</li>
415 * <li>{@linkplain CompilationUnit#getMessages() Compiler messages}
416 * and {@linkplain CompilationUnit#getProblems() detailed problem reports}.
417 * Character positions are relative to the start of
418 * <code>source</code>; line positions are for the subrange scanned.</li>
419 * <li>{@linkplain CompilationUnit#getCommentList() Comment list}
420 * for the subrange scanned.</li>
422 * The contrived nodes do not have source positions. Other aspects of the
423 * {@link CompilationUnit CompilationUnit} node are unspecified, including
424 * the exact arrangment of intervening nodes.
427 * Lexical or syntax errors detected while parsing can result in
428 * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}.
429 * In more severe failure cases where the parser is unable to
430 * recognize the input, this method returns
431 * a {@link CompilationUnit CompilationUnit} node with at least the
434 * <p>Each node in the subtree (other than the contrived nodes)
435 * carries source range(s) information relating back
436 * to positions in the given source (the given source itself
437 * is not remembered with the AST).
438 * The source range usually begins at the first character of the first token
439 * corresponding to the node; leading whitespace and comments are <b>not</b>
440 * included. The source range usually extends through the last character of
441 * the last token corresponding to the node; trailing whitespace and
442 * comments are <b>not</b> included. There are a handful of exceptions
443 * (including the various body declarations); the
444 * specification for these node type spells out the details.
445 * Source ranges nest properly: the source range for a child is always
446 * within the source range of its parent, and the source ranges of sibling
447 * nodes never overlap.
450 * Binding information is only computed when <code>kind</code> is
451 * <code>K_COMPILATION_UNIT</code>.
454 * @param kind the kind of construct to parse: one of
455 * {@link #K_COMPILATION_UNIT},
456 * {@link #K_CLASS_BODY_DECLARATIONS},
457 * {@link #K_EXPRESSION},
458 * {@link #K_STATEMENTS}
460 public void setKind(int kind) {
461 if ((kind != K_COMPILATION_UNIT)
462 && (kind != K_CLASS_BODY_DECLARATIONS)
463 && (kind != K_EXPRESSION)
464 && (kind != K_STATEMENTS)) {
465 throw new IllegalArgumentException();
471 * Sets the source code to be parsed.
473 * @param source the source string to be parsed,
474 * or <code>null</code> if none
476 public void setSource(char[] source) {
477 this.rawSource = source;
478 // clear the type root
479 this.typeRoot = null;
483 * Sets the source code to be parsed.
484 * This method automatically sets the project (and compiler
485 * options) based on the given compilation unit, in a manner
486 * equivalent to <code>setProject(source.getJavaProject())</code>
488 * @param source the Java model compilation unit whose source code
489 * is to be parsed, or <code>null</code> if none
491 public void setSource(ICompilationUnit source) {
492 setSource((ITypeRoot)source);
496 * Sets the source code to be parsed.
497 * <p>This method automatically sets the project (and compiler
498 * options) based on the given compilation unit, in a manner
499 * equivalent to <code>setProject(source.getJavaProject())</code>.</p>
500 * <p>If the given class file has no source attachment, the creation of the
501 * ast will fail with an IllegalStateException.</p>
503 * @param source the Java model class file whose corresponding source code
504 * is to be parsed, or <code>null</code> if none
506 public void setSource(IClassFile source) {
507 setSource((ITypeRoot)source);
511 * Sets the source code to be parsed.
512 * <p>This method automatically sets the project (and compiler
513 * options) based on the given compilation unit of class file, in a manner
514 * equivalent to <code>setProject(source.getJavaProject())</code>.</p>
515 * <p>If the source is a class file without source attachment, the creation of the
516 * ast will fail with an IllegalStateException.</p>
518 * @param source the Java model compilation unit or class file whose corresponding source code
519 * is to be parsed, or <code>null</code> if none
522 public void setSource(ITypeRoot source) {
523 this.typeRoot = source;
524 // clear the raw source
525 this.rawSource = null;
526 if (source != null) {
527 this.project = source.getJavaProject();
528 Map options = this.project.getOptions(true);
529 options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags
530 this.compilerOptions = options;
535 * Sets the subrange of the source code to be parsed.
536 * By default, the entire source string will be parsed
537 * (<code>offset</code> 0 and <code>length</code> -1).
539 * @param offset the index of the first character to parse
540 * @param length the number of characters to parse, or -1 if
541 * the remainder of the source string is
543 public void setSourceRange(int offset, int length) {
544 if (offset < 0 || length < -1) {
545 throw new IllegalArgumentException();
547 this.sourceOffset = offset;
548 this.sourceLength = length;
552 * Requests that the compiler should perform statements recovery.
553 * When statements recovery is enabled the compiler tries to create statement nodes
554 * from code containing syntax errors
556 * Default to <code>false</code>.
559 * @param enabled <code>true</code> if statements containing syntax errors are wanted,
560 * and <code>false</code> if these statements aren't wanted.
564 public void setStatementsRecovery(boolean enabled) {
565 this.statementsRecovery = enabled;
569 * Sets the working copy owner using when resolving bindings, where
570 * <code>null</code> means the primary owner. Defaults to the primary owner.
572 * @param owner the owner of working copies that take precedence over underlying
573 * compilation units, or <code>null</code> if the primary owner should be used
575 public void setWorkingCopyOwner(WorkingCopyOwner owner) {
577 this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
579 this.workingCopyOwner = owner;
584 * Sets the name of the compilation unit that would hypothetically contains
585 * the source string. This is used in conjunction with {@link #setSource(char[])}
586 * and {@link #setProject(IJavaProject) } to locate the compilation unit relative to a Java project.
587 * Defaults to none (<code>null</code>).
589 * The name of the compilation unit must be supplied for resolving bindings.
590 * This name should be suffixed by a dot ('.') followed by one of the
591 * {@link JavaCore#getJavaLikeExtensions() Java-like extensions}
592 * and match the name of the main (public) class or interface declared in the source.</p>
594 * <p>This name must represent the full path of the unit inside the given project. For example, if the source
595 * declares a public class named "Foo" in a project "P", the name of the compilation unit must be
596 * "/P/Foo.java". If the source declares a public class name "Bar" in a package "p1.p2" in a project "P",
597 * the name of the compilation unit must be "/P/p1/p2/Bar.java".</p>
599 * @param unitName the name of the compilation unit that would contain the source
600 * string, or <code>null</code> if none
602 public void setUnitName(String unitName) {
603 this.unitName = unitName;
607 * Sets the Java project used when resolving bindings.
608 * This method automatically sets the compiler
609 * options based on the given project:
611 * setCompilerOptions(project.getOptions(true));
613 * See {@link #setCompilerOptions(Map)} for a discussion of
614 * the pros and cons of using these options vs specifying
615 * compiler options explicitly.
616 * This setting is used in conjunction with <code>setSource(char[])</code>.
617 * For the purposes of resolving bindings, types declared in the
618 * source string will hide types by the same name available
619 * through the classpath of the given project.
620 * Defaults to none (<code>null</code>).
622 * @param project the Java project used to resolve names, or
623 * <code>null</code> if none
625 public void setProject(IJavaProject project) {
626 this.project = project;
627 if (project != null) {
628 Map options = project.getOptions(true);
629 options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags
630 this.compilerOptions = options;
635 * Creates an abstract syntax tree.
637 * A successful call to this method returns all settings to their
638 * default values so the object is ready to be reused.
641 * @param monitor the progress monitor used to report progress and request cancelation,
642 * or <code>null</code> if none
643 * @return an AST node whose type depends on the kind of parse
644 * requested, with a fallback to a <code>CompilationUnit</code>
645 * in the case of severe parsing errors
646 * @exception IllegalStateException if the settings provided
647 * are insufficient, contradictory, or otherwise unsupported
649 public ASTNode createAST(IProgressMonitor monitor) {
650 ASTNode result = null;
651 if (monitor != null) monitor.beginTask("", 1); //$NON-NLS-1$
653 if (this.rawSource == null && this.typeRoot == null) {
654 throw new IllegalStateException("source not specified"); //$NON-NLS-1$
656 result = internalCreateAST(monitor);
658 // re-init defaults to allow reuse (and avoid leaking)
659 initializeDefaults();
660 if (monitor != null) monitor.done();
666 * Creates ASTs for a batch of compilation units.
667 * When bindings are being resolved, processing a
668 * batch of compilation units is more efficient because much
669 * of the work involved in resolving bindings can be shared.
671 * When bindings are being resolved, all compilation units must
672 * come from the same Java project, which must be set beforehand
673 * with <code>setProject</code>.
674 * The compilation units are processed one at a time in no
675 * specified order. For each of the compilation units in turn,
677 * <li><code>ASTParser.createAST</code> is called to parse it
678 * and create a corresponding AST. The calls to
679 * <code>ASTParser.createAST</code> all employ the same settings.</li>
680 * <li><code>ASTRequestor.acceptAST</code> is called passing
681 * the compilation unit and the corresponding AST to
682 * <code>requestor</code>.
685 * Note only ASTs from the given compilation units are reported
686 * to the requestor. If additional compilation units are required to
687 * resolve the original ones, the corresponding ASTs are <b>not</b>
688 * reported to the requestor.
691 * Note also the following parser parameters are used, regardless of what
692 * may have been specified:
694 * <li>The {@linkplain #setKind(int) parser kind} is <code>K_COMPILATION_UNIT</code></li>
695 * <li>The {@linkplain #setSourceRange(int,int) source range} is <code>(0, -1)</code></li>
696 * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li>
700 * The <code>bindingKeys</code> parameter specifies bindings keys
701 * ({@link IBinding#getKey()}) that are to be looked up. These keys may
702 * be for elements either inside or outside the set of compilation
703 * units being processed. When bindings are being resolved,
704 * the keys and corresponding bindings (or <code>null</code> if none) are
705 * passed to <code>ASTRequestor.acceptBinding</code>. Note that binding keys
706 * for elements outside the set of compilation units being processed are looked up
707 * after all <code>ASTRequestor.acceptAST</code> callbacks have been made.
708 * Binding keys for elements inside the set of compilation units being processed
709 * are looked up and reported right after the corresponding
710 * <code>ASTRequestor.acceptAST</code> callback has been made.
711 * No <code>ASTRequestor.acceptBinding</code> callbacks are made unless
712 * bindings are being resolved.
715 * A successful call to this method returns all settings to their
716 * default values so the object is ready to be reused.
719 * @param compilationUnits the compilation units to create ASTs for
720 * @param bindingKeys the binding keys to create bindings for
721 * @param requestor the AST requestor that collects abtract syntax trees and bindings
722 * @param monitor the progress monitor used to report progress and request cancelation,
723 * or <code>null</code> if none
724 * @exception IllegalStateException if the settings provided
725 * are insufficient, contradictory, or otherwise unsupported
728 public void createASTs(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor requestor, IProgressMonitor monitor) {
731 if (this.statementsRecovery) flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
732 if (this.resolveBindings) {
733 if (this.project == null)
734 throw new IllegalStateException("project not specified"); //$NON-NLS-1$
735 if (this.bindingsRecovery) flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
736 CompilationUnitResolver.resolve(compilationUnits, bindingKeys, requestor, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, flags, monitor);
738 CompilationUnitResolver.parse(compilationUnits, requestor, this.apiLevel, this.compilerOptions, flags, monitor);
741 // re-init defaults to allow reuse (and avoid leaking)
742 initializeDefaults();
747 * Creates bindings for a batch of Java elements. These elements are either
748 * enclosed in {@link ICompilationUnit}s or in {@link IClassFile}s.
750 * All enclosing compilation units and class files must
751 * come from the same Java project, which must be set beforehand
752 * with <code>setProject</code>.
755 * All elements must exist. If one doesn't exist, an <code>IllegalStateException</code>
759 * The returned array has the same size as the given elements array. At a given position
760 * it contains the binding of the corresponding Java element, or <code>null</code>
761 * if no binding could be created.
764 * Note also the following parser parameters are used, regardless of what
765 * may have been specified:
767 * <li>The {@linkplain #setResolveBindings(boolean) binding resolution flag} is <code>true</code></li>
768 * <li>The {@linkplain #setKind(int) parser kind} is <code>K_COMPILATION_UNIT</code></li>
769 * <li>The {@linkplain #setSourceRange(int,int) source range} is <code>(0, -1)</code></li>
770 * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li>
774 * A successful call to this method returns all settings to their
775 * default values so the object is ready to be reused.
778 * @param elements the Java elements to create bindings for
779 * @return the bindings for the given Java elements, possibly containing <code>null</code>s
780 * if some bindings could not be created
781 * @exception IllegalStateException if the settings provided
782 * are insufficient, contradictory, or otherwise unsupported
785 public IBinding[] createBindings(IJavaElement[] elements, IProgressMonitor monitor) {
787 if (this.project == null)
788 throw new IllegalStateException("project not specified"); //$NON-NLS-1$
790 if (this.statementsRecovery) flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
791 if (this.bindingsRecovery) flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
792 return CompilationUnitResolver.resolve(elements, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, flags, monitor);
794 // re-init defaults to allow reuse (and avoid leaking)
795 initializeDefaults();
799 private ASTNode internalCreateAST(IProgressMonitor monitor) {
800 boolean needToResolveBindings = this.resolveBindings;
801 switch(this.astKind) {
802 case K_CLASS_BODY_DECLARATIONS :
805 if (this.rawSource != null) {
806 if (this.sourceOffset + this.sourceLength > this.rawSource.length) {
807 throw new IllegalStateException();
809 return internalCreateASTForKind();
812 case K_COMPILATION_UNIT :
813 CompilationUnitDeclaration compilationUnitDeclaration = null;
815 NodeSearcher searcher = null;
816 net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit sourceUnit = null;
817 WorkingCopyOwner wcOwner = this.workingCopyOwner;
818 if (this.typeRoot instanceof ICompilationUnit) {
820 * this.compilationUnitSource is an instance of org.eclipse.jdt.internal.core.CompilationUnit that implements
821 * both org.eclipse.jdt.core.ICompilationUnit and org.eclipse.jdt.internal.compiler.env.ICompilationUnit
823 sourceUnit = (net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit) this.typeRoot;
825 * use a BasicCompilation that caches the source instead of using the compilationUnitSource directly
826 * (if it is a working copy, the source can change between the parse and the AST convertion)
827 * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=75632)
829 sourceUnit = new BasicCompilationUnit(sourceUnit.getContents(), sourceUnit.getPackageName(), new String(sourceUnit.getFileName()), this.project);
830 wcOwner = ((ICompilationUnit) this.typeRoot).getOwner();
831 } else if (this.typeRoot instanceof IClassFile) {
833 String sourceString = this.typeRoot.getSource();
834 if (sourceString == null) {
835 throw new IllegalStateException();
837 PackageFragment packageFragment = (PackageFragment) this.typeRoot.getParent();
838 BinaryType type = (BinaryType) this.typeRoot.findPrimaryType();
839 IBinaryType binaryType = (IBinaryType) type.getElementInfo();
840 // file name is used to recreate the Java element, so it has to be the toplevel .class file name
841 char[] fileName = binaryType.getFileName();
842 int firstDollar = CharOperation.indexOf('$', fileName);
843 if (firstDollar != -1) {
844 char[] suffix = SuffixConstants.SUFFIX_class;
845 int suffixLength = suffix.length;
846 char[] newFileName = new char[firstDollar + suffixLength];
847 System.arraycopy(fileName, 0, newFileName, 0, firstDollar);
848 System.arraycopy(suffix, 0, newFileName, firstDollar, suffixLength);
849 fileName = newFileName;
851 sourceUnit = new BasicCompilationUnit(sourceString.toCharArray(), Util.toCharArrays(packageFragment.names), new String(fileName), this.project);
852 } catch(JavaModelException e) {
853 // an error occured accessing the java element
854 StringWriter stringWriter = new StringWriter();
855 PrintWriter writer = null;
857 writer = new PrintWriter(stringWriter);
858 e.printStackTrace(writer);
860 if (writer != null) writer.close();
862 throw new IllegalStateException(String.valueOf(stringWriter.getBuffer()));
864 } else if (this.rawSource != null) {
865 needToResolveBindings = this.resolveBindings && this.unitName != null && this.project != null && this.compilerOptions != null;
866 sourceUnit = new BasicCompilationUnit(this.rawSource, null, this.unitName == null ? "" : this.unitName, this.project); //$NON-NLS-1$
868 throw new IllegalStateException();
871 searcher = new NodeSearcher(this.focalPointPosition);
874 if (this.statementsRecovery) flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY;
875 if (needToResolveBindings) {
876 if (this.bindingsRecovery) flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
879 compilationUnitDeclaration =
880 CompilationUnitResolver.resolve(
884 this.compilerOptions,
885 this.workingCopyOwner,
888 } catch (JavaModelException e) {
889 flags &= ~ICompilationUnit.ENABLE_BINDINGS_RECOVERY;
890 compilationUnitDeclaration = CompilationUnitResolver.parse(
893 this.compilerOptions,
895 needToResolveBindings = false;
898 compilationUnitDeclaration = CompilationUnitResolver.parse(
901 this.compilerOptions,
903 needToResolveBindings = false;
905 CompilationUnit result = CompilationUnitResolver.convert(
906 compilationUnitDeclaration,
907 sourceUnit.getContents(),
909 this.compilerOptions,
910 needToResolveBindings,
912 needToResolveBindings ? new DefaultBindingResolver.BindingTables() : null,
915 result.setTypeRoot(this.typeRoot);
918 if (compilationUnitDeclaration != null && this.resolveBindings) {
919 compilationUnitDeclaration.cleanUp();
923 throw new IllegalStateException();
927 * Parses the given source between the bounds specified by the given offset (inclusive)
928 * and the given length and creates and returns a corresponding abstract syntax tree.
930 * When the parse is successful the result returned includes the ASTs for the
933 * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result node
934 * is a {@link TypeDeclaration TypeDeclaration} whose
935 * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations}
936 * are the new trees. Other aspects of the type declaration are unspecified.</li>
937 * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a
938 * {@link Block Block} whose {@link Block#statements() statements}
939 * are the new trees. Other aspects of the block are unspecified.</li>
940 * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of
941 * {@link Expression Expression}. Other aspects of the expression are unspecified.</li>
943 * The resulting AST node is rooted under an contrived
944 * {@link CompilationUnit CompilationUnit} node, to allow the
945 * client to retrieve the following pieces of information
948 * <li>{@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line
949 * numbers start at 1 and only cover the subrange scanned
950 * (<code>source[offset]</code> through <code>source[offset+length-1]</code>).</li>
951 * <li>{@linkplain CompilationUnit#getMessages() Compiler messages}
952 * and {@linkplain CompilationUnit#getProblems() detailed problem reports}.
953 * Character positions are relative to the start of
954 * <code>source</code>; line positions are for the subrange scanned.</li>
955 * <li>{@linkplain CompilationUnit#getCommentList() Comment list}
956 * for the subrange scanned.</li>
958 * The contrived nodes do not have source positions. Other aspects of the
959 * {@link CompilationUnit CompilationUnit} node are unspecified, including
960 * the exact arrangment of intervening nodes.
963 * Lexical or syntax errors detected while parsing can result in
964 * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}.
965 * In more severe failure cases where the parser is unable to
966 * recognize the input, this method returns
967 * a {@link CompilationUnit CompilationUnit} node with at least the
970 * <p>Each node in the subtree (other than the contrived nodes)
971 * carries source range(s) information relating back
972 * to positions in the given source (the given source itself
973 * is not remembered with the AST).
974 * The source range usually begins at the first character of the first token
975 * corresponding to the node; leading whitespace and comments are <b>not</b>
976 * included. The source range usually extends through the last character of
977 * the last token corresponding to the node; trailing whitespace and
978 * comments are <b>not</b> included. There are a handful of exceptions
979 * (including the various body declarations); the
980 * specification for these node type spells out the details.
981 * Source ranges nest properly: the source range for a child is always
982 * within the source range of its parent, and the source ranges of sibling
983 * nodes never overlap.
986 * This method does not compute binding information; all <code>resolveBinding</code>
987 * methods applied to nodes of the resulting AST return <code>null</code>.
990 * @return an AST node whose type depends on the kind of parse
991 * requested, with a fallback to a <code>CompilationUnit</code>
992 * in the case of severe parsing errors
993 * @see ASTNode#getStartPosition()
994 * @see ASTNode#getLength()
996 private ASTNode internalCreateASTForKind() {
997 final ASTConverter converter = new ASTConverter(this.compilerOptions, false, null);
998 converter.compilationUnitSource = this.rawSource;
999 converter.compilationUnitSourceLength = this.rawSource.length;
1000 converter.scanner.setSource(this.rawSource);
1002 AST ast = AST.newAST(this.apiLevel);
1003 ast.setDefaultNodeFlag(ASTNode.ORIGINAL);
1004 ast.setBindingResolver(new BindingResolver());
1005 if (this.statementsRecovery) {
1006 ast.setFlag(ICompilationUnit.ENABLE_STATEMENTS_RECOVERY);
1008 converter.setAST(ast);
1009 CodeSnippetParsingUtil codeSnippetParsingUtil = new CodeSnippetParsingUtil();
1010 CompilationUnit compilationUnit = ast.newCompilationUnit();
1011 if (this.sourceLength == -1) {
1012 this.sourceLength = this.rawSource.length;
1014 switch(this.astKind) {
1016 ConstructorDeclaration constructorDeclaration = codeSnippetParsingUtil.parseStatements(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true, this.statementsRecovery);
1017 RecoveryScannerData data = constructorDeclaration.compilationResult.recoveryScannerData;
1019 Scanner scanner = converter.scanner;
1020 converter.scanner = new RecoveryScanner(scanner, data.removeUnused());
1021 converter.docParser.scanner = converter.scanner;
1022 converter.scanner.setSource(scanner.source);
1024 RecordedParsingInformation recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation;
1025 int[][] comments = recordedParsingInformation.commentPositions;
1026 if (comments != null) {
1027 converter.buildCommentsTable(compilationUnit, comments);
1029 compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds);
1030 Block block = ast.newBlock();
1031 block.setSourceRange(this.sourceOffset, this.sourceOffset + this.sourceLength);
1032 net.sourceforge.phpdt.internal.compiler.ast.Statement[] statements = constructorDeclaration.statements;
1033 if (statements != null) {
1034 int statementsLength = statements.length;
1035 for (int i = 0; i < statementsLength; i++) {
1036 if (statements[i] instanceof net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration) {
1037 converter.checkAndAddMultipleLocalDeclaration(statements, i, block.statements());
1039 Statement statement = converter.convert(statements[i]);
1040 if (statement != null) {
1041 block.statements().add(statement);
1046 rootNodeToCompilationUnit(ast, compilationUnit, block, recordedParsingInformation, data);
1047 ast.setDefaultNodeFlag(0);
1048 ast.setOriginalModificationCount(ast.modificationCount());
1051 net.sourceforge.phpdt.internal.compiler.ast.Expression expression = codeSnippetParsingUtil.parseExpression(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true);
1052 recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation;
1053 comments = recordedParsingInformation.commentPositions;
1054 if (comments != null) {
1055 converter.buildCommentsTable(compilationUnit, comments);
1057 compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds);
1058 if (expression != null) {
1059 Expression expression2 = converter.convert(expression);
1060 rootNodeToCompilationUnit(expression2.getAST(), compilationUnit, expression2, codeSnippetParsingUtil.recordedParsingInformation, null);
1061 ast.setDefaultNodeFlag(0);
1062 ast.setOriginalModificationCount(ast.modificationCount());
1065 CategorizedProblem[] problems = recordedParsingInformation.problems;
1066 if (problems != null) {
1067 compilationUnit.setProblems(problems);
1069 ast.setDefaultNodeFlag(0);
1070 ast.setOriginalModificationCount(ast.modificationCount());
1071 return compilationUnit;
1073 case K_CLASS_BODY_DECLARATIONS :
1074 final net.sourceforge.phpdt.internal.compiler.ast.ASTNode[] nodes = codeSnippetParsingUtil.parseClassBodyDeclarations(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true);
1075 recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation;
1076 comments = recordedParsingInformation.commentPositions;
1077 if (comments != null) {
1078 converter.buildCommentsTable(compilationUnit, comments);
1080 compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds);
1081 if (nodes != null) {
1082 TypeDeclaration typeDeclaration = converter.convert(nodes);
1083 typeDeclaration.setSourceRange(this.sourceOffset, this.sourceOffset + this.sourceLength);
1084 rootNodeToCompilationUnit(typeDeclaration.getAST(), compilationUnit, typeDeclaration, codeSnippetParsingUtil.recordedParsingInformation, null);
1085 ast.setDefaultNodeFlag(0);
1086 ast.setOriginalModificationCount(ast.modificationCount());
1087 return typeDeclaration;
1089 CategorizedProblem[] problems = recordedParsingInformation.problems;
1090 if (problems != null) {
1091 compilationUnit.setProblems(problems);
1093 ast.setDefaultNodeFlag(0);
1094 ast.setOriginalModificationCount(ast.modificationCount());
1095 return compilationUnit;
1098 throw new IllegalStateException();
1101 private void propagateErrors(ASTNode astNode, CategorizedProblem[] problems, RecoveryScannerData data) {
1102 astNode.accept(new ASTSyntaxErrorPropagator(problems));
1104 astNode.accept(new ASTRecoveryPropagator(problems, data));
1108 private void rootNodeToCompilationUnit(AST ast, CompilationUnit compilationUnit, ASTNode node, RecordedParsingInformation recordedParsingInformation, RecoveryScannerData data) {
1109 final int problemsCount = recordedParsingInformation.problemsCount;
1110 switch(node.getNodeType()) {
1111 case ASTNode.BLOCK :
1113 Block block = (Block) node;
1114 if (problemsCount != 0) {
1115 // propagate and record problems
1116 final CategorizedProblem[] problems = recordedParsingInformation.problems;
1117 propagateErrors(block, problems, data);
1118 compilationUnit.setProblems(problems);
1120 TypeDeclaration typeDeclaration = ast.newTypeDeclaration();
1121 Initializer initializer = ast.newInitializer();
1122 initializer.setBody(block);
1123 typeDeclaration.bodyDeclarations().add(initializer);
1124 compilationUnit.types().add(typeDeclaration);
1127 case ASTNode.TYPE_DECLARATION :
1129 TypeDeclaration typeDeclaration = (TypeDeclaration) node;
1130 if (problemsCount != 0) {
1131 // propagate and record problems
1132 final CategorizedProblem[] problems = recordedParsingInformation.problems;
1133 propagateErrors(typeDeclaration, problems, data);
1134 compilationUnit.setProblems(problems);
1136 compilationUnit.types().add(typeDeclaration);
1140 if (node instanceof Expression) {
1141 Expression expression = (Expression) node;
1142 if (problemsCount != 0) {
1143 // propagate and record problems
1144 final CategorizedProblem[] problems = recordedParsingInformation.problems;
1145 propagateErrors(expression, problems, data);
1146 compilationUnit.setProblems(problems);
1148 ExpressionStatement expressionStatement = ast.newExpressionStatement(expression);
1149 Block block = ast.newBlock();
1150 block.statements().add(expressionStatement);
1151 Initializer initializer = ast.newInitializer();
1152 initializer.setBody(block);
1153 TypeDeclaration typeDeclaration = ast.newTypeDeclaration();
1154 typeDeclaration.bodyDeclarations().add(initializer);
1155 compilationUnit.types().add(typeDeclaration);