KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > core > dom > ASTParser


1 /*******************************************************************************
2  * Copyright (c) 2004, 2005 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
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.core.dom;
12
13 import java.util.Map JavaDoc;
14
15 import org.eclipse.core.runtime.IProgressMonitor;
16 import org.eclipse.jdt.core.IClassFile;
17 import org.eclipse.jdt.core.ICompilationUnit;
18 import org.eclipse.jdt.core.IJavaElement;
19 import org.eclipse.jdt.core.IJavaProject;
20 import org.eclipse.jdt.core.JavaCore;
21 import org.eclipse.jdt.core.JavaModelException;
22 import org.eclipse.jdt.core.WorkingCopyOwner;
23 import org.eclipse.jdt.core.compiler.IProblem;
24 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
25 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
26 import org.eclipse.jdt.internal.compiler.ast.Statement;
27 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
28 import org.eclipse.jdt.internal.core.*;
29 import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner;
30 import org.eclipse.jdt.internal.core.PackageFragment;
31 import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil;
32 import org.eclipse.jdt.internal.core.util.RecordedParsingInformation;
33 import org.eclipse.jdt.internal.core.util.Util;
34
35 /**
36  * A Java language parser for creating abstract syntax trees (ASTs).
37  * <p>
38  * Example: Create basic AST from source string
39  * <pre>
40  * char[] source = ...;
41  * ASTParser parser = ASTParser.newParser(AST.JLS3); // handles JDK 1.0, 1.1, 1.2, 1.3, 1.4, 1.5
42  * parser.setSource(source);
43  * CompilationUnit result = (CompilationUnit) parser.createAST(null);
44  * </pre>
45  * Once a configured parser instance has been used to create an AST,
46  * the settings are automicatically returned to their defaults,
47  * ready for the parser instance to be reused.
48  * </p>
49  * <p>
50  * There are a number of configurable features:
51  * <ul>
52  * <li>Source string from {@link #setSource(char[]) char[]},
53  * {@link #setSource(ICompilationUnit) ICompilationUnit},
54  * or {@link #setSource(IClassFile) IClassFile}, and limited
55  * to a specified {@linkplain #setSourceRange(int,int) subrange}.</li>
56  * <li>Whether {@linkplain #setResolveBindings(boolean) bindings} will be created.</li>
57  * <li>Which {@linkplain #setWorkingCopyOwner(WorkingCopyOwner)
58  * working set owner} to use when resolving bindings).</li>
59  * <li>A hypothetical {@linkplain #setUnitName(String) compilation unit file name}
60  * and {@linkplain #setProject(IJavaProject) Java project}
61  * for locating a raw source string in the Java model (when
62  * resolving bindings)</li>
63  * <li>Which {@linkplain #setCompilerOptions(Map) compiler options}
64  * to use.</li>
65  * <li>Whether to parse just {@linkplain #setKind(int) an expression, statements,
66  * or body declarations} rather than an entire compilation unit.</li>
67  * <li>Whether to return a {@linkplain #setFocalPosition(int) abridged AST}
68  * focused on the declaration containing a given source position.</li>
69  * </ul>
70  * </p>
71  *
72  * @since 3.0
73  */

74 public class ASTParser {
75
76     /**
77      * Kind constant used to request that the source be parsed
78      * as a single expression.
79      */

80     public static final int K_EXPRESSION = 0x01;
81
82     /**
83      * Kind constant used to request that the source be parsed
84      * as a sequence of statements.
85      */

86     public static final int K_STATEMENTS = 0x02;
87     
88     /**
89      * Kind constant used to request that the source be parsed
90      * as a sequence of class body declarations.
91      */

92     public static final int K_CLASS_BODY_DECLARATIONS = 0x04;
93     
94     /**
95      * Kind constant used to request that the source be parsed
96      * as a compilation unit.
97      */

98     public static final int K_COMPILATION_UNIT = 0x08;
99     
100     /**
101      * Creates a new object for creating a Java abstract syntax tree
102      * (AST) following the specified set of API rules.
103      *
104      * @param level the API level; one of the LEVEL constants
105      * declared on <code>AST</code>
106      * @return new ASTParser instance
107      */

108     public static ASTParser newParser(int level) {
109         return new ASTParser(level);
110     }
111
112     /**
113      * Level of AST API desired.
114      */

115     private final int apiLevel;
116
117     /**
118      * Kind of parse requested. Defaults to an entire compilation unit.
119      */

120     private int astKind;
121     
122     /**
123      * Compiler options. Defaults to JavaCore.getOptions().
124      */

125     private Map JavaDoc compilerOptions;
126     
127     /**
128      * Request for bindings. Defaults to <code>false</code>.
129      */

130     private boolean resolveBindings;
131
132     /**
133      * Request for a partial AST. Defaults to <code>false</code>.
134      */

135     private boolean partial = false;
136
137     /**
138      * The focal point for a partial AST request.
139      * Only used when <code>partial</code> is <code>true</code>.
140      */

141     private int focalPointPosition;
142
143     /**
144      * Source string.
145      */

146     private char[] rawSource = null;
147     
148     /**
149      * Java mode compilation unit supplying the source.
150      */

151     private ICompilationUnit compilationUnitSource = null;
152     
153     /**
154      * Java model class file supplying the source.
155      */

156     private IClassFile classFileSource = null;
157     
158     /**
159      * Character-based offset into the source string where parsing is to
160      * begin. Defaults to 0.
161      */

162     private int sourceOffset = 0;
163     
164     /**
165      * Character-based length limit, or -1 if unlimited.
166      * All characters in the source string between <code>offset</code>
167      * and <code>offset+length-1</code> inclusive are parsed. Defaults to -1,
168      * which means the rest of the source string.
169      */

170     private int sourceLength = -1;
171
172     /**
173      * Working copy owner. Defaults to primary owner.
174      */

175     private WorkingCopyOwner workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
176     
177     /**
178      * Java project used to resolve names, or <code>null</code> if none.
179      * Defaults to none.
180      */

181     private IJavaProject project = null;
182     
183     /**
184      * Name of the compilation unit for resolving bindings, or
185      * <code>null</code> if none. Defaults to none.
186      */

187     private String JavaDoc unitName = null;
188
189     /**
190      * Creates a new AST parser for the given API level.
191      * <p>
192      * N.B. This constructor is package-private.
193      * </p>
194      *
195      * @param level the API level; one of the LEVEL constants
196      * declared on <code>AST</code>
197      */

198     ASTParser(int level) {
199         if ((level != AST.JLS2_INTERNAL)
200             && (level != AST.JLS3)) {
201             throw new IllegalArgumentException JavaDoc();
202         }
203         this.apiLevel = level;
204         initializeDefaults();
205     }
206
207     /**
208      * Sets all the setting to their default values.
209      */

210     private void initializeDefaults() {
211        this.astKind = K_COMPILATION_UNIT;
212        this.rawSource = null;
213        this.classFileSource = null;
214        this.compilationUnitSource = null;
215        this.resolveBindings = false;
216        this.sourceLength = -1;
217        this.sourceOffset = 0;
218        this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
219        this.unitName = null;
220        this.project = null;
221        this.partial = false;
222        this.compilerOptions = JavaCore.getOptions();
223     }
224        
225     /**
226      * Sets the compiler options to be used when parsing.
227      * <p>
228      * Note that {@link #setSource(IClassFile)},
229      * {@link #setSource(ICompilationUnit)},
230      * and {@link #setProject(IJavaProject)} reset the compiler options
231      * based on the Java project. In other cases, compiler options default
232      * to {@link JavaCore#getOptions()}. In either case, and especially
233      * in the latter, the caller should carefully weight the consequences of
234      * allowing compiler options to be defaulted as opposed to being
235      * explicitly specified for the <code>ASTParser</code> instance.
236      * For instance, there is a compiler option called "Source Compatibility Mode"
237      * which determines which JDK level the source code is expected to meet.
238      * If you specify "1.4", then "assert" is treated as a keyword and disallowed
239      * as an identifier; if you specify "1.3", then "assert" is allowed as an
240      * identifier. So this particular setting has a major bearing on what is
241      * considered syntactically legal. By explicitly specifying the setting,
242      * the client control exactly how the parser works. On the other hand,
243      * allowing default settings means the parsing behaves like other JDT tools.
244      * </p>
245      *
246      * @param options the table of options (key type: <code>String</code>;
247      * value type: <code>String</code>), or <code>null</code>
248      * to set it back to the default
249      */

250     public void setCompilerOptions(Map JavaDoc options) {
251        if (options == null) {
252           this.compilerOptions = JavaCore.getOptions();
253        }
254        this.compilerOptions = options;
255     }
256     
257     /**
258      * Requests that the compiler should provide binding information for
259      * the AST nodes it creates.
260      * <p>
261      * Default to <code>false</code> (no bindings).
262      * </p>
263      * <p>
264      * If <code>setResolveBindings(true)</code>, the various names
265      * and types appearing in the AST can be resolved to "bindings"
266      * by calling the <code>resolveBinding</code> methods. These bindings
267      * draw connections between the different parts of a program, and
268      * generally afford a more powerful vantage point for clients who wish to
269      * analyze a program's structure more deeply. These bindings come at a
270      * considerable cost in both time and space, however, and should not be
271      * requested frivolously. The additional space is not reclaimed until the
272      * AST, all its nodes, and all its bindings become garbage. So it is very
273      * important to not retain any of these objects longer than absolutely
274      * necessary. Bindings are resolved at the time the AST is created. Subsequent
275      * modifications to the AST do not affect the bindings returned by
276      * <code>resolveBinding</code> methods in any way; these methods return the
277      * same binding as before the AST was modified (including modifications
278      * that rearrange subtrees by reparenting nodes).
279      * If <code>setResolveBindings(false)</code> (the default), the analysis
280      * does not go beyond parsing and building the tree, and all
281      * <code>resolveBinding</code> methods return <code>null</code> from the
282      * outset.
283      * </p>
284      * <p>
285      * When bindings are requested, instead of considering compilation units on disk only
286      * one can supply a <code>WorkingCopyOwner</code>. Working copies owned
287      * by this owner take precedence over the underlying compilation units when looking
288      * up names and drawing the connections.
289      * </p>
290      * <p>
291      * Binding information is obtained from the Java model.
292      * This means that the compilation unit must be located relative to the
293      * Java model. This happens automatically when the source code comes from
294      * either {@link #setSource(ICompilationUnit) setSource(ICompilationUnit)}
295      * or {@link #setSource(IClassFile) setSource(IClassFile)}.
296      * When source is supplied by {@link #setSource(char[]) setSource(char[])},
297      * the location must be extablished explicitly by calling
298      * {@link #setProject(IJavaProject)} and {@link #setUnitName(String)}.
299      * Note that the compiler options that affect doc comment checking may also
300      * affect whether any bindings are resolved for nodes within doc comments.
301      * </p>
302      *
303      * @param bindings <code>true</code> if bindings are wanted,
304      * and <code>false</code> if bindings are not of interest
305      */

306     public void setResolveBindings(boolean bindings) {
307       this.resolveBindings = bindings;
308     }
309     
310     /**
311      * Requests an abridged abstract syntax tree.
312      * By default, complete ASTs are returned.
313      *
314      * When <code>true</code> the resulting AST does not have nodes for
315      * the entire compilation unit. Rather, the AST is only fleshed out
316      * for the node that include the given source position. This kind of limited
317      * AST is sufficient for certain purposes but totally unsuitable for others.
318      * In places where it can be used, the limited AST offers the advantage of
319      * being smaller and faster to construct.
320      * </p>
321      * <p>
322      * The AST will include nodes for all of the compilation unit's
323      * package, import, and top-level type declarations. It will also always contain
324      * nodes for all the body declarations for those top-level types, as well
325      * as body declarations for any member types. However, some of the body
326      * declarations may be abridged. In particular, the statements ordinarily
327      * found in the body of a method declaration node will not be included
328      * (the block will be empty) unless the source position falls somewhere
329      * within the source range of that method declaration node. The same is true
330      * for initializer declarations; the statements ordinarily found in the body
331      * of initializer node will not be included unless the source position falls
332      * somewhere within the source range of that initializer declaration node.
333      * Field declarations are never abridged. Note that the AST for the body of
334      * that one unabridged method (or initializer) is 100% complete; it has all
335      * its statements, including any local or anonymous type declarations
336      * embedded within them. When the the given position is not located within
337      * the source range of any body declaration of a top-level type, the AST
338      * returned will be a skeleton that includes nodes for all and only the major
339      * declarations; this kind of AST is still quite useful because it contains
340      * all the constructs that introduce names visible to the world outside the
341      * compilation unit.
342      * </p>
343      *
344      * @param position a position into the corresponding body declaration
345      */

346     public void setFocalPosition(int position) {
347         this.partial = true;
348         this.focalPointPosition = position;
349     }
350     
351     /**
352      * Sets the kind of constructs to be parsed from the source.
353      * Defaults to an entire compilation unit.
354      * <p>
355      * When the parse is successful the result returned includes the ASTs for the
356      * requested source:
357      * <ul>
358      * <li>{@link #K_COMPILATION_UNIT K_COMPILATION_UNIT}: The result node
359      * is a {@link CompilationUnit}.</li>
360      * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result node
361      * is a {@link TypeDeclaration} whose
362      * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations}
363      * are the new trees. Other aspects of the type declaration are unspecified.</li>
364      * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a
365      * {@link Block Block} whose {@link Block#statements() statements}
366      * are the new trees. Other aspects of the block are unspecified.</li>
367      * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of
368      * {@link Expression Expression}. Other aspects of the expression are unspecified.</li>
369      * </ul>
370      * The resulting AST node is rooted under (possibly contrived)
371      * {@link CompilationUnit CompilationUnit} node, to allow the
372      * client to retrieve the following pieces of information
373      * available there:
374      * <ul>
375      * <li>{@linkplain CompilationUnit#lineNumber(int) Line number map}. Line
376      * numbers start at 1 and only cover the subrange scanned
377      * (<code>source[offset]</code> through <code>source[offset+length-1]</code>).</li>
378      * <li>{@linkplain CompilationUnit#getMessages() Compiler messages}
379      * and {@linkplain CompilationUnit#getProblems() detailed problem reports}.
380      * Character positions are relative to the start of
381      * <code>source</code>; line positions are for the subrange scanned.</li>
382      * <li>{@linkplain CompilationUnit#getCommentList() Comment list}
383      * for the subrange scanned.</li>
384      * </ul>
385      * The contrived nodes do not have source positions. Other aspects of the
386      * {@link CompilationUnit CompilationUnit} node are unspecified, including
387      * the exact arrangment of intervening nodes.
388      * </p>
389      * <p>
390      * Lexical or syntax errors detected while parsing can result in
391      * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}.
392      * In more severe failure cases where the parser is unable to
393      * recognize the input, this method returns
394      * a {@link CompilationUnit CompilationUnit} node with at least the
395      * compiler messages.
396      * </p>
397      * <p>Each node in the subtree (other than the contrived nodes)
398      * carries source range(s) information relating back
399      * to positions in the given source (the given source itself
400      * is not remembered with the AST).
401      * The source range usually begins at the first character of the first token
402      * corresponding to the node; leading whitespace and comments are <b>not</b>
403      * included. The source range usually extends through the last character of
404      * the last token corresponding to the node; trailing whitespace and
405      * comments are <b>not</b> included. There are a handful of exceptions
406      * (including the various body declarations); the
407      * specification for these node type spells out the details.
408      * Source ranges nest properly: the source range for a child is always
409      * within the source range of its parent, and the source ranges of sibling
410      * nodes never overlap.
411      * </p>
412      * <p>
413      * Binding information is only computed when <code>kind</code> is
414      * <code>K_COMPILATION_UNIT</code>.
415      * </p>
416      *
417      * @param kind the kind of construct to parse: one of
418      * {@link #K_COMPILATION_UNIT},
419      * {@link #K_CLASS_BODY_DECLARATIONS},
420      * {@link #K_EXPRESSION},
421      * {@link #K_STATEMENTS}
422      */

423     public void setKind(int kind) {
424         if ((kind != K_COMPILATION_UNIT)
425             && (kind != K_CLASS_BODY_DECLARATIONS)
426             && (kind != K_EXPRESSION)
427             && (kind != K_STATEMENTS)) {
428             throw new IllegalArgumentException JavaDoc();
429         }
430         this.astKind = kind;
431     }
432     
433     /**
434      * Sets the source code to be parsed.
435      *
436      * @param source the source string to be parsed,
437      * or <code>null</code> if none
438      */

439     public void setSource(char[] source) {
440         this.rawSource = source;
441         // clear the others
442
this.compilationUnitSource = null;
443         this.classFileSource = null;
444     }
445
446     /**
447      * Sets the source code to be parsed.
448      * This method automatically sets the project (and compiler
449      * options) based on the given compilation unit, in a manner
450      * equivalent to <code>setProject(source.getJavaProject())</code>
451      *
452      * @param source the Java model compilation unit whose source code
453      * is to be parsed, or <code>null</code> if none
454       */

455     public void setSource(ICompilationUnit source) {
456         this.compilationUnitSource = source;
457         // clear the others
458
this.rawSource = null;
459         this.classFileSource = null;
460         if (source != null) {
461             this.project = source.getJavaProject();
462             this.compilerOptions = this.project.getOptions(true);
463         }
464     }
465     
466     /**
467      * Sets the source code to be parsed.
468      * This method automatically sets the project (and compiler
469      * options) based on the given compilation unit, in a manner
470      * equivalent to <code>setProject(source.getJavaProject())</code>
471      *
472      * @param source the Java model class file whose corresponding source code
473      * is to be parsed, or <code>null</code> if none
474      */

475     public void setSource(IClassFile source) {
476         this.classFileSource = source;
477         // clear the others
478
this.rawSource = null;
479         this.compilationUnitSource = null;
480         if (source != null) {
481             this.project = source.getJavaProject();
482             this.compilerOptions = this.project.getOptions(true);
483         }
484     }
485     
486     /**
487      * Sets the subrange of the source code to be parsed.
488      * By default, the entire source string will be parsed
489      * (<code>offset</code> 0 and <code>length</code> -1).
490      *
491      * @param offset the index of the first character to parse
492      * @param length the number of characters to parse, or -1 if
493      * the remainder of the source string is
494      */

495     public void setSourceRange(int offset, int length) {
496         if (offset < 0 || length < -1) {
497             throw new IllegalArgumentException JavaDoc();
498         }
499         this.sourceOffset = offset;
500         this.sourceLength = length;
501     }
502     
503     /**
504      * Sets the working copy owner using when resolving bindings, where
505      * <code>null</code> means the primary owner. Defaults to the primary owner.
506      *
507      * @param owner the owner of working copies that take precedence over underlying
508      * compilation units, or <code>null</code> if the primary owner should be used
509      */

510     public void setWorkingCopyOwner(WorkingCopyOwner owner) {
511         if (owner == null) {
512             this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY;
513         } else {
514             this.workingCopyOwner = owner;
515         }
516     }
517
518     /**
519      * Sets the name of the compilation unit that would hypothetically contains
520      * the source string. This is used in conjunction with
521      * <code>setSource(char[])</code> and <code>setProject</code> to locate the
522      * compilation unit relative to a Java project.
523      * Defaults to none (<code>null</code>).
524      * <p>
525      * The name of the compilation unit must be supplied for resolving bindings.
526      * This name should include the ".java" suffix and match the name of the main
527      * (public) class or interface declared in the source. For example, if the source
528      * declares a public class named "Foo", the name of the compilation should be
529      * "Foo.java".
530      * </p>
531      *
532      * @param unitName the name of the compilation unit that would contain the source
533      * string, or <code>null</code> if none
534      */

535     public void setUnitName(String JavaDoc unitName) {
536         this.unitName = unitName;
537     }
538     
539     /**
540      * Sets the Java project used when resolving bindings.
541      * This method automatically sets the compiler
542      * options based on the given project:
543      * <pre>
544      * setCompilerOptions(project.getOptions(true));
545      * </pre>
546      * See {@link #setCompilerOptions(Map)} for a discussion of
547      * the pros and cons of using these options vs specifying
548      * compiler options explicitly.
549      * This setting is used in conjunction with <code>setSource(char[])</code>.
550      * For the purposes of resolving bindings, types declared in the
551      * source string will hide types by the same name available
552      * through the classpath of the given project.
553      * Defaults to none (<code>null</code>).
554      *
555      * @param project the Java project used to resolve names, or
556      * <code>null</code> if none
557      */

558     public void setProject(IJavaProject project) {
559         this.project = project;
560         if (project != null) {
561             this.compilerOptions = project.getOptions(true);
562         }
563     }
564     
565     /**
566      * Creates an abstract syntax tree.
567      * <p>
568      * A successful call to this method returns all settings to their
569      * default values so the object is ready to be reused.
570      * </p>
571      *
572      * @param monitor the progress monitor used to report progress and request cancelation,
573      * or <code>null</code> if none
574      * @return an AST node whose type depends on the kind of parse
575      * requested, with a fallback to a <code>CompilationUnit</code>
576      * in the case of severe parsing errors
577      * @exception IllegalStateException if the settings provided
578      * are insufficient, contradictory, or otherwise unsupported
579      */

580     public ASTNode createAST(IProgressMonitor monitor) {
581        ASTNode result = null;
582         try {
583             if ((this.rawSource == null)
584               && (this.compilationUnitSource == null)
585               && (this.classFileSource == null)) {
586               throw new IllegalStateException JavaDoc("source not specified"); //$NON-NLS-1$
587
}
588             result = internalCreateAST(monitor);
589         } finally {
590            // re-init defaults to allow reuse (and avoid leaking)
591
initializeDefaults();
592         }
593        return result;
594     }
595     
596     /**
597      * Creates ASTs for a batch of compilation units.
598      * When bindings are being resolved, processing a
599      * batch of compilation units is more efficient because much
600      * of the work involved in resolving bindings can be shared.
601      * <p>
602      * When bindings are being resolved, all compilation units must
603      * come from the same Java project, which must be set beforehand
604      * with <code>setProject</code>.
605      * The compilation units are processed one at a time in no
606      * specified order. For each of the compilation units in turn,
607      * <ul>
608      * <li><code>ASTParser.createAST</code> is called to parse it
609      * and create a corresponding AST. The calls to
610      * <code>ASTParser.createAST</code> all employ the same settings.</li>
611      * <li><code>ASTRequestor.acceptAST</code> is called passing
612      * the compilation unit and the corresponding AST to
613      * <code>requestor</code>.
614      * </li>
615      * </ul>
616      * Note only ASTs from the given compilation units are reported
617      * to the requestor. If additional compilation units are required to
618      * resolve the original ones, the corresponding ASTs are <b>not</b>
619      * reported to the requestor.
620      * </p>
621      * <p>
622      * Note also the following parser parameters are used, regardless of what
623      * may have been specified:
624      * <ul>
625      * <li>The {@linkplain #setKind(int) parser kind} is <code>K_COMPILATION_UNIT</code></li>
626      * <li>The {@linkplain #setSourceRange(int,int) source range} is <code>(0, -1)</code></li>
627      * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li>
628      * </ul>
629      * </p>
630      * <p>
631      * The <code>bindingKeys</code> parameter specifies bindings keys
632      * ({@link IBinding#getKey()}) that are to be looked up. These keys may
633      * be for elements either inside or outside the set of compilation
634      * units being processed. When bindings are being resolved,
635      * the keys and corresponding bindings (or <code>null</code> if none) are
636      * passed to <code>ASTRequestor.acceptBinding</code>. Note that binding keys
637      * for elements outside the set of compilation units being processed are looked up
638      * after all <code>ASTRequestor.acceptAST</code> callbacks have been made.
639      * Binding keys for elements inside the set of compilation units being processed
640      * are looked up and reported right after the corresponding
641      * <code>ASTRequestor.acceptAST</code> callback has been made.
642      * No <code>ASTRequestor.acceptBinding</code> callbacks are made unless
643      * bindings are being resolved.
644      * </p>
645      * <p>
646      * A successful call to this method returns all settings to their
647      * default values so the object is ready to be reused.
648      * </p>
649      *
650      * @param compilationUnits the compilation units to create ASTs for
651      * @param bindingKeys the binding keys to create bindings for
652      * @param requestor the AST requestor that collects abtract syntax trees and bindings
653      * @param monitor the progress monitor used to report progress and request cancelation,
654      * or <code>null</code> if none
655      * @exception IllegalStateException if the settings provided
656      * are insufficient, contradictory, or otherwise unsupported
657      * @since 3.1
658      */

659     public void createASTs(ICompilationUnit[] compilationUnits, String JavaDoc[] bindingKeys, ASTRequestor requestor, IProgressMonitor monitor) {
660         try {
661             if (this.resolveBindings) {
662                 if (this.project == null)
663                     throw new IllegalStateException JavaDoc("project not specified"); //$NON-NLS-1$
664
CompilationUnitResolver.resolve(compilationUnits, bindingKeys, requestor, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, monitor);
665             } else {
666                 CompilationUnitResolver.parse(compilationUnits, requestor, this.apiLevel, this.compilerOptions, monitor);
667             }
668         } finally {
669            // re-init defaults to allow reuse (and avoid leaking)
670
initializeDefaults();
671         }
672     }
673     
674     /**
675      * Creates bindings for a batch of Java elements. These elements are either
676      * enclosed in {@link ICompilationUnit}s or in {@link IClassFile}s.
677      * <p>
678      * All enclosing compilation units and class files must
679      * come from the same Java project, which must be set beforehand
680      * with <code>setProject</code>.
681      * </p>
682      * <p>
683      * All elements must exist. If one doesn't exist, an <code>IllegalStateException</code>
684      * is thrown.
685      * </p>
686      * <p>
687      * The returned array has the same size as the given elements array. At a given position
688      * it contains the binding of the corresponding Java element, or <code>null</code>
689      * if no binding could be created.
690      * </p>
691      * <p>
692      * Note also the following parser parameters are used, regardless of what
693      * may have been specified:
694      * <ul>
695      * <li>The {@linkplain #setResolveBindings(boolean) binding resolution flag} is <code>true</code<</li>
696      * <li>The {@linkplain #setKind(int) parser kind} is <code>K_COMPILATION_UNIT</code></li>
697      * <li>The {@linkplain #setSourceRange(int,int) source range} is <code>(0, -1)</code></li>
698      * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li>
699      * </ul>
700      * </p>
701      * <p>
702      * A successful call to this method returns all settings to their
703      * default values so the object is ready to be reused.
704      * </p>
705      *
706      * @param elements the Java elements to create bindings for
707      * @return the bindings for the given Java elements, possibly containing <code>null</code>s
708      * if some bindings could not be created
709      * @exception IllegalStateException if the settings provided
710      * are insufficient, contradictory, or otherwise unsupported
711      * @since 3.1
712      */

713     public IBinding[] createBindings(IJavaElement[] elements, IProgressMonitor monitor) {
714         try {
715             if (this.project == null)
716                 throw new IllegalStateException JavaDoc("project not specified"); //$NON-NLS-1$
717
return CompilationUnitResolver.resolve(elements, this.apiLevel, this.compilerOptions, this.project, this.workingCopyOwner, monitor);
718         } finally {
719            // re-init defaults to allow reuse (and avoid leaking)
720
initializeDefaults();
721         }
722     }
723     
724     private ASTNode internalCreateAST(IProgressMonitor monitor) {
725         boolean needToResolveBindings = this.resolveBindings;
726         switch(this.astKind) {
727             case K_CLASS_BODY_DECLARATIONS :
728             case K_EXPRESSION :
729             case K_STATEMENTS :
730                 if (this.rawSource != null) {
731                     if (this.sourceOffset + this.sourceLength > this.rawSource.length) {
732                         throw new IllegalStateException JavaDoc();
733                     }
734                     return internalCreateASTForKind();
735                 }
736                 break;
737             case K_COMPILATION_UNIT :
738                 CompilationUnitDeclaration compilationUnitDeclaration = null;
739                 try {
740                     NodeSearcher searcher = null;
741                     org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = null;
742                     IJavaElement element = null;
743                     if (this.compilationUnitSource != null) {
744                         sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) this.compilationUnitSource;
745                         // use a BasicCompilation that caches the source instead of using the compilationUnitSource directly
746
// (if it is a working copy, the source can change between the parse and the AST convertion)
747
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=75632)
748
sourceUnit = new BasicCompilationUnit(sourceUnit.getContents(), sourceUnit.getPackageName(), new String JavaDoc(sourceUnit.getFileName()), this.project);
749                         element = this.compilationUnitSource;
750                     } else if (this.classFileSource != null) {
751                         try {
752                             String JavaDoc sourceString = this.classFileSource.getSource();
753                             if (sourceString == null) {
754                                 throw new IllegalStateException JavaDoc();
755                             }
756                             PackageFragment packageFragment = (PackageFragment) this.classFileSource.getParent();
757                             BinaryType type = (BinaryType) this.classFileSource.getType();
758                             IBinaryType binaryType = (IBinaryType) type.getElementInfo();
759                             String JavaDoc fileName = new String JavaDoc(binaryType.getFileName()); // file name is used to recreate the Java element, so it has to be the .class file name
760
sourceUnit = new BasicCompilationUnit(sourceString.toCharArray(), Util.toCharArrays(packageFragment.names), fileName, this.project);
761                             element = this.classFileSource;
762                         } catch(JavaModelException e) {
763                             // an error occured accessing the java element
764
throw new IllegalStateException JavaDoc();
765                         }
766                     } else if (this.rawSource != null) {
767                         needToResolveBindings = this.unitName != null && this.project != null && this.compilerOptions != null;
768                         sourceUnit = new BasicCompilationUnit(this.rawSource, null, this.unitName == null ? "" : this.unitName, this.project); //$NON-NLS-1$
769
} else {
770                         throw new IllegalStateException JavaDoc();
771                     }
772                     if (this.partial) {
773                         searcher = new NodeSearcher(this.focalPointPosition);
774                     }
775                     if (needToResolveBindings && this.project != null) {
776                         try {
777                             // parse and resolve
778
compilationUnitDeclaration =
779                                 CompilationUnitResolver.resolve(
780                                     sourceUnit,
781                                     this.project,
782                                     searcher,
783                                     this.compilerOptions,
784                                     this.workingCopyOwner,
785                                     monitor);
786                         } catch (JavaModelException e) {
787                             compilationUnitDeclaration = CompilationUnitResolver.parse(
788                                     sourceUnit,
789                                     searcher,
790                                     this.compilerOptions);
791                             needToResolveBindings = false;
792                         }
793                     } else {
794                         compilationUnitDeclaration = CompilationUnitResolver.parse(
795                                 sourceUnit,
796                                 searcher,
797                                 this.compilerOptions);
798                         needToResolveBindings = false;
799                     }
800                     CompilationUnit result = CompilationUnitResolver.convert(
801                         compilationUnitDeclaration,
802                         sourceUnit.getContents(),
803                         this.apiLevel,
804                         this.compilerOptions,
805                         needToResolveBindings,
806                         this.compilationUnitSource == null ? this.workingCopyOwner : this.compilationUnitSource.getOwner(),
807                         needToResolveBindings ? new DefaultBindingResolver.BindingTables() : null,
808                         monitor);
809                     result.setJavaElement(element);
810                     return result;
811                 } finally {
812                     if (compilationUnitDeclaration != null && this.resolveBindings) {
813                         compilationUnitDeclaration.cleanUp();
814                     }
815                 }
816         }
817         throw new IllegalStateException JavaDoc();
818     }
819     
820     /**
821      * Parses the given source between the bounds specified by the given offset (inclusive)
822      * and the given length and creates and returns a corresponding abstract syntax tree.
823      * <p>
824      * When the parse is successful the result returned includes the ASTs for the
825      * requested source:
826      * <ul>
827      * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result node
828      * is a {@link TypeDeclaration TypeDeclaration} whose
829      * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations}
830      * are the new trees. Other aspects of the type declaration are unspecified.</li>
831      * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a
832      * {@link Block Block} whose {@link Block#statements() statements}
833      * are the new trees. Other aspects of the block are unspecified.</li>
834      * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of
835      * {@link Expression Expression}. Other aspects of the expression are unspecified.</li>
836      * </ul>
837      * The resulting AST node is rooted under an contrived
838      * {@link CompilationUnit CompilationUnit} node, to allow the
839      * client to retrieve the following pieces of information
840      * available there:
841      * <ul>
842      * <li>{@linkplain CompilationUnit#lineNumber(int) Line number map}. Line
843      * numbers start at 1 and only cover the subrange scanned
844      * (<code>source[offset]</code> through <code>source[offset+length-1]</code>).</li>
845      * <li>{@linkplain CompilationUnit#getMessages() Compiler messages}
846      * and {@linkplain CompilationUnit#getProblems() detailed problem reports}.
847      * Character positions are relative to the start of
848      * <code>source</code>; line positions are for the subrange scanned.</li>
849      * <li>{@linkplain CompilationUnit#getCommentList() Comment list}
850      * for the subrange scanned.</li>
851      * </ul>
852      * The contrived nodes do not have source positions. Other aspects of the
853      * {@link CompilationUnit CompilationUnit} node are unspecified, including
854      * the exact arrangment of intervening nodes.
855      * </p>
856      * <p>
857      * Lexical or syntax errors detected while parsing can result in
858      * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}.
859      * In more severe failure cases where the parser is unable to
860      * recognize the input, this method returns
861      * a {@link CompilationUnit CompilationUnit} node with at least the
862      * compiler messages.
863      * </p>
864      * <p>Each node in the subtree (other than the contrived nodes)
865      * carries source range(s) information relating back
866      * to positions in the given source (the given source itself
867      * is not remembered with the AST).
868      * The source range usually begins at the first character of the first token
869      * corresponding to the node; leading whitespace and comments are <b>not</b>
870      * included. The source range usually extends through the last character of
871      * the last token corresponding to the node; trailing whitespace and
872      * comments are <b>not</b> included. There are a handful of exceptions
873      * (including the various body declarations); the
874      * specification for these node type spells out the details.
875      * Source ranges nest properly: the source range for a child is always
876      * within the source range of its parent, and the source ranges of sibling
877      * nodes never overlap.
878      * </p>
879      * <p>
880      * This method does not compute binding information; all <code>resolveBinding</code>
881      * methods applied to nodes of the resulting AST return <code>null</code>.
882      * </p>
883      *
884      * @return an AST node whose type depends on the kind of parse
885      * requested, with a fallback to a <code>CompilationUnit</code>
886      * in the case of severe parsing errors
887      * @see ASTNode#getStartPosition()
888      * @see ASTNode#getLength()
889      */

890     private ASTNode internalCreateASTForKind() {
891         final ASTConverter converter = new ASTConverter(this.compilerOptions, false, null);
892         converter.compilationUnitSource = this.rawSource;
893         converter.compilationUnitSourceLength = this.rawSource.length;
894         converter.scanner.setSource(this.rawSource);
895         
896         AST ast = AST.newAST(this.apiLevel);
897         ast.setDefaultNodeFlag(ASTNode.ORIGINAL);
898         ast.setBindingResolver(new BindingResolver());
899         converter.setAST(ast);
900         CodeSnippetParsingUtil codeSnippetParsingUtil = new CodeSnippetParsingUtil();
901         CompilationUnit compilationUnit = ast.newCompilationUnit();
902         if (this.sourceLength == -1) {
903             this.sourceLength = this.rawSource.length;
904         }
905         switch(this.astKind) {
906             case K_STATEMENTS :
907                 ConstructorDeclaration constructorDeclaration = codeSnippetParsingUtil.parseStatements(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true);
908                 RecordedParsingInformation recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation;
909                 int[][] comments = recordedParsingInformation.commentPositions;
910                 if (comments != null) {
911                     converter.buildCommentsTable(compilationUnit, comments);
912                 }
913                 compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds);
914                 if (constructorDeclaration != null) {
915                     Block block = ast.newBlock();
916                     Statement[] statements = constructorDeclaration.statements;
917                     if (statements != null) {
918                         int statementsLength = statements.length;
919                         for (int i = 0; i < statementsLength; i++) {
920                             block.statements().add(converter.convert(statements[i]));
921                         }
922                     }
923                     rootNodeToCompilationUnit(ast, compilationUnit, block, recordedParsingInformation);
924                     ast.setDefaultNodeFlag(0);
925                     ast.setOriginalModificationCount(ast.modificationCount());
926                     return block;
927                 } else {
928                     IProblem[] problems = recordedParsingInformation.problems;
929                     if (problems != null) {
930                         compilationUnit.setProblems(problems);
931                     }
932                     ast.setDefaultNodeFlag(0);
933                     ast.setOriginalModificationCount(ast.modificationCount());
934                     return compilationUnit;
935                 }
936             case K_EXPRESSION :
937                 org.eclipse.jdt.internal.compiler.ast.Expression expression = codeSnippetParsingUtil.parseExpression(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true);
938                 recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation;
939                 comments = recordedParsingInformation.commentPositions;
940                 if (comments != null) {
941                     converter.buildCommentsTable(compilationUnit, comments);
942                 }
943                 compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds);
944                 if (expression != null) {
945                     Expression expression2 = converter.convert(expression);
946                     rootNodeToCompilationUnit(expression2.getAST(), compilationUnit, expression2, codeSnippetParsingUtil.recordedParsingInformation);
947                     ast.setDefaultNodeFlag(0);
948                     ast.setOriginalModificationCount(ast.modificationCount());
949                     return expression2;
950                 } else {
951                     IProblem[] problems = recordedParsingInformation.problems;
952                     if (problems != null) {
953                         compilationUnit.setProblems(problems);
954                     }
955                     ast.setDefaultNodeFlag(0);
956                     ast.setOriginalModificationCount(ast.modificationCount());
957                     return compilationUnit;
958                 }
959             case K_CLASS_BODY_DECLARATIONS :
960                 final org.eclipse.jdt.internal.compiler.ast.ASTNode[] nodes = codeSnippetParsingUtil.parseClassBodyDeclarations(this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true);
961                 recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation;
962                 comments = recordedParsingInformation.commentPositions;
963                 if (comments != null) {
964                     converter.buildCommentsTable(compilationUnit, comments);
965                 }
966                 compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds);
967                 if (nodes != null) {
968                     TypeDeclaration typeDeclaration = converter.convert(nodes);
969                     rootNodeToCompilationUnit(typeDeclaration.getAST(), compilationUnit, typeDeclaration, codeSnippetParsingUtil.recordedParsingInformation);
970                     ast.setDefaultNodeFlag(0);
971                     ast.setOriginalModificationCount(ast.modificationCount());
972                     return typeDeclaration;
973                 } else {
974                     IProblem[] problems = recordedParsingInformation.problems;
975                     if (problems != null) {
976                         compilationUnit.setProblems(problems);
977                     }
978                     ast.setDefaultNodeFlag(0);
979                     ast.setOriginalModificationCount(ast.modificationCount());
980                     return compilationUnit;
981                 }
982         }
983         throw new IllegalStateException JavaDoc();
984     }
985
986     private void propagateErrors(ASTNode astNode, IProblem[] problems) {
987         ASTSyntaxErrorPropagator syntaxErrorPropagator = new ASTSyntaxErrorPropagator(problems);
988         astNode.accept(syntaxErrorPropagator);
989     }
990     
991     private void rootNodeToCompilationUnit(AST ast, CompilationUnit compilationUnit, ASTNode node, RecordedParsingInformation recordedParsingInformation) {
992         final int problemsCount = recordedParsingInformation.problemsCount;
993         switch(node.getNodeType()) {
994             case ASTNode.BLOCK :
995                 {
996                     Block block = (Block) node;
997                     if (problemsCount != 0) {
998                         // propagate and record problems
999
final IProblem[] problems = recordedParsingInformation.problems;
1000                        for (int i = 0, max = block.statements().size(); i < max; i++) {
1001                            propagateErrors((ASTNode) block.statements().get(i), problems);
1002                        }
1003                        compilationUnit.setProblems(problems);
1004                    }
1005                    TypeDeclaration typeDeclaration = ast.newTypeDeclaration();
1006                    Initializer initializer = ast.newInitializer();
1007                    initializer.setBody(block);
1008                    typeDeclaration.bodyDeclarations().add(initializer);
1009                    compilationUnit.types().add(typeDeclaration);
1010                }
1011                break;
1012            case ASTNode.TYPE_DECLARATION :
1013                {
1014                    TypeDeclaration typeDeclaration = (TypeDeclaration) node;
1015                    if (problemsCount != 0) {
1016                        // propagate and record problems
1017
final IProblem[] problems = recordedParsingInformation.problems;
1018                        for (int i = 0, max = typeDeclaration.bodyDeclarations().size(); i < max; i++) {
1019                            propagateErrors((ASTNode) typeDeclaration.bodyDeclarations().get(i), problems);
1020                        }
1021                        compilationUnit.setProblems(problems);
1022                    }
1023                    compilationUnit.types().add(typeDeclaration);
1024                }
1025                break;
1026            default :
1027                if (node instanceof Expression) {
1028                    Expression expression = (Expression) node;
1029                    if (problemsCount != 0) {
1030                        // propagate and record problems
1031
final IProblem[] problems = recordedParsingInformation.problems;
1032                        propagateErrors(expression, problems);
1033                        compilationUnit.setProblems(problems);
1034                    }
1035                    ExpressionStatement expressionStatement = ast.newExpressionStatement(expression);
1036                    Block block = ast.newBlock();
1037                    block.statements().add(expressionStatement);
1038                    Initializer initializer = ast.newInitializer();
1039                    initializer.setBody(block);
1040                    TypeDeclaration typeDeclaration = ast.newTypeDeclaration();
1041                    typeDeclaration.bodyDeclarations().add(initializer);
1042                    compilationUnit.types().add(typeDeclaration);
1043                }
1044        }
1045    }
1046}
1047
Popular Tags