1 | /******************************************************************************* |
---|---|
2 | * Copyright (c) 2004, 2022 IBM Corporation and others. |
3 | * |
4 | * This program and the accompanying materials |
5 | * are made available under the terms of the Eclipse Public License 2.0 |
6 | * which accompanies this distribution, and is available at |
7 | * https://www.eclipse.org/legal/epl-2.0/ |
8 | * |
9 | * SPDX-License-Identifier: EPL-2.0 |
10 | * |
11 | * Contributors: |
12 | * IBM Corporation - initial API and implementation |
13 | * Stephan Herrmann - Contribution for |
14 | * Bug 458577 - IClassFile.getWorkingCopy() may lead to NPE in BecomeWorkingCopyOperation |
15 | *******************************************************************************/ |
16 | package org.eclipse.jdt.core.dom; |
17 | |
18 | import java.io.PrintWriter; |
19 | import java.io.StringWriter; |
20 | import java.util.ArrayList; |
21 | import java.util.HashMap; |
22 | import java.util.List; |
23 | import java.util.Map; |
24 | |
25 | import org.eclipse.core.runtime.IProgressMonitor; |
26 | import org.eclipse.core.runtime.SubMonitor; |
27 | import org.eclipse.jdt.core.IClassFile; |
28 | import org.eclipse.jdt.core.ICompilationUnit; |
29 | import org.eclipse.jdt.core.IJavaElement; |
30 | import org.eclipse.jdt.core.IJavaProject; |
31 | import org.eclipse.jdt.core.ITypeRoot; |
32 | import org.eclipse.jdt.core.JavaCore; |
33 | import org.eclipse.jdt.core.JavaModelException; |
34 | import org.eclipse.jdt.core.WorkingCopyOwner; |
35 | import org.eclipse.jdt.core.compiler.CategorizedProblem; |
36 | import org.eclipse.jdt.core.compiler.CharOperation; |
37 | import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration; |
38 | import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; |
39 | import org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall; |
40 | import org.eclipse.jdt.internal.compiler.batch.FileSystem.Classpath; |
41 | import org.eclipse.jdt.internal.compiler.batch.Main; |
42 | import org.eclipse.jdt.internal.compiler.env.IBinaryType; |
43 | import org.eclipse.jdt.internal.compiler.parser.RecoveryScanner; |
44 | import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData; |
45 | import org.eclipse.jdt.internal.compiler.parser.Scanner; |
46 | import org.eclipse.jdt.internal.compiler.util.SuffixConstants; |
47 | import org.eclipse.jdt.internal.core.BasicCompilationUnit; |
48 | import org.eclipse.jdt.internal.core.BinaryType; |
49 | import org.eclipse.jdt.internal.core.ClassFileWorkingCopy; |
50 | import org.eclipse.jdt.internal.core.DefaultWorkingCopyOwner; |
51 | import org.eclipse.jdt.internal.core.PackageFragment; |
52 | import org.eclipse.jdt.internal.core.dom.util.DOMASTUtil; |
53 | import org.eclipse.jdt.internal.core.util.CodeSnippetParsingUtil; |
54 | import org.eclipse.jdt.internal.core.util.RecordedParsingInformation; |
55 | import org.eclipse.jdt.internal.core.util.Util; |
56 | |
57 | /** |
58 | * A Java language parser for creating abstract syntax trees (ASTs). |
59 | * <p> |
60 | * Example: Create basic AST from source string |
61 | * |
62 | * <pre> |
63 | * char[] source = ...; |
64 | * ASTParser parser = ASTParser.newParser(AST.JLS3); // handles JDK 1.0, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6 |
65 | * parser.setSource(source); |
66 | * // In order to parse 1.5 code, some compiler options need to be set to 1.5 |
67 | * Map options = JavaCore.getOptions(); |
68 | * JavaCore.setComplianceOptions(JavaCore.VERSION_1_5, options); |
69 | * parser.setCompilerOptions(options); |
70 | * CompilationUnit result = (CompilationUnit) parser.createAST(null); |
71 | * </pre> |
72 | * <p> |
73 | * Once a configured parser instance has been used to create an AST, |
74 | * the settings are automatically reset to their defaults, |
75 | * ready for the parser instance to be reused. |
76 | * </p> |
77 | * <p> |
78 | * There are a number of configurable features: |
79 | * <ul> |
80 | * <li>Source string from {@link #setSource(char[]) char[]}, |
81 | * {@link #setSource(ICompilationUnit) ICompilationUnit}, |
82 | * or {@link #setSource(IClassFile) IClassFile}, and limited |
83 | * to a specified {@linkplain #setSourceRange(int,int) subrange}.</li> |
84 | * <li>Whether {@linkplain #setResolveBindings(boolean) bindings} will be |
85 | * created.</li> |
86 | * <li>Which {@linkplain #setWorkingCopyOwner(WorkingCopyOwner) |
87 | * working copy owner} to use when resolving bindings.</li> |
88 | * <li>A hypothetical {@linkplain #setUnitName(String) compilation unit file |
89 | * name} |
90 | * and {@linkplain #setProject(IJavaProject) Java project} |
91 | * for locating a raw source string in the Java model (when |
92 | * resolving bindings)</li> |
93 | * <li>Which {@linkplain #setCompilerOptions(Map) compiler options} |
94 | * to use. This is especially important to use if the parsing/scanning of the |
95 | * source code requires a |
96 | * different version than the default of the workspace. For example, the |
97 | * workspace defaults are 1.4 and |
98 | * you want to create an AST for a source code that is using 1.5 |
99 | * constructs.</li> |
100 | * <li>Whether to parse just {@linkplain #setKind(int) an expression, |
101 | * statements, |
102 | * or body declarations} rather than an entire compilation unit.</li> |
103 | * <li>Whether to return a {@linkplain #setFocalPosition(int) abridged AST} |
104 | * focused on the declaration containing a given source position.</li> |
105 | * </ul> |
106 | * |
107 | * @since 3.0 |
108 | * @noinstantiate This class is not intended to be instantiated by clients. |
109 | */ |
110 | @SuppressWarnings({ "rawtypes" }) |
111 | public class ASTParser { |
112 | |
113 | /** |
114 | * Kind constant used to request that the source be parsed |
115 | * as a single expression. |
116 | */ |
117 | public static final int K_EXPRESSION = 0x01; |
118 | |
119 | /** |
120 | * Kind constant used to request that the source be parsed |
121 | * as a sequence of statements. |
122 | */ |
123 | public static final int K_STATEMENTS = 0x02; |
124 | |
125 | /** |
126 | * Kind constant used to request that the source be parsed |
127 | * as a sequence of class body declarations. |
128 | */ |
129 | public static final int K_CLASS_BODY_DECLARATIONS = 0x04; |
130 | |
131 | /** |
132 | * Kind constant used to request that the source be parsed |
133 | * as a compilation unit. |
134 | */ |
135 | public static final int K_COMPILATION_UNIT = 0x08; |
136 | |
137 | /** |
138 | * Creates a new object for creating a Java abstract syntax tree |
139 | * (AST) following the specified set of API rules. |
140 | * |
141 | * @param level the API level; one of the <code>.JLS*</code> level constants |
142 | * declared on {@link AST} |
143 | * @return new ASTParser instance |
144 | */ |
145 | public static ASTParser newParser(int level) { |
146 | return new ASTParser(level); |
147 | } |
148 | |
149 | /** |
150 | * Level of AST API desired. |
151 | */ |
152 | private final int apiLevel; |
153 | |
154 | /** |
155 | * Kind of parse requested. Defaults to an entire compilation unit. |
156 | */ |
157 | private int astKind; |
158 | |
159 | /** |
160 | * Compiler options. Defaults to JavaCore.getOptions(). |
161 | */ |
162 | private Map<String, String> compilerOptions; |
163 | |
164 | /** |
165 | * The focal point for a partial AST request. |
166 | * Only used when <code>partial</code> is <code>true</code>. |
167 | */ |
168 | private int focalPointPosition; |
169 | |
170 | /** |
171 | * Source string. |
172 | */ |
173 | private char[] rawSource = null; |
174 | |
175 | /** |
176 | * Java model class file or compilation unit supplying the source. |
177 | */ |
178 | private ITypeRoot typeRoot = null; |
179 | |
180 | /** |
181 | * Character-based offset into the source string where parsing is to |
182 | * begin. Defaults to 0. |
183 | */ |
184 | private int sourceOffset = 0; |
185 | |
186 | /** |
187 | * Character-based length limit, or -1 if unlimited. |
188 | * All characters in the source string between <code>offset</code> |
189 | * and <code>offset+length-1</code> inclusive are parsed. Defaults to -1, |
190 | * which means the rest of the source string. |
191 | */ |
192 | private int sourceLength = -1; |
193 | |
194 | /** |
195 | * Working copy owner. Defaults to primary owner. |
196 | */ |
197 | private WorkingCopyOwner workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY; |
198 | |
199 | /** |
200 | * Java project used to resolve names, or <code>null</code> if none. |
201 | * Defaults to none. |
202 | */ |
203 | private IJavaProject project = null; |
204 | |
205 | /** |
206 | * Name of the compilation unit for resolving bindings, or |
207 | * <code>null</code> if none. Defaults to none. |
208 | */ |
209 | private String unitName = null; |
210 | |
211 | /** |
212 | * Classpath entries to use to resolve bindings when no java project are |
213 | * available. |
214 | */ |
215 | private String[] classpaths; |
216 | |
217 | /** |
218 | * Sourcepath entries to use to resolve bindings when no java project are |
219 | * available. |
220 | */ |
221 | private String[] sourcepaths; |
222 | |
223 | /** |
224 | * Encoding of the given sourcepaths entries. |
225 | */ |
226 | private String[] sourcepathsEncodings; |
227 | |
228 | /** |
229 | * Bits used to set the different values from CompilationUnitResolver values. |
230 | */ |
231 | private int bits; |
232 | |
233 | /** |
234 | * Creates a new AST parser for the given API level. |
235 | * <p> |
236 | * N.B. This constructor is package-private. |
237 | * </p> |
238 | * |
239 | * @param level the API level; one of the <code>JLS*</code> level constants |
240 | * declared on {@link AST} |
241 | */ |
242 | ASTParser(int level) { |
243 | DOMASTUtil.checkASTLevel(level); |
244 | this.apiLevel = level; |
245 | initializeDefaults(); |
246 | } |
247 | |
248 | private List<Classpath> getClasspath() throws IllegalStateException { |
249 | Main main = new Main(new PrintWriter(System.out), new PrintWriter(System.err), false/* systemExit */, |
250 | null/* options */, null/* progress */); |
251 | ArrayList<Classpath> allClasspaths = new ArrayList<Classpath>(); |
252 | try { |
253 | if ((this.bits & CompilationUnitResolver.INCLUDE_RUNNING_VM_BOOTCLASSPATH) != 0) { |
254 | org.eclipse.jdt.internal.compiler.util.Util.collectRunningVMBootclasspath(allClasspaths); |
255 | } |
256 | if (this.sourcepaths != null) { |
257 | for (int i = 0, max = this.sourcepaths.length; i < max; i++) { |
258 | String encoding = this.sourcepathsEncodings == null ? null : this.sourcepathsEncodings[i]; |
259 | main.processPathEntries( |
260 | Main.DEFAULT_SIZE_CLASSPATH, |
261 | allClasspaths, this.sourcepaths[i], encoding, true, false); |
262 | } |
263 | } |
264 | if (this.classpaths != null) { |
265 | for (int i = 0, max = this.classpaths.length; i < max; i++) { |
266 | main.processPathEntries( |
267 | Main.DEFAULT_SIZE_CLASSPATH, |
268 | allClasspaths, this.classpaths[i], null, false, false); |
269 | } |
270 | } |
271 | ArrayList pendingErrors = main.pendingErrors; |
272 | if (pendingErrors != null && pendingErrors.size() != 0) { |
273 | throw new IllegalStateException("invalid environment settings"); //$NON-NLS-1$ |
274 | } |
275 | } catch (IllegalArgumentException e) { |
276 | throw new IllegalStateException("invalid environment settings", e); //$NON-NLS-1$ |
277 | } |
278 | return allClasspaths; |
279 | } |
280 | |
281 | /** |
282 | * Sets all the setting to their default values. |
283 | */ |
284 | private void initializeDefaults() { |
285 | this.astKind = K_COMPILATION_UNIT; |
286 | this.rawSource = null; |
287 | this.typeRoot = null; |
288 | this.bits = 0; |
289 | this.sourceLength = -1; |
290 | this.sourceOffset = 0; |
291 | this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY; |
292 | this.unitName = null; |
293 | this.project = null; |
294 | this.classpaths = null; |
295 | this.sourcepaths = null; |
296 | this.sourcepathsEncodings = null; |
297 | Map<String, String> options = JavaCore.getOptions(); |
298 | options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags |
299 | this.compilerOptions = options; |
300 | } |
301 | |
302 | /** |
303 | * Requests that the compiler should perform bindings recovery. |
304 | * When bindings recovery is enabled the compiler returns incomplete bindings. |
305 | * <p> |
306 | * Default to <code>false</code>. |
307 | * </p> |
308 | * <p> |
309 | * This should be set to true only if bindings are resolved. It has no effect if |
310 | * there is no binding |
311 | * resolution. |
312 | * </p> |
313 | * |
314 | * @param enabled <code>true</code> if incomplete bindings are expected, |
315 | * and <code>false</code> if only complete bindings are expected. |
316 | * |
317 | * @see IBinding#isRecovered() |
318 | * @since 3.3 |
319 | */ |
320 | public void setBindingsRecovery(boolean enabled) { |
321 | if (enabled) { |
322 | this.bits |= CompilationUnitResolver.BINDING_RECOVERY; |
323 | } else { |
324 | this.bits &= ~CompilationUnitResolver.BINDING_RECOVERY; |
325 | } |
326 | } |
327 | |
328 | /** |
329 | * Sets the environment to be used when no {@link IJavaProject} is available. |
330 | * |
331 | * <p> |
332 | * The user has to make sure that all the required types are included either in |
333 | * the classpath or source paths. |
334 | * All the paths containing binary types must be included in the |
335 | * <code>classpathEntries</code> whereas all paths containing |
336 | * source types must be included in the <code>sourcepathEntries</code>. |
337 | * </p> |
338 | * <p> |
339 | * All paths in the <code>classpathEntries</code> and |
340 | * <code>sourcepathEntries</code> are absolute paths. |
341 | * </p> |
342 | * <p> |
343 | * If the source paths contain units using a specific encoding (other than the |
344 | * platform encoding), then the |
345 | * given <code>encodings</code> must be set. When the <code>encodings</code> is |
346 | * set to non <code>null</code>, its length must |
347 | * match the length of <code>sourcepathEntries</code> or an |
348 | * IllegalArgumentException will be thrown. |
349 | * </p> |
350 | * <p> |
351 | * If <code>encodings</code> is not <code>null</code>, the given |
352 | * <code>sourcepathEntries</code> must not be <code>null</code>. |
353 | * </p> |
354 | * |
355 | * @param classpathEntries the given classpath entries to be used |
356 | * to resolve bindings |
357 | * @param sourcepathEntries the given sourcepath entries to be used |
358 | * to resolve bindings |
359 | * @param encodings the encodings of the corresponding |
360 | * sourcepath entries or <code>null</code> |
361 | * if the platform encoding |
362 | * can be used. |
363 | * @param includeRunningVMBootclasspath <code>true</code> if the bootclasspath |
364 | * of the running VM must be prepended to |
365 | * the |
366 | * given classpath and <code>false</code> |
367 | * if the bootclasspath of the running VM |
368 | * should be ignored. |
369 | * @throws IllegalArgumentException if the size of the given encodings is not |
370 | * equals to the size of the given <code> |
371 | * sourcepathEntries</code> |
372 | * @since 3.6 |
373 | */ |
374 | public void setEnvironment(String[] classpathEntries, String[] sourcepathEntries, String[] encodings, |
375 | boolean includeRunningVMBootclasspath) { |
376 | this.classpaths = classpathEntries; |
377 | this.sourcepaths = sourcepathEntries; |
378 | this.sourcepathsEncodings = encodings; |
379 | if (encodings != null) { |
380 | if (sourcepathEntries == null || sourcepathEntries.length != encodings.length) { |
381 | throw new IllegalArgumentException(); |
382 | } |
383 | } |
384 | if (includeRunningVMBootclasspath) { |
385 | this.bits |= CompilationUnitResolver.INCLUDE_RUNNING_VM_BOOTCLASSPATH; |
386 | } |
387 | } |
388 | |
389 | /** |
390 | * Sets the compiler options to be used when parsing. |
391 | * <p> |
392 | * Note that {@link #setSource(IClassFile)}, |
393 | * {@link #setSource(ICompilationUnit)}, |
394 | * and {@link #setProject(IJavaProject)} reset the compiler options |
395 | * based on the Java project. In other cases, compiler options default |
396 | * to {@link JavaCore#getOptions()}. In either case, and especially |
397 | * in the latter, the caller should carefully weight the consequences of |
398 | * allowing compiler options to be defaulted as opposed to being |
399 | * explicitly specified for the {@link ASTParser} instance. |
400 | * For instance, there is a compiler option called "Source Compatibility Mode" |
401 | * which determines which JDK level the source code is expected to meet. |
402 | * If you specify "1.4", then "assert" is treated as a keyword and disallowed |
403 | * as an identifier; if you specify "1.3", then "assert" is allowed as an |
404 | * identifier. So this particular setting has a major bearing on what is |
405 | * considered syntactically legal. By explicitly specifying the setting, |
406 | * the client control exactly how the parser works. On the other hand, |
407 | * allowing default settings means the parsing behaves like other JDT tools. |
408 | * </p> |
409 | * |
410 | * @param options the table of options (key type: <code>String</code>; |
411 | * value type: <code>String</code>), or <code>null</code> |
412 | * to set it back to the default |
413 | */ |
414 | public void setCompilerOptions(Map<String, String> options) { |
415 | if (options == null) { |
416 | options = JavaCore.getOptions(); |
417 | } else { |
418 | // copy client's options so as to not do any side effect on them |
419 | options = new HashMap<>(options); |
420 | } |
421 | options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags |
422 | this.compilerOptions = options; |
423 | } |
424 | |
425 | /** |
426 | * Requests that the compiler should provide binding information for |
427 | * the AST nodes it creates. |
428 | * <p> |
429 | * Defaults to <code>false</code> (no bindings). |
430 | * </p> |
431 | * <p> |
432 | * If {@link #setResolveBindings(boolean) setResolveBindings(true)}, the various |
433 | * names |
434 | * and types appearing in the AST can be resolved to "bindings" |
435 | * by calling the <code>resolveBinding</code> methods. These bindings |
436 | * draw connections between the different parts of a program, and |
437 | * generally afford a more powerful vantage point for clients who wish to |
438 | * analyze a program's structure more deeply. These bindings come at a |
439 | * considerable cost in both time and space, however, and should not be |
440 | * requested frivolously. The additional space is not reclaimed until the |
441 | * AST, all its nodes, and all its bindings become garbage. So it is very |
442 | * important to not retain any of these objects longer than absolutely |
443 | * necessary. Bindings are resolved at the time the AST is created. Subsequent |
444 | * modifications to the AST do not affect the bindings returned by |
445 | * <code>resolveBinding</code> methods in any way; these methods return the |
446 | * same binding as before the AST was modified (including modifications |
447 | * that rearrange subtrees by reparenting nodes). |
448 | * If {@link #setResolveBindings(boolean) setResolveBindings(false)}, (the |
449 | * default), the analysis |
450 | * does not go beyond parsing and building the tree, and all |
451 | * <code>resolveBinding</code> methods return <code>null</code> from the outset. |
452 | * </p> |
453 | * <p> |
454 | * When bindings are requested, instead of considering compilation units on disk |
455 | * only, |
456 | * one can also supply a <code>WorkingCopyOwner</code>. Working copies owned |
457 | * by this owner take precedence over the underlying compilation units when |
458 | * looking |
459 | * up names and drawing the connections. |
460 | * </p> |
461 | * <p> |
462 | * Note that working copy owners are used only if the |
463 | * <code>org.eclipse.jdt.core</code> |
464 | * bundle is initialized. |
465 | * </p> |
466 | * <p> |
467 | * Binding information is obtained from the Java model. |
468 | * This means that the compilation unit must be located relative to the |
469 | * Java model. This happens automatically when the source code comes from |
470 | * either {@link #setSource(ICompilationUnit) setSource(ICompilationUnit)} |
471 | * or {@link #setSource(IClassFile) setSource(IClassFile)}. |
472 | * When source is supplied by {@link #setSource(char[]) setSource(char[])}, |
473 | * the location must be established explicitly by setting an environment using |
474 | * {@link #setProject(IJavaProject)} or |
475 | * {@link #setEnvironment(String[], String[], String[], boolean)} |
476 | * and a unit name {@link #setUnitName(String)}. |
477 | * Note that the compiler options that affect doc comment checking may also |
478 | * affect whether any bindings are resolved for nodes within doc comments. |
479 | * </p> |
480 | * |
481 | * @param enabled <code>true</code> if bindings are wanted, |
482 | * and <code>false</code> if bindings are not of interest |
483 | */ |
484 | public void setResolveBindings(boolean enabled) { |
485 | if (enabled) { |
486 | this.bits |= CompilationUnitResolver.RESOLVE_BINDING; |
487 | } else { |
488 | this.bits &= ~CompilationUnitResolver.RESOLVE_BINDING; |
489 | } |
490 | } |
491 | |
492 | /** |
493 | * Requests an abridged abstract syntax tree. |
494 | * By default, complete ASTs are returned. |
495 | * <p> |
496 | * When the given <code>position</code> is a valid position within the source |
497 | * code of |
498 | * the compilation unit, the resulting AST does not have nodes for |
499 | * the entire compilation unit. Rather, the AST is only fleshed out |
500 | * for the node that include the given source position. This kind of limited |
501 | * AST is sufficient for certain purposes but totally unsuitable for others. |
502 | * In places where it can be used, the limited AST offers the advantage of |
503 | * being smaller and faster to construct. |
504 | * </p> |
505 | * <p> |
506 | * The AST will include nodes for all of the compilation unit's |
507 | * package, import, and top-level type declarations. It will also always contain |
508 | * nodes for all the body declarations for those top-level types, as well |
509 | * as body declarations for any member types. However, some of the body |
510 | * declarations may be abridged. In particular, the statements ordinarily |
511 | * found in the body of a method declaration node will not be included |
512 | * (the block will be empty) unless the source position falls somewhere |
513 | * within the source range of that method declaration node. The same is true |
514 | * for initializer declarations; the statements ordinarily found in the body |
515 | * of initializer node will not be included unless the source position falls |
516 | * somewhere within the source range of that initializer declaration node. |
517 | * Field declarations are never abridged. Note that the AST for the body of |
518 | * that one unabridged method (or initializer) is 100% complete; it has all |
519 | * its statements, including any local or anonymous type declarations |
520 | * embedded within them. When the given <code>position</code> is not located |
521 | * within |
522 | * the source range of any body declaration of a top-level type, the AST |
523 | * returned will be a skeleton that includes nodes for all and only the major |
524 | * declarations; this kind of AST is still quite useful because it contains |
525 | * all the constructs that introduce names visible to the world outside the |
526 | * compilation unit. |
527 | * </p> |
528 | * |
529 | * <p> |
530 | * This focal position is not used when the AST is built using |
531 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
532 | * </p> |
533 | * |
534 | * @param position a position into the corresponding body declaration |
535 | */ |
536 | public void setFocalPosition(int position) { |
537 | this.bits |= CompilationUnitResolver.PARTIAL; |
538 | this.focalPointPosition = position; |
539 | } |
540 | |
541 | /** |
542 | * Sets the kind of constructs to be parsed from the source. |
543 | * Defaults to an entire compilation unit. |
544 | * <p> |
545 | * When the parse is successful the result returned includes the ASTs for the |
546 | * requested source: |
547 | * <ul> |
548 | * <li>{@link #K_COMPILATION_UNIT K_COMPILATION_UNIT}: The result node |
549 | * is a {@link CompilationUnit}.</li> |
550 | * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result |
551 | * node |
552 | * is a {@link TypeDeclaration} whose |
553 | * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations} |
554 | * are the new trees. Other aspects of the type declaration are |
555 | * unspecified.</li> |
556 | * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a |
557 | * {@link Block Block} whose {@link Block#statements() statements} |
558 | * are the new trees. Other aspects of the block are unspecified.</li> |
559 | * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of |
560 | * {@link Expression Expression}. Other aspects of the expression are |
561 | * unspecified.</li> |
562 | * </ul> |
563 | * <p> |
564 | * The resulting AST node is rooted under (possibly contrived) |
565 | * {@link CompilationUnit CompilationUnit} node, to allow the |
566 | * client to retrieve the following pieces of information |
567 | * available there: |
568 | * </p> |
569 | * <ul> |
570 | * <li>{@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line |
571 | * numbers start at 1 and only cover the subrange scanned |
572 | * (<code>source[offset]</code> through |
573 | * <code>source[offset+length-1]</code>).</li> |
574 | * <li>{@linkplain CompilationUnit#getMessages() Compiler messages} |
575 | * and {@linkplain CompilationUnit#getProblems() detailed problem reports}. |
576 | * Character positions are relative to the start of |
577 | * <code>source</code>; line positions are for the subrange scanned.</li> |
578 | * <li>{@linkplain CompilationUnit#getCommentList() Comment list} |
579 | * for the subrange scanned.</li> |
580 | * </ul> |
581 | * <p> |
582 | * The contrived nodes do not have source positions. Other aspects of the |
583 | * {@link CompilationUnit CompilationUnit} node are unspecified, including |
584 | * the exact arrangement of intervening nodes. |
585 | * </p> |
586 | * <p> |
587 | * Lexical or syntax errors detected while parsing can result in |
588 | * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}. |
589 | * In more severe failure cases where the parser is unable to |
590 | * recognize the input, this method returns |
591 | * a {@link CompilationUnit CompilationUnit} node with at least the |
592 | * compiler messages. |
593 | * </p> |
594 | * <p> |
595 | * Each node in the subtree (other than the contrived nodes) |
596 | * carries source range(s) information relating back |
597 | * to positions in the given source (the given source itself |
598 | * is not remembered with the AST). |
599 | * The source range usually begins at the first character of the first token |
600 | * corresponding to the node; leading whitespace and comments are <b>not</b> |
601 | * included. The source range usually extends through the last character of |
602 | * the last token corresponding to the node; trailing whitespace and |
603 | * comments are <b>not</b> included. There are a handful of exceptions |
604 | * (including the various body declarations); the |
605 | * specification for these node type spells out the details. |
606 | * Source ranges nest properly: the source range for a child is always |
607 | * within the source range of its parent, and the source ranges of sibling |
608 | * nodes never overlap. |
609 | * </p> |
610 | * <p> |
611 | * Binding information is only computed when <code>kind</code> is |
612 | * {@link #K_COMPILATION_UNIT}. |
613 | * </p> |
614 | * |
615 | * <p> |
616 | * This kind is not used when the AST is built using |
617 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
618 | * </p> |
619 | * |
620 | * @param kind the kind of construct to parse: one of |
621 | * {@link #K_COMPILATION_UNIT}, |
622 | * {@link #K_CLASS_BODY_DECLARATIONS}, |
623 | * {@link #K_EXPRESSION}, |
624 | * {@link #K_STATEMENTS} |
625 | */ |
626 | public void setKind(int kind) { |
627 | if ((kind != K_COMPILATION_UNIT) |
628 | && (kind != K_CLASS_BODY_DECLARATIONS) |
629 | && (kind != K_EXPRESSION) |
630 | && (kind != K_STATEMENTS)) { |
631 | throw new IllegalArgumentException(); |
632 | } |
633 | this.astKind = kind; |
634 | } |
635 | |
636 | /** |
637 | * Sets the source code to be parsed. |
638 | * |
639 | * <p> |
640 | * This source is not used when the AST is built using |
641 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
642 | * </p> |
643 | * |
644 | * <p> |
645 | * If this method is used, the user needs to specify compiler options explicitly |
646 | * using |
647 | * {@link #setCompilerOptions(Map)} as 1.5 code will not be properly parsed |
648 | * without setting |
649 | * the appropriate values for the compiler options: |
650 | * {@link JavaCore#COMPILER_SOURCE}, |
651 | * {@link JavaCore#COMPILER_CODEGEN_TARGET_PLATFORM}, and |
652 | * {@link JavaCore#COMPILER_COMPLIANCE}. |
653 | * </p> |
654 | * <p> |
655 | * Otherwise the default values for the compiler options will be used to parse |
656 | * the given source. |
657 | * </p> |
658 | * |
659 | * @param source the source string to be parsed, |
660 | * or <code>null</code> if none |
661 | * @see JavaCore#setComplianceOptions(String, Map) |
662 | */ |
663 | public void setSource(char[] source) { |
664 | this.rawSource = source; |
665 | // clear the type root |
666 | this.typeRoot = null; |
667 | } |
668 | |
669 | /** |
670 | * Sets the source code to be parsed. |
671 | * |
672 | * <p> |
673 | * This method automatically sets the project (and compiler |
674 | * options) based on the given compilation unit, in a manner |
675 | * equivalent to {@link #setProject(IJavaProject) |
676 | * setProject(source.getJavaProject())}. |
677 | * </p> |
678 | * |
679 | * <p> |
680 | * This source is not used when the AST is built using |
681 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
682 | * </p> |
683 | * |
684 | * @param source the Java model compilation unit whose source code |
685 | * is to be parsed, or <code>null</code> if none |
686 | */ |
687 | public void setSource(ICompilationUnit source) { |
688 | setSource((ITypeRoot) source); |
689 | } |
690 | |
691 | /** |
692 | * Sets the source code to be parsed. |
693 | * |
694 | * <p> |
695 | * This method automatically sets the project (and compiler |
696 | * options) based on the given compilation unit, in a manner |
697 | * equivalent to {@link #setProject(IJavaProject) |
698 | * setProject(source.getJavaProject())}. |
699 | * </p> |
700 | * <p> |
701 | * If the given class file has no source attachment, the creation of the |
702 | * ast will fail with an {@link IllegalStateException}. |
703 | * </p> |
704 | * |
705 | * <p> |
706 | * This source is not used when the AST is built using |
707 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
708 | * </p> |
709 | * |
710 | * @param source the Java model class file whose corresponding source code |
711 | * is to be parsed, or <code>null</code> if none |
712 | */ |
713 | public void setSource(IClassFile source) { |
714 | setSource((ITypeRoot) source); |
715 | } |
716 | |
717 | /** |
718 | * Sets the source code to be parsed. |
719 | * |
720 | * <p> |
721 | * This method automatically sets the project (and compiler |
722 | * options) based on the given compilation unit of class file, in a manner |
723 | * equivalent to {@link #setProject(IJavaProject) |
724 | * setProject(source.getJavaProject())}. |
725 | * </p> |
726 | * <p> |
727 | * If the source is a class file without source attachment, the creation of the |
728 | * ast will fail with an {@link IllegalStateException}. |
729 | * </p> |
730 | * |
731 | * <p> |
732 | * This source is not used when the AST is built using |
733 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
734 | * </p> |
735 | * |
736 | * @param source the Java model compilation unit or class file whose |
737 | * corresponding source code |
738 | * is to be parsed, or <code>null</code> if none |
739 | * @since 3.3 |
740 | */ |
741 | public void setSource(ITypeRoot source) { |
742 | this.typeRoot = source; |
743 | // clear the raw source |
744 | this.rawSource = null; |
745 | if (source != null) { |
746 | this.project = source.getJavaProject(); |
747 | Map<String, String> options = this.project.getOptions(true); |
748 | options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags |
749 | this.compilerOptions = options; |
750 | } |
751 | } |
752 | |
753 | /** |
754 | * Sets the source code to be parsed. |
755 | * |
756 | * |
757 | * <p> |
758 | * This method automatically sets the project (and compiler |
759 | * options) based on the given compilation unit of class file, in a manner |
760 | * equivalent to {@link #setProject(IJavaProject) |
761 | * setProject(source.getJavaProject())}. |
762 | * </p> |
763 | * <p> |
764 | * If the source is a class file without source attachment, the creation of the |
765 | * ast will fail with an {@link IllegalStateException}. |
766 | * </p> |
767 | * |
768 | * <p> |
769 | * If this method is used, the user need not specify compiler options |
770 | * explicitly. |
771 | * The @param astLevel will be used for setting the corresponding values for the |
772 | * compiler |
773 | * options: {@link JavaCore#COMPILER_SOURCE}, |
774 | * {@link JavaCore#COMPILER_CODEGEN_TARGET_PLATFORM} |
775 | * and {@link JavaCore#COMPILER_COMPLIANCE}. |
776 | * </p> |
777 | * |
778 | * <p> |
779 | * This source is not used when the AST is built using |
780 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
781 | * </p> |
782 | * |
783 | * <p> |
784 | * This astLevel will be used as the |
785 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
786 | * </p> |
787 | * |
788 | * @param source the Java model compilation unit or class file whose |
789 | * corresponding source code |
790 | * is to be parsed, or <code>null</code> if none |
791 | * @param astLevel the API level; one of the <code>JLS*</code> level constants |
792 | * declared on {@link AST} |
793 | * @since 3.27 |
794 | */ |
795 | public void setSource(ITypeRoot source, int astLevel) { |
796 | this.typeRoot = source; |
797 | // clear the raw source |
798 | this.rawSource = null; |
799 | if (source != null) { |
800 | this.project = source.getJavaProject(); |
801 | Map<String, String> options = this.project.getOptions(true); |
802 | options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags |
803 | this.compilerOptions = options; |
804 | String compliance = DOMASTUtil.getCompliance(astLevel); |
805 | this.compilerOptions.put(JavaCore.COMPILER_COMPLIANCE, compliance); |
806 | this.compilerOptions.put(JavaCore.COMPILER_SOURCE, compliance); |
807 | this.compilerOptions.put(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, compliance); |
808 | } |
809 | } |
810 | |
811 | /** |
812 | * Sets the subrange of the source code to be parsed. |
813 | * By default, the entire source string will be parsed |
814 | * (<code>offset</code> 0 and <code>length</code> -1). |
815 | * |
816 | * <p> |
817 | * This range is not used when the AST is built using |
818 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
819 | * </p> |
820 | * |
821 | * @param offset the index of the first character to parse |
822 | * @param length the number of characters to parse, or -1 if |
823 | * the remainder of the source string is to be parsed |
824 | */ |
825 | public void setSourceRange(int offset, int length) { |
826 | if (offset < 0 || length < -1) { |
827 | throw new IllegalArgumentException(); |
828 | } |
829 | this.sourceOffset = offset; |
830 | this.sourceLength = length; |
831 | } |
832 | |
833 | /** |
834 | * Requests that the compiler should perform statements recovery. |
835 | * When statements recovery is enabled the compiler tries to create statement |
836 | * nodes |
837 | * from code containing syntax errors |
838 | * <p> |
839 | * Default to <code>false</code>. |
840 | * </p> |
841 | * |
842 | * @param enabled <code>true</code> if statements containing syntax errors are |
843 | * wanted, |
844 | * and <code>false</code> if these statements aren't wanted. |
845 | * |
846 | * @since 3.2 |
847 | */ |
848 | public void setStatementsRecovery(boolean enabled) { |
849 | if (enabled) { |
850 | this.bits |= CompilationUnitResolver.STATEMENT_RECOVERY; |
851 | } else { |
852 | this.bits &= ~CompilationUnitResolver.STATEMENT_RECOVERY; |
853 | } |
854 | } |
855 | |
856 | /** |
857 | * Requests an abstract syntax tree without method bodies. |
858 | * |
859 | * <p> |
860 | * When ignore method bodies is enabled, all method bodies are discarded. |
861 | * This has no impact on the binding resolution. |
862 | * </p> |
863 | * |
864 | * <p> |
865 | * This setting is not used when the kind used in {@link #setKind(int)} is |
866 | * either |
867 | * {@link #K_EXPRESSION} or {@link #K_STATEMENTS}. |
868 | * </p> |
869 | * |
870 | * @since 3.5.2 |
871 | */ |
872 | public void setIgnoreMethodBodies(boolean enabled) { |
873 | if (enabled) { |
874 | this.bits |= CompilationUnitResolver.IGNORE_METHOD_BODIES; |
875 | } else { |
876 | this.bits &= ~CompilationUnitResolver.IGNORE_METHOD_BODIES; |
877 | } |
878 | } |
879 | |
880 | /** |
881 | * Sets the working copy owner used when resolving bindings, where |
882 | * <code>null</code> means the primary owner. Defaults to the primary owner. |
883 | * |
884 | * @param owner the owner of working copies that take precedence over underlying |
885 | * compilation units, or <code>null</code> if the primary owner |
886 | * should be used |
887 | */ |
888 | public void setWorkingCopyOwner(WorkingCopyOwner owner) { |
889 | if (owner == null) { |
890 | this.workingCopyOwner = DefaultWorkingCopyOwner.PRIMARY; |
891 | } else { |
892 | this.workingCopyOwner = owner; |
893 | } |
894 | } |
895 | |
896 | /** |
897 | * Sets the name of the compilation unit that would hypothetically contains the |
898 | * source string. |
899 | * |
900 | * <p> |
901 | * This is used in conjunction with {@link #setSource(char[])} |
902 | * and {@link #setProject(IJavaProject)} to locate the compilation unit relative |
903 | * to a Java project. |
904 | * Defaults to none (<code>null</code>). |
905 | * </p> |
906 | * <p> |
907 | * The name of the compilation unit must be supplied for resolving bindings. |
908 | * This name should be suffixed by a dot ('.') followed by one of the |
909 | * {@link JavaCore#getJavaLikeExtensions() Java-like extensions} |
910 | * and match the name of the main (public) class or interface declared in the |
911 | * source. |
912 | * </p> |
913 | * |
914 | * <p> |
915 | * For compilation of a module-info.java file (since Java 9), the name of the |
916 | * compilation unit must be supplied. |
917 | * Otherwise, module-info.java will be compiled as an ordinary Java file |
918 | * resulting in compilation errors. |
919 | * </p> |
920 | * |
921 | * <p> |
922 | * This name must represent the full path of the unit inside the given project. |
923 | * For example, if the source |
924 | * declares a public class named "Foo" in a project "P" where the source folder |
925 | * is the project itself, the name |
926 | * of the compilation unit must be "/P/Foo.java". |
927 | * If the source declares a public class name "Bar" in a package "p1.p2" in a |
928 | * project "P" in a source folder "src", |
929 | * the name of the compilation unit must be "/P/src/p1/p2/Bar.java". |
930 | * </p> |
931 | * |
932 | * <p> |
933 | * This unit name is not used when the AST is built using |
934 | * {@link #createASTs(ICompilationUnit[], String[], ASTRequestor, IProgressMonitor)}. |
935 | * </p> |
936 | * |
937 | * @param unitName the name of the compilation unit that would contain the |
938 | * source |
939 | * string, or <code>null</code> if none |
940 | */ |
941 | public void setUnitName(String unitName) { |
942 | this.unitName = unitName; |
943 | } |
944 | |
945 | /** |
946 | * Sets the Java project used when resolving bindings. |
947 | * |
948 | * <p> |
949 | * This method automatically sets the compiler |
950 | * options based on the given project: |
951 | * </p> |
952 | * |
953 | * <pre> |
954 | * setCompilerOptions(project.getOptions(true)); |
955 | * </pre> |
956 | * <p> |
957 | * See {@link #setCompilerOptions(Map)} for a discussion of |
958 | * the pros and cons of using these options vs specifying |
959 | * compiler options explicitly. |
960 | * </p> |
961 | * <p> |
962 | * This setting is used in conjunction with {@link #setSource(char[])}. |
963 | * For the purposes of resolving bindings, types declared in the |
964 | * source string will hide types by the same name available |
965 | * through the classpath of the given project. |
966 | * </p> |
967 | * <p> |
968 | * Defaults to none (<code>null</code>). |
969 | * </p> |
970 | * |
971 | * @param project the Java project used to resolve names, or |
972 | * <code>null</code> if none |
973 | */ |
974 | public void setProject(IJavaProject project) { |
975 | this.project = project; |
976 | if (project != null) { |
977 | Map<String, String> options = project.getOptions(true); |
978 | options.remove(JavaCore.COMPILER_TASK_TAGS); // no need to parse task tags |
979 | this.compilerOptions = options; |
980 | } |
981 | } |
982 | |
983 | /** |
984 | * Creates an abstract syntax tree. |
985 | * <p> |
986 | * A successful call to this method returns all settings to their |
987 | * default values so the object is ready to be reused. |
988 | * </p> |
989 | * <p> |
990 | * For identifying a module-info.java file as a special file instead of an |
991 | * ordinary |
992 | * Java file (Since Java 9), a call to this should be preceded by a call to |
993 | * {@link #setUnitName(String)} that sets the unit name as module-info.java |
994 | * </p> |
995 | * |
996 | * @param monitor the progress monitor used to report progress and request |
997 | * cancellation, |
998 | * or <code>null</code> if none |
999 | * @return an AST node whose type depends on the kind of parse |
1000 | * requested, with a fallback to a <code>CompilationUnit</code> |
1001 | * in the case of severe parsing errors |
1002 | * @exception IllegalStateException if the settings provided |
1003 | * are insufficient, contradictory, or |
1004 | * otherwise unsupported |
1005 | */ |
1006 | public ASTNode createAST(IProgressMonitor monitor) { |
1007 | SubMonitor subMonitor = SubMonitor.convert(monitor, 1); |
1008 | ASTNode result = null; |
1009 | try { |
1010 | if (this.rawSource == null && this.typeRoot == null) { |
1011 | throw new IllegalStateException("source not specified"); //$NON-NLS-1$ |
1012 | } |
1013 | result = internalCreateAST(subMonitor.split(1)); |
1014 | } finally { |
1015 | // reset to defaults to allow reuse (and avoid leaking) |
1016 | initializeDefaults(); |
1017 | } |
1018 | return result; |
1019 | } |
1020 | |
1021 | /** |
1022 | * Creates ASTs for a batch of compilation units. |
1023 | * <p> |
1024 | * When bindings are being resolved, processing a |
1025 | * batch of compilation units is more efficient because much |
1026 | * of the work involved in resolving bindings can be shared. |
1027 | * </p> |
1028 | * <p> |
1029 | * When bindings are being resolved, all compilation units must |
1030 | * come from the same Java project, which must be set beforehand |
1031 | * with {@link #setProject(IJavaProject) setProject}. |
1032 | * </p> |
1033 | * <p> |
1034 | * The compilation units are processed one at a time in no |
1035 | * specified order. For each of the compilation units in turn, |
1036 | * </p> |
1037 | * <ul> |
1038 | * <li>{@link #createAST(IProgressMonitor) ASTParser.createAST} is called to |
1039 | * parse it |
1040 | * and create a corresponding AST. The calls to |
1041 | * {@link #createAST(IProgressMonitor) ASTParser.createAST} all employ the same |
1042 | * settings.</li> |
1043 | * <li>{@link ASTRequestor#acceptAST(ICompilationUnit, CompilationUnit) |
1044 | * ASTRequestor.acceptAST} |
1045 | * is called passing the compilation unit and the corresponding AST to |
1046 | * <code>requestor</code>. |
1047 | * </li> |
1048 | * </ul> |
1049 | * <p> |
1050 | * Note only ASTs from the given compilation units are reported |
1051 | * to the requestor. If additional compilation units are required to |
1052 | * resolve the original ones, the corresponding ASTs are <b>not</b> |
1053 | * reported to the requestor. |
1054 | * </p> |
1055 | * <p> |
1056 | * Note also the following parser parameters are used, regardless of what |
1057 | * may have been specified: |
1058 | * <ul> |
1059 | * <li>The {@linkplain #setKind(int) parser kind} is |
1060 | * <code>K_COMPILATION_UNIT</code></li> |
1061 | * <li>The {@linkplain #setSourceRange(int,int) source range} is |
1062 | * <code>(0, -1)</code></li> |
1063 | * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li> |
1064 | * </ul> |
1065 | * <p> |
1066 | * The <code>bindingKeys</code> parameter specifies bindings keys |
1067 | * ({@link IBinding#getKey()}) that are to be looked up. These keys may |
1068 | * be for elements either inside or outside the set of compilation |
1069 | * units being processed. When bindings are being resolved, |
1070 | * the keys and corresponding bindings (or <code>null</code> if none) are |
1071 | * passed to {@link ASTRequestor#acceptBinding(String, IBinding) |
1072 | * ASTRequestor.acceptBinding}. |
1073 | * Note that binding keys for elements outside the set of compilation units |
1074 | * being processed |
1075 | * are looked up after all |
1076 | * {@link ASTRequestor#acceptAST(ICompilationUnit, CompilationUnit) |
1077 | * ASTRequestor.acceptAST} |
1078 | * callbacks have been made. |
1079 | * Binding keys for elements inside the set of compilation units being processed |
1080 | * are looked up and reported right after the corresponding |
1081 | * {@link ASTRequestor#acceptAST(ICompilationUnit, CompilationUnit) |
1082 | * ASTRequestor.acceptAST} callback has been made. |
1083 | * No {@link ASTRequestor#acceptBinding(String, IBinding) |
1084 | * ASTRequestor.acceptBinding} callbacks are made unless |
1085 | * bindings are being resolved. |
1086 | * </p> |
1087 | * <p> |
1088 | * A successful call to this method returns all settings to their |
1089 | * default values so the object is ready to be reused. |
1090 | * </p> |
1091 | * |
1092 | * @param compilationUnits the compilation units to create ASTs for |
1093 | * @param bindingKeys the binding keys to create bindings for |
1094 | * @param requestor the AST requestor that collects abstract syntax trees |
1095 | * and bindings |
1096 | * @param monitor the progress monitor used to report progress and |
1097 | * request cancellation, |
1098 | * or <code>null</code> if none |
1099 | * @exception IllegalStateException if the settings provided |
1100 | * are insufficient, contradictory, or |
1101 | * otherwise unsupported |
1102 | * @since 3.1 |
1103 | */ |
1104 | public void createASTs(ICompilationUnit[] compilationUnits, String[] bindingKeys, ASTRequestor requestor, |
1105 | IProgressMonitor monitor) { |
1106 | try { |
1107 | int flags = 0; |
1108 | if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { |
1109 | flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; |
1110 | } |
1111 | if ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0) { |
1112 | flags |= ICompilationUnit.IGNORE_METHOD_BODIES; |
1113 | } |
1114 | if ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0) { |
1115 | if (this.project == null) |
1116 | throw new IllegalStateException("project not specified"); //$NON-NLS-1$ |
1117 | if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) { |
1118 | flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; |
1119 | } |
1120 | CompilationUnitResolver.resolve(compilationUnits, bindingKeys, requestor, this.apiLevel, |
1121 | this.compilerOptions, this.project, this.workingCopyOwner, flags, monitor); |
1122 | } else { |
1123 | CompilationUnitResolver.parse(compilationUnits, requestor, this.apiLevel, this.compilerOptions, flags, |
1124 | monitor); |
1125 | } |
1126 | } finally { |
1127 | // reset to defaults to allow reuse (and avoid leaking) |
1128 | initializeDefaults(); |
1129 | } |
1130 | } |
1131 | |
1132 | /** |
1133 | * Creates ASTs for a batch of compilation units. |
1134 | * When bindings are being resolved, processing a |
1135 | * batch of compilation units is more efficient because much |
1136 | * of the work involved in resolving bindings can be shared. |
1137 | * <p> |
1138 | * When bindings are being resolved, all compilation units are resolved using |
1139 | * the same environment, which must be set beforehand |
1140 | * with {@link #setEnvironment(String[], String[], String[], boolean) |
1141 | * setEnvironment}. |
1142 | * The compilation units are processed one at a time in no |
1143 | * specified order. For each of the compilation units in turn, |
1144 | * <ul> |
1145 | * <li>{@link ASTParser#createAST(IProgressMonitor) ASTParser.createAST} is |
1146 | * called to parse it |
1147 | * and create a corresponding AST. The calls to |
1148 | * {@link ASTParser#createAST(IProgressMonitor) ASTParser.createAST} all employ |
1149 | * the same settings.</li> |
1150 | * <li>{@link FileASTRequestor#acceptAST(String, CompilationUnit) |
1151 | * FileASTRequestor.acceptAST} is called passing |
1152 | * the compilation unit path and the corresponding AST to |
1153 | * <code>requestor</code>. The compilation unit path is the same |
1154 | * path that is passed into the given <code>sourceFilePaths</code> parameter. |
1155 | * </li> |
1156 | * </ul> |
1157 | * <p> |
1158 | * Note only ASTs from the given compilation units are reported |
1159 | * to the requestor. If additional compilation units are required to |
1160 | * resolve the original ones, the corresponding ASTs are <b>not</b> |
1161 | * reported to the requestor. |
1162 | * </p> |
1163 | * <p> |
1164 | * Note also the following parser parameters are used, regardless of what |
1165 | * may have been specified: |
1166 | * </p> |
1167 | * <ul> |
1168 | * <li>The {@linkplain #setKind(int) parser kind} is |
1169 | * <code>K_COMPILATION_UNIT</code></li> |
1170 | * <li>The {@linkplain #setSourceRange(int,int) source range} is |
1171 | * <code>(0, -1)</code></li> |
1172 | * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li> |
1173 | * </ul> |
1174 | * <p> |
1175 | * The <code>bindingKeys</code> parameter specifies bindings keys |
1176 | * ({@link IBinding#getKey()}) that are to be looked up. These keys may |
1177 | * be for elements either inside or outside the set of compilation |
1178 | * units being processed. When bindings are being resolved, |
1179 | * the keys and corresponding bindings (or <code>null</code> if none) are |
1180 | * passed to {@link FileASTRequestor#acceptBinding(String, IBinding) |
1181 | * FileASTRequestor.acceptBinding}. Note that binding keys |
1182 | * for elements outside the set of compilation units being processed are looked |
1183 | * up |
1184 | * after all {@link FileASTRequestor#acceptAST(String, CompilationUnit) |
1185 | * ASTRequestor.acceptAST} |
1186 | * callbacks have been made. |
1187 | * Binding keys for elements inside the set of compilation units being processed |
1188 | * are looked up and reported right after the corresponding |
1189 | * {@link FileASTRequestor#acceptAST(String, CompilationUnit) |
1190 | * FileASTRequestor.acceptAST} callback has been made. |
1191 | * No {@link FileASTRequestor#acceptBinding(String, IBinding) |
1192 | * FileASTRequestor.acceptBinding} callbacks are made unless |
1193 | * bindings are being resolved. |
1194 | * </p> |
1195 | * <p> |
1196 | * A successful call to this method returns all settings to their |
1197 | * default values so the object is ready to be reused. |
1198 | * </p> |
1199 | * <p> |
1200 | * The given <code>encodings</code> are used to properly parse the given source |
1201 | * units. If the platform encoding is sufficient, |
1202 | * then the given encodings can be set to <code>null</code>. |
1203 | * </p> |
1204 | * |
1205 | * @param sourceFilePaths the compilation units to create ASTs for |
1206 | * @param encodings the given encoding for the source units |
1207 | * @param bindingKeys the binding keys to create bindings for |
1208 | * @param requestor the AST requestor that collects abstract syntax trees |
1209 | * and bindings |
1210 | * @param monitor the progress monitor used to report progress and |
1211 | * request cancellation, |
1212 | * or <code>null</code> if none |
1213 | * @exception IllegalStateException if the settings provided |
1214 | * are insufficient, contradictory, or |
1215 | * otherwise unsupported |
1216 | * @since 3.6 |
1217 | */ |
1218 | public void createASTs(String[] sourceFilePaths, String[] encodings, String[] bindingKeys, |
1219 | FileASTRequestor requestor, IProgressMonitor monitor) { |
1220 | try { |
1221 | int flags = 0; |
1222 | if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { |
1223 | flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; |
1224 | } |
1225 | if ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0) { |
1226 | flags |= ICompilationUnit.IGNORE_METHOD_BODIES; |
1227 | } |
1228 | if ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0) { |
1229 | if (this.classpaths == null && this.sourcepaths == null |
1230 | && ((this.bits & CompilationUnitResolver.INCLUDE_RUNNING_VM_BOOTCLASSPATH) == 0)) { |
1231 | throw new IllegalStateException("no environment is specified"); //$NON-NLS-1$ |
1232 | } |
1233 | if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) { |
1234 | flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; |
1235 | } |
1236 | CompilationUnitResolver.resolve(sourceFilePaths, encodings, bindingKeys, requestor, this.apiLevel, |
1237 | this.compilerOptions, getClasspath(), flags, monitor); |
1238 | } else { |
1239 | CompilationUnitResolver.parse(sourceFilePaths, encodings, requestor, this.apiLevel, |
1240 | this.compilerOptions, flags, monitor); |
1241 | } |
1242 | } finally { |
1243 | // reset to defaults to allow reuse (and avoid leaking) |
1244 | initializeDefaults(); |
1245 | } |
1246 | } |
1247 | |
1248 | /** |
1249 | * Creates bindings for a batch of Java elements. |
1250 | * |
1251 | * <p> |
1252 | * These elements are either |
1253 | * enclosed in {@link ICompilationUnit ICompilationUnits} or in |
1254 | * {@link IClassFile IClassFiles}. |
1255 | * </p> |
1256 | * <p> |
1257 | * All enclosing compilation units and class files must |
1258 | * come from the same Java project, which must be set beforehand |
1259 | * with {@link #setProject(IJavaProject) setProject}. |
1260 | * </p> |
1261 | * <p> |
1262 | * All elements must exist. If one doesn't exist, an |
1263 | * {@link IllegalStateException} |
1264 | * is thrown. |
1265 | * </p> |
1266 | * <p> |
1267 | * The returned array has the same size as the given elements array. At a given |
1268 | * position |
1269 | * it contains the binding of the corresponding Java element, or |
1270 | * <code>null</code> |
1271 | * if no binding could be created. |
1272 | * </p> |
1273 | * <p> |
1274 | * Note also the following parser parameters are used, regardless of what |
1275 | * may have been specified: |
1276 | * <ul> |
1277 | * <li>The {@linkplain #setResolveBindings(boolean) binding resolution flag} is |
1278 | * <code>true</code></li> |
1279 | * <li>The {@linkplain #setKind(int) parser kind} is |
1280 | * <code>K_COMPILATION_UNIT</code></li> |
1281 | * <li>The {@linkplain #setSourceRange(int,int) source range} is |
1282 | * <code>(0, -1)</code></li> |
1283 | * <li>The {@linkplain #setFocalPosition(int) focal position} is not set</li> |
1284 | * </ul> |
1285 | * <p> |
1286 | * A successful call to this method returns all settings to their |
1287 | * default values so the object is ready to be reused. |
1288 | * </p> |
1289 | * |
1290 | * @param elements the Java elements to create bindings for |
1291 | * @return the bindings for the given Java elements, possibly containing |
1292 | * <code>null</code>s |
1293 | * if some bindings could not be created |
1294 | * @exception IllegalStateException if the settings provided |
1295 | * are insufficient, contradictory, or |
1296 | * otherwise unsupported |
1297 | * @since 3.1 |
1298 | */ |
1299 | public IBinding[] createBindings(IJavaElement[] elements, IProgressMonitor monitor) { |
1300 | try { |
1301 | if (this.project == null) |
1302 | throw new IllegalStateException("project or classpath not specified"); //$NON-NLS-1$ |
1303 | int flags = 0; |
1304 | if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { |
1305 | flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; |
1306 | } |
1307 | if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) { |
1308 | flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; |
1309 | } |
1310 | if ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0) { |
1311 | flags |= ICompilationUnit.IGNORE_METHOD_BODIES; |
1312 | } |
1313 | return CompilationUnitResolver.resolve(elements, this.apiLevel, this.compilerOptions, this.project, |
1314 | this.workingCopyOwner, flags, monitor); |
1315 | } finally { |
1316 | // reset to defaults to allow reuse (and avoid leaking) |
1317 | initializeDefaults(); |
1318 | } |
1319 | } |
1320 | |
1321 | private ASTNode internalCreateAST(IProgressMonitor monitor) { |
1322 | boolean needToResolveBindings = (this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0; |
1323 | switch (this.astKind) { |
1324 | case K_CLASS_BODY_DECLARATIONS: |
1325 | case K_EXPRESSION: |
1326 | case K_STATEMENTS: |
1327 | if (this.rawSource == null) { |
1328 | if (this.typeRoot != null) { |
1329 | // get the source from the type root |
1330 | if (this.typeRoot instanceof ICompilationUnit) { |
1331 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) this.typeRoot; |
1332 | this.rawSource = sourceUnit.getContents(); |
1333 | } else if (this.typeRoot instanceof IClassFile) { |
1334 | try { |
1335 | String sourceString = this.typeRoot.getSource(); |
1336 | if (sourceString != null) { |
1337 | this.rawSource = sourceString.toCharArray(); |
1338 | } |
1339 | } catch (JavaModelException e) { |
1340 | // an error occured accessing the java element |
1341 | StringWriter stringWriter = new StringWriter(); |
1342 | try (PrintWriter writer = new PrintWriter(stringWriter)) { |
1343 | e.printStackTrace(writer); |
1344 | } |
1345 | throw new IllegalStateException(String.valueOf(stringWriter.getBuffer())); |
1346 | } |
1347 | } |
1348 | } |
1349 | } |
1350 | if (this.rawSource != null) { |
1351 | if (this.sourceOffset + this.sourceLength > this.rawSource.length) { |
1352 | throw new IllegalStateException(); |
1353 | } |
1354 | return internalCreateASTForKind(); |
1355 | } |
1356 | break; |
1357 | case K_COMPILATION_UNIT: |
1358 | CompilationUnitDeclaration compilationUnitDeclaration = null; |
1359 | try { |
1360 | NodeSearcher searcher = null; |
1361 | org.eclipse.jdt.internal.compiler.env.ICompilationUnit sourceUnit = null; |
1362 | WorkingCopyOwner wcOwner = this.workingCopyOwner; |
1363 | if (this.typeRoot instanceof ClassFileWorkingCopy) { |
1364 | // special case: class file mimics as compilation unit, but that would use a |
1365 | // wrong file name below, so better unwrap now: |
1366 | this.typeRoot = ((ClassFileWorkingCopy) this.typeRoot).classFile; |
1367 | } |
1368 | if (this.typeRoot instanceof ICompilationUnit) { |
1369 | /* |
1370 | * this.compilationUnitSource is an instance of |
1371 | * org.eclipse.jdt.internal.core.CompilationUnit that implements |
1372 | * both org.eclipse.jdt.core.ICompilationUnit and |
1373 | * org.eclipse.jdt.internal.compiler.env.ICompilationUnit |
1374 | */ |
1375 | sourceUnit = (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) this.typeRoot; |
1376 | /* |
1377 | * use a BasicCompilation that caches the source instead of using the |
1378 | * compilationUnitSource directly |
1379 | * (if it is a working copy, the source can change between the parse and the AST |
1380 | * convertion) |
1381 | * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=75632) |
1382 | */ |
1383 | sourceUnit = new BasicCompilationUnit(sourceUnit.getContents(), sourceUnit.getPackageName(), |
1384 | new String(sourceUnit.getFileName()), this.project); |
1385 | wcOwner = ((ICompilationUnit) this.typeRoot).getOwner(); |
1386 | } else if (this.typeRoot instanceof IClassFile) { |
1387 | try { |
1388 | String sourceString = this.typeRoot.getSource(); |
1389 | if (sourceString == null) { |
1390 | throw new IllegalStateException(); |
1391 | } |
1392 | PackageFragment packageFragment = (PackageFragment) this.typeRoot.getParent(); |
1393 | BinaryType type = (BinaryType) this.typeRoot.findPrimaryType(); |
1394 | String fileNameString = null; |
1395 | if (type != null) { |
1396 | IBinaryType binaryType = (IBinaryType) type.getElementInfo(); |
1397 | // file name is used to recreate the Java element, so it has to be the toplevel |
1398 | // .class file name |
1399 | char[] fileName = binaryType.getFileName(); |
1400 | |
1401 | int firstDollar = CharOperation.indexOf('$', fileName); |
1402 | if (firstDollar != -1) { |
1403 | char[] suffix = SuffixConstants.SUFFIX_class; |
1404 | int suffixLength = suffix.length; |
1405 | char[] newFileName = new char[firstDollar + suffixLength]; |
1406 | System.arraycopy(fileName, 0, newFileName, 0, firstDollar); |
1407 | System.arraycopy(suffix, 0, newFileName, firstDollar, suffixLength); |
1408 | fileName = newFileName; |
1409 | } |
1410 | fileNameString = new String(fileName); |
1411 | } else { |
1412 | // assumed to be "module-info.class" (which has no type): |
1413 | fileNameString = this.typeRoot.getElementName(); |
1414 | } |
1415 | sourceUnit = new BasicCompilationUnit(sourceString.toCharArray(), |
1416 | Util.toCharArrays(packageFragment.names), fileNameString, this.typeRoot); |
1417 | } catch (JavaModelException e) { |
1418 | // an error occured accessing the java element |
1419 | StringWriter stringWriter = new StringWriter(); |
1420 | try (PrintWriter writer = new PrintWriter(stringWriter)) { |
1421 | e.printStackTrace(writer); |
1422 | } |
1423 | throw new IllegalStateException(String.valueOf(stringWriter.getBuffer())); |
1424 | } |
1425 | } else if (this.rawSource != null) { |
1426 | needToResolveBindings = ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0) |
1427 | && this.unitName != null |
1428 | && (this.project != null |
1429 | || this.classpaths != null |
1430 | || this.sourcepaths != null |
1431 | || ((this.bits |
1432 | & CompilationUnitResolver.INCLUDE_RUNNING_VM_BOOTCLASSPATH) != 0)) |
1433 | && this.compilerOptions != null; |
1434 | sourceUnit = new BasicCompilationUnit(this.rawSource, null, |
1435 | this.unitName == null ? "" : this.unitName, this.project); //$NON-NLS-1$ |
1436 | } else { |
1437 | throw new IllegalStateException(); |
1438 | } |
1439 | if ((this.bits & CompilationUnitResolver.PARTIAL) != 0) { |
1440 | searcher = new NodeSearcher(this.focalPointPosition); |
1441 | } |
1442 | int flags = 0; |
1443 | if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { |
1444 | flags |= ICompilationUnit.ENABLE_STATEMENTS_RECOVERY; |
1445 | } |
1446 | if (searcher == null && ((this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0)) { |
1447 | flags |= ICompilationUnit.IGNORE_METHOD_BODIES; |
1448 | } |
1449 | if (needToResolveBindings) { |
1450 | if ((this.bits & CompilationUnitResolver.BINDING_RECOVERY) != 0) { |
1451 | flags |= ICompilationUnit.ENABLE_BINDINGS_RECOVERY; |
1452 | } |
1453 | try { |
1454 | // parse and resolve |
1455 | compilationUnitDeclaration = CompilationUnitResolver.resolve( |
1456 | sourceUnit, |
1457 | this.project, |
1458 | getClasspath(), |
1459 | searcher, |
1460 | this.compilerOptions, |
1461 | this.workingCopyOwner, |
1462 | flags, |
1463 | monitor); |
1464 | } catch (JavaModelException e) { |
1465 | flags &= ~ICompilationUnit.ENABLE_BINDINGS_RECOVERY; |
1466 | compilationUnitDeclaration = CompilationUnitResolver.parse( |
1467 | sourceUnit, |
1468 | searcher, |
1469 | this.compilerOptions, |
1470 | flags); |
1471 | needToResolveBindings = false; |
1472 | } |
1473 | } else { |
1474 | compilationUnitDeclaration = CompilationUnitResolver.parse( |
1475 | sourceUnit, |
1476 | searcher, |
1477 | this.compilerOptions, |
1478 | flags, |
1479 | this.project); |
1480 | needToResolveBindings = false; |
1481 | } |
1482 | CompilationUnit result = CompilationUnitResolver.convert( |
1483 | compilationUnitDeclaration, |
1484 | sourceUnit.getContents(), |
1485 | this.apiLevel, |
1486 | this.compilerOptions, |
1487 | needToResolveBindings, |
1488 | wcOwner, |
1489 | needToResolveBindings ? new DefaultBindingResolver.BindingTables() : null, |
1490 | flags, |
1491 | monitor, |
1492 | this.project != null, |
1493 | this.project); |
1494 | result.setTypeRoot(this.typeRoot); |
1495 | return result; |
1496 | } finally { |
1497 | if (compilationUnitDeclaration != null |
1498 | && ((this.bits & CompilationUnitResolver.RESOLVE_BINDING) != 0)) { |
1499 | compilationUnitDeclaration.cleanUp(); |
1500 | } |
1501 | } |
1502 | } |
1503 | throw new IllegalStateException(); |
1504 | } |
1505 | |
1506 | /** |
1507 | * Parses the given source between the bounds specified by the given offset |
1508 | * (inclusive) |
1509 | * and the given length and creates and returns a corresponding abstract syntax |
1510 | * tree. |
1511 | * <p> |
1512 | * When the parse is successful the result returned includes the ASTs for the |
1513 | * requested source: |
1514 | * <ul> |
1515 | * <li>{@link #K_CLASS_BODY_DECLARATIONS K_CLASS_BODY_DECLARATIONS}: The result |
1516 | * node |
1517 | * is a {@link TypeDeclaration TypeDeclaration} whose |
1518 | * {@link TypeDeclaration#bodyDeclarations() bodyDeclarations} |
1519 | * are the new trees. Other aspects of the type declaration are |
1520 | * unspecified.</li> |
1521 | * <li>{@link #K_STATEMENTS K_STATEMENTS}: The result node is a |
1522 | * {@link Block Block} whose {@link Block#statements() statements} |
1523 | * are the new trees. Other aspects of the block are unspecified.</li> |
1524 | * <li>{@link #K_EXPRESSION K_EXPRESSION}: The result node is a subclass of |
1525 | * {@link Expression Expression}. Other aspects of the expression are |
1526 | * unspecified.</li> |
1527 | * </ul> |
1528 | * The resulting AST node is rooted under an contrived |
1529 | * {@link CompilationUnit CompilationUnit} node, to allow the |
1530 | * client to retrieve the following pieces of information |
1531 | * available there: |
1532 | * <ul> |
1533 | * <li>{@linkplain CompilationUnit#getLineNumber(int) Line number map}. Line |
1534 | * numbers start at 1 and only cover the subrange scanned |
1535 | * (<code>source[offset]</code> through |
1536 | * <code>source[offset+length-1]</code>).</li> |
1537 | * <li>{@linkplain CompilationUnit#getMessages() Compiler messages} |
1538 | * and {@linkplain CompilationUnit#getProblems() detailed problem reports}. |
1539 | * Character positions are relative to the start of |
1540 | * <code>source</code>; line positions are for the subrange scanned.</li> |
1541 | * <li>{@linkplain CompilationUnit#getCommentList() Comment list} |
1542 | * for the subrange scanned.</li> |
1543 | * </ul> |
1544 | * <p> |
1545 | * The contrived nodes do not have source positions. Other aspects of the |
1546 | * {@link CompilationUnit CompilationUnit} node are unspecified, including |
1547 | * the exact arrangment of intervening nodes. |
1548 | * </p> |
1549 | * <p> |
1550 | * Lexical or syntax errors detected while parsing can result in |
1551 | * a result node being marked as {@link ASTNode#MALFORMED MALFORMED}. |
1552 | * In more severe failure cases where the parser is unable to |
1553 | * recognize the input, this method returns |
1554 | * a {@link CompilationUnit CompilationUnit} node with at least the |
1555 | * compiler messages. |
1556 | * </p> |
1557 | * <p> |
1558 | * Each node in the subtree (other than the contrived nodes) |
1559 | * carries source range(s) information relating back |
1560 | * to positions in the given source (the given source itself |
1561 | * is not remembered with the AST). |
1562 | * The source range usually begins at the first character of the first token |
1563 | * corresponding to the node; leading whitespace and comments are <b>not</b> |
1564 | * included. The source range usually extends through the last character of |
1565 | * the last token corresponding to the node; trailing whitespace and |
1566 | * comments are <b>not</b> included. There are a handful of exceptions |
1567 | * (including the various body declarations); the |
1568 | * specification for these node type spells out the details. |
1569 | * Source ranges nest properly: the source range for a child is always |
1570 | * within the source range of its parent, and the source ranges of sibling |
1571 | * nodes never overlap. |
1572 | * </p> |
1573 | * <p> |
1574 | * This method does not compute binding information; all |
1575 | * <code>resolveBinding</code> |
1576 | * methods applied to nodes of the resulting AST return <code>null</code>. |
1577 | * </p> |
1578 | * |
1579 | * @return an AST node whose type depends on the kind of parse |
1580 | * requested, with a fallback to a <code>CompilationUnit</code> |
1581 | * in the case of severe parsing errors |
1582 | * @see ASTNode#getStartPosition() |
1583 | * @see ASTNode#getLength() |
1584 | */ |
1585 | private ASTNode internalCreateASTForKind() { |
1586 | final ASTConverter converter = new ASTConverter(this.compilerOptions, false, null); |
1587 | converter.compilationUnitSource = this.rawSource; |
1588 | converter.compilationUnitSourceLength = this.rawSource.length; |
1589 | converter.scanner.setSource(this.rawSource); |
1590 | |
1591 | AST ast = AST.newAST(this.apiLevel, |
1592 | JavaCore.ENABLED.equals(this.compilerOptions.get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES))); |
1593 | ast.setDefaultNodeFlag(ASTNode.ORIGINAL); |
1594 | ast.setBindingResolver(new BindingResolver()); |
1595 | if ((this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0) { |
1596 | ast.setFlag(ICompilationUnit.ENABLE_STATEMENTS_RECOVERY); |
1597 | } |
1598 | ast.scanner.previewEnabled = JavaCore.ENABLED |
1599 | .equals(this.compilerOptions.get(JavaCore.COMPILER_PB_ENABLE_PREVIEW_FEATURES)); |
1600 | converter.setAST(ast); |
1601 | CodeSnippetParsingUtil codeSnippetParsingUtil = new CodeSnippetParsingUtil( |
1602 | (this.bits & CompilationUnitResolver.IGNORE_METHOD_BODIES) != 0); |
1603 | CompilationUnit compilationUnit = ast.newCompilationUnit(); |
1604 | if (this.sourceLength == -1) { |
1605 | this.sourceLength = this.rawSource.length; |
1606 | } |
1607 | switch (this.astKind) { |
1608 | case K_STATEMENTS: |
1609 | ConstructorDeclaration constructorDeclaration = codeSnippetParsingUtil.parseStatements( |
1610 | this.rawSource, |
1611 | this.sourceOffset, |
1612 | this.sourceLength, |
1613 | this.compilerOptions, |
1614 | true, |
1615 | (this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0); |
1616 | RecoveryScannerData data = constructorDeclaration.compilationResult.recoveryScannerData; |
1617 | if (data != null) { |
1618 | Scanner scanner = converter.scanner; |
1619 | converter.scanner = new RecoveryScanner(scanner, data.removeUnused()); |
1620 | converter.docParser.scanner = converter.scanner; |
1621 | converter.scanner.setSource(scanner.source); |
1622 | |
1623 | compilationUnit.setStatementsRecoveryData(data); |
1624 | } |
1625 | RecordedParsingInformation recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation; |
1626 | int[][] comments = recordedParsingInformation.commentPositions; |
1627 | if (comments != null) { |
1628 | converter.buildCommentsTable(compilationUnit, comments); |
1629 | } |
1630 | compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); |
1631 | Block block = ast.newBlock(); |
1632 | block.setSourceRange(this.sourceOffset, this.sourceOffset + this.sourceLength); |
1633 | ExplicitConstructorCall constructorCall = constructorDeclaration.constructorCall; |
1634 | if (constructorCall != null |
1635 | && constructorCall.accessMode != org.eclipse.jdt.internal.compiler.ast.ExplicitConstructorCall.ImplicitSuper) { |
1636 | block.statements().add(converter.convert(constructorCall)); |
1637 | } |
1638 | org.eclipse.jdt.internal.compiler.ast.Statement[] statements = constructorDeclaration.statements; |
1639 | if (statements != null) { |
1640 | int statementsLength = statements.length; |
1641 | for (int i = 0; i < statementsLength; i++) { |
1642 | if (statements[i] instanceof org.eclipse.jdt.internal.compiler.ast.LocalDeclaration) { |
1643 | converter.checkAndAddMultipleLocalDeclaration(statements, i, block.statements()); |
1644 | } else { |
1645 | Statement statement = converter.convert(statements[i]); |
1646 | if (statement != null) { |
1647 | block.statements().add(statement); |
1648 | } |
1649 | } |
1650 | } |
1651 | } |
1652 | rootNodeToCompilationUnit(ast, compilationUnit, block, recordedParsingInformation, data); |
1653 | ast.setDefaultNodeFlag(0); |
1654 | ast.setOriginalModificationCount(ast.modificationCount()); |
1655 | return block; |
1656 | case K_EXPRESSION: |
1657 | org.eclipse.jdt.internal.compiler.ast.Expression expression = codeSnippetParsingUtil.parseExpression( |
1658 | this.rawSource, this.sourceOffset, this.sourceLength, this.compilerOptions, true); |
1659 | recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation; |
1660 | comments = recordedParsingInformation.commentPositions; |
1661 | if (comments != null) { |
1662 | converter.buildCommentsTable(compilationUnit, comments); |
1663 | } |
1664 | compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); |
1665 | if (expression != null) { |
1666 | Expression expression2 = converter.convert(expression); |
1667 | rootNodeToCompilationUnit(expression2.getAST(), compilationUnit, expression2, |
1668 | codeSnippetParsingUtil.recordedParsingInformation, null); |
1669 | ast.setDefaultNodeFlag(0); |
1670 | ast.setOriginalModificationCount(ast.modificationCount()); |
1671 | return expression2; |
1672 | } else { |
1673 | CategorizedProblem[] problems = recordedParsingInformation.problems; |
1674 | if (problems != null) { |
1675 | compilationUnit.setProblems(problems); |
1676 | } |
1677 | ast.setDefaultNodeFlag(0); |
1678 | ast.setOriginalModificationCount(ast.modificationCount()); |
1679 | return compilationUnit; |
1680 | } |
1681 | case K_CLASS_BODY_DECLARATIONS: |
1682 | final org.eclipse.jdt.internal.compiler.ast.ASTNode[] nodes = codeSnippetParsingUtil |
1683 | .parseClassBodyDeclarations( |
1684 | this.rawSource, |
1685 | this.sourceOffset, |
1686 | this.sourceLength, |
1687 | this.compilerOptions, |
1688 | true, |
1689 | (this.bits & CompilationUnitResolver.STATEMENT_RECOVERY) != 0); |
1690 | recordedParsingInformation = codeSnippetParsingUtil.recordedParsingInformation; |
1691 | comments = recordedParsingInformation.commentPositions; |
1692 | if (comments != null) { |
1693 | converter.buildCommentsTable(compilationUnit, comments); |
1694 | } |
1695 | compilationUnit.setLineEndTable(recordedParsingInformation.lineEnds); |
1696 | if (nodes != null) { |
1697 | // source has no syntax error or the statement recovery is enabled |
1698 | TypeDeclaration typeDeclaration = converter.convert(nodes); |
1699 | typeDeclaration.setSourceRange(this.sourceOffset, this.sourceOffset + this.sourceLength); |
1700 | rootNodeToCompilationUnit(typeDeclaration.getAST(), compilationUnit, typeDeclaration, |
1701 | codeSnippetParsingUtil.recordedParsingInformation, null); |
1702 | ast.setDefaultNodeFlag(0); |
1703 | ast.setOriginalModificationCount(ast.modificationCount()); |
1704 | return typeDeclaration; |
1705 | } else { |
1706 | // source has syntax error and the statement recovery is disabled |
1707 | CategorizedProblem[] problems = recordedParsingInformation.problems; |
1708 | if (problems != null) { |
1709 | compilationUnit.setProblems(problems); |
1710 | } |
1711 | ast.setDefaultNodeFlag(0); |
1712 | ast.setOriginalModificationCount(ast.modificationCount()); |
1713 | return compilationUnit; |
1714 | } |
1715 | } |
1716 | throw new IllegalStateException(); |
1717 | } |
1718 | |
1719 | private void propagateErrors(ASTNode astNode, CategorizedProblem[] problems, RecoveryScannerData data) { |
1720 | astNode.accept(new ASTSyntaxErrorPropagator(problems)); |
1721 | if (data != null) { |
1722 | astNode.accept(new ASTRecoveryPropagator(problems, data)); |
1723 | } |
1724 | } |
1725 | |
1726 | private void rootNodeToCompilationUnit(AST ast, CompilationUnit compilationUnit, ASTNode node, |
1727 | RecordedParsingInformation recordedParsingInformation, RecoveryScannerData data) { |
1728 | final int problemsCount = recordedParsingInformation.problemsCount; |
1729 | switch (node.getNodeType()) { |
1730 | case ASTNode.BLOCK: { |
1731 | Block block = (Block) node; |
1732 | if (problemsCount != 0) { |
1733 | // propagate and record problems |
1734 | final CategorizedProblem[] problems = recordedParsingInformation.problems; |
1735 | propagateErrors(block, problems, data); |
1736 | compilationUnit.setProblems(problems); |
1737 | } |
1738 | TypeDeclaration typeDeclaration = ast.newTypeDeclaration(); |
1739 | Initializer initializer = ast.newInitializer(); |
1740 | initializer.setBody(block); |
1741 | typeDeclaration.bodyDeclarations().add(initializer); |
1742 | compilationUnit.types().add(typeDeclaration); |
1743 | } |
1744 | break; |
1745 | case ASTNode.TYPE_DECLARATION: { |
1746 | TypeDeclaration typeDeclaration = (TypeDeclaration) node; |
1747 | if (problemsCount != 0) { |
1748 | // propagate and record problems |
1749 | final CategorizedProblem[] problems = recordedParsingInformation.problems; |
1750 | propagateErrors(typeDeclaration, problems, data); |
1751 | compilationUnit.setProblems(problems); |
1752 | } |
1753 | compilationUnit.types().add(typeDeclaration); |
1754 | } |
1755 | break; |
1756 | default: |
1757 | if (node instanceof Expression) { |
1758 | Expression expression = (Expression) node; |
1759 | if (problemsCount != 0) { |
1760 | // propagate and record problems |
1761 | final CategorizedProblem[] problems = recordedParsingInformation.problems; |
1762 | propagateErrors(expression, problems, data); |
1763 | compilationUnit.setProblems(problems); |
1764 | } |
1765 | ExpressionStatement expressionStatement = ast.newExpressionStatement(expression); |
1766 | Block block = ast.newBlock(); |
1767 | block.statements().add(expressionStatement); |
1768 | Initializer initializer = ast.newInitializer(); |
1769 | initializer.setBody(block); |
1770 | TypeDeclaration typeDeclaration = ast.newTypeDeclaration(); |
1771 | typeDeclaration.bodyDeclarations().add(initializer); |
1772 | compilationUnit.types().add(typeDeclaration); |
1773 | } |
1774 | } |
1775 | } |
1776 | } |
1777 |
Members