1 | /******************************************************************************* |
---|---|
2 | * Copyright (c) 2000, 2019 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 | *******************************************************************************/ |
14 | |
15 | package org.eclipse.jdt.core.dom; |
16 | |
17 | import java.util.ArrayList; |
18 | import java.util.Arrays; |
19 | import java.util.Collections; |
20 | import java.util.List; |
21 | import java.util.Map; |
22 | |
23 | import org.eclipse.jdt.core.IJavaElement; |
24 | import org.eclipse.jdt.core.ITypeRoot; |
25 | import org.eclipse.jdt.core.compiler.IProblem; |
26 | import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; |
27 | import org.eclipse.jdt.internal.compiler.parser.Scanner; |
28 | import org.eclipse.jdt.internal.compiler.util.Util; |
29 | |
30 | /** |
31 | * Java compilation unit AST node type. This is the type of the root of an AST. |
32 | * In JLS9 and later, this node can also contain a ModuleDeclaration (with a |
33 | * completely different grammar). |
34 | * <p> |
35 | * The source range for this type of node is ordinarily the entire source file, |
36 | * including leading and trailing whitespace and comments. |
37 | * </p> |
38 | * |
39 | * <pre> |
40 | * CompilationUnit: |
41 | * OrdinaryCompilationUnit |
42 | * ModularCompilationUnit |
43 | * |
44 | * OrdinaryCompilationUnit: |
45 | * [ PackageDeclaration ] |
46 | * { ImportDeclaration } |
47 | * { TypeDeclaration | EnumDeclaration | AnnotationTypeDeclaration | <b>;</b> } |
48 | * |
49 | * ModularCompilationUnit: |
50 | * {ImportDeclaration} |
51 | * ModuleDeclaration |
52 | * </pre> |
53 | * |
54 | * @since 2.0 |
55 | * @noinstantiate This class is not intended to be instantiated by clients. |
56 | * @noextend This class is not intended to be subclassed by clients. |
57 | */ |
58 | @SuppressWarnings({ "rawtypes", "unchecked" }) |
59 | public class CompilationUnit extends ASTNode { |
60 | |
61 | /** |
62 | * Canonical empty list of messages. |
63 | */ |
64 | private static final Message[] EMPTY_MESSAGES = new Message[0]; |
65 | |
66 | /** |
67 | * Canonical empty list of problems. |
68 | */ |
69 | private static final IProblem[] EMPTY_PROBLEMS = new IProblem[0]; |
70 | |
71 | /** |
72 | * The "imports" structural property of this node type (element type: |
73 | * {@link ImportDeclaration}). |
74 | * |
75 | * @since 3.0 |
76 | */ |
77 | public static final ChildListPropertyDescriptor IMPORTS_PROPERTY = new ChildListPropertyDescriptor( |
78 | CompilationUnit.class, "imports", ImportDeclaration.class, NO_CYCLE_RISK); //$NON-NLS-1$ |
79 | |
80 | /** |
81 | * The "package" structural property of this node type (child type: |
82 | * {@link PackageDeclaration}). |
83 | * |
84 | * @since 3.0 |
85 | */ |
86 | public static final ChildPropertyDescriptor PACKAGE_PROPERTY = new ChildPropertyDescriptor(CompilationUnit.class, |
87 | "package", PackageDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ |
88 | |
89 | /** |
90 | * The "module" structural property of this node type (child type: |
91 | * {@link ModuleDeclaration}) (added in JLS9 API). |
92 | * |
93 | * @since 3.14 |
94 | */ |
95 | public static final ChildPropertyDescriptor MODULE_PROPERTY = new ChildPropertyDescriptor(CompilationUnit.class, |
96 | "module", ModuleDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ |
97 | |
98 | /** |
99 | * A list of property descriptors (element type: |
100 | * {@link StructuralPropertyDescriptor}), |
101 | * or null if uninitialized. |
102 | * |
103 | * @since 3.0 |
104 | */ |
105 | private static final List PROPERTY_DESCRIPTORS; |
106 | |
107 | /** |
108 | * A list of property descriptors (element type: |
109 | * {@link StructuralPropertyDescriptor}), |
110 | * or null if uninitialized. |
111 | * |
112 | * @since 3.14 |
113 | */ |
114 | private static final List PROPERTY_DESCRIPTORS_9_0; |
115 | |
116 | /** |
117 | * The "types" structural property of this node type (element type: |
118 | * {@link AbstractTypeDeclaration}). |
119 | * |
120 | * @since 3.0 |
121 | */ |
122 | public static final ChildListPropertyDescriptor TYPES_PROPERTY = new ChildListPropertyDescriptor( |
123 | CompilationUnit.class, "types", AbstractTypeDeclaration.class, CYCLE_RISK); //$NON-NLS-1$ |
124 | |
125 | static { |
126 | List properyList = new ArrayList(4); |
127 | createPropertyList(CompilationUnit.class, properyList); |
128 | addProperty(PACKAGE_PROPERTY, properyList); |
129 | addProperty(IMPORTS_PROPERTY, properyList); |
130 | addProperty(TYPES_PROPERTY, properyList); |
131 | PROPERTY_DESCRIPTORS = reapPropertyList(properyList); |
132 | |
133 | properyList = new ArrayList(5); |
134 | createPropertyList(CompilationUnit.class, properyList); |
135 | addProperty(PACKAGE_PROPERTY, properyList); |
136 | addProperty(IMPORTS_PROPERTY, properyList); |
137 | addProperty(TYPES_PROPERTY, properyList); |
138 | addProperty(MODULE_PROPERTY, properyList); |
139 | PROPERTY_DESCRIPTORS_9_0 = reapPropertyList(properyList); |
140 | } |
141 | |
142 | /** |
143 | * Returns a list of structural property descriptors for this node type. |
144 | * Clients must not modify the result. |
145 | * |
146 | * @param apiLevel the API level; one of the |
147 | * <code>AST.JLS*</code> constants |
148 | * |
149 | * @return a list of property descriptors (element type: |
150 | * {@link StructuralPropertyDescriptor}) |
151 | * @since 3.0 |
152 | */ |
153 | public static List propertyDescriptors(int apiLevel) { |
154 | if (apiLevel < AST.JLS9_INTERNAL) |
155 | return PROPERTY_DESCRIPTORS; |
156 | else |
157 | return PROPERTY_DESCRIPTORS_9_0; |
158 | } |
159 | |
160 | /** |
161 | * The comment mapper, or <code>null</code> if none; |
162 | * initially <code>null</code>. |
163 | * |
164 | * @since 3.0 |
165 | */ |
166 | private DefaultCommentMapper commentMapper = null; |
167 | |
168 | /** |
169 | * The Java type root (an <code>org.eclipse.jdt.core.ICompilationUnit</code> or |
170 | * an <code>org.eclipse.jdt.core.IClassFile</code>) |
171 | * this compilation unit was created from, or <code>null</code> if it was not |
172 | * created from a Java type root. |
173 | */ |
174 | private ITypeRoot typeRoot = null; |
175 | |
176 | /** |
177 | * The list of import declarations in textual order order; |
178 | * initially none (elementType: <code>ImportDeclaration</code>). |
179 | */ |
180 | private ASTNode.NodeList imports = new ASTNode.NodeList(IMPORTS_PROPERTY); |
181 | |
182 | /** |
183 | * Line end table. If <code>lineEndTable[i] == p</code> then the |
184 | * line number <code>i+1</code> ends at character position |
185 | * <code>p</code>. Except for the last line, the positions are that |
186 | * of the last character of the line delimiter. |
187 | * For example, the source string <code>A\nB\nC</code> has |
188 | * line end table {1, 3} (if \n is one character). |
189 | */ |
190 | private int[] lineEndTable = Util.EMPTY_INT_ARRAY; |
191 | |
192 | /** |
193 | * Messages reported by the compiler during parsing or name resolution. |
194 | */ |
195 | private Message[] messages; |
196 | |
197 | /** |
198 | * The comment list (element type: {@link Comment}, |
199 | * or <code>null</code> if none; initially <code>null</code>. |
200 | * |
201 | * @since 3.0 |
202 | */ |
203 | private List optionalCommentList = null; |
204 | |
205 | /** |
206 | * The comment table, or <code>null</code> if none; initially |
207 | * <code>null</code>. This array is the storage underlying |
208 | * the <code>optionalCommentList</code> ArrayList. |
209 | * |
210 | * @since 3.0 |
211 | */ |
212 | Comment[] optionalCommentTable = null; |
213 | |
214 | /** |
215 | * The package declaration, or <code>null</code> if none; initially |
216 | * <code>null</code>. |
217 | */ |
218 | private PackageDeclaration optionalPackageDeclaration = null; |
219 | |
220 | /** |
221 | * The module declaration, or <code>null</code> if none; initially |
222 | * <code>null</code>. |
223 | */ |
224 | private ModuleDeclaration module = null; |
225 | /** |
226 | * Problems reported by the compiler during parsing or name resolution. |
227 | */ |
228 | private IProblem[] problems = EMPTY_PROBLEMS; |
229 | |
230 | /** |
231 | * Internal data used to perform statements recovery. |
232 | */ |
233 | private Object statementsRecoveryData; |
234 | |
235 | /** |
236 | * The list of type declarations in textual order order; |
237 | * initially none (elementType: <code>AbstractTypeDeclaration</code>) |
238 | */ |
239 | private ASTNode.NodeList types = new ASTNode.NodeList(TYPES_PROPERTY); |
240 | |
241 | /** |
242 | * Creates a new AST node for a compilation owned by the given AST. |
243 | * The compilation unit initially has no package declaration, no |
244 | * import declarations, and no type declarations. |
245 | * <p> |
246 | * N.B. This constructor is package-private; all subclasses must be |
247 | * declared in the same package; clients are unable to declare |
248 | * additional subclasses. |
249 | * </p> |
250 | * |
251 | * @param ast the AST that is to own this node |
252 | */ |
253 | CompilationUnit(AST ast) { |
254 | super(ast); |
255 | } |
256 | |
257 | @Override |
258 | void accept0(ASTVisitor visitor) { |
259 | boolean visitChildren = visitor.visit(this); |
260 | if (visitChildren) { |
261 | // visit children in normal left to right reading order |
262 | if (this.ast.apiLevel >= AST.JLS9_INTERNAL) { |
263 | acceptChild(visitor, getModule()); |
264 | } |
265 | acceptChild(visitor, getPackage()); |
266 | acceptChildren(visitor, this.imports); |
267 | acceptChildren(visitor, this.types); |
268 | } |
269 | visitor.endVisit(this); |
270 | } |
271 | |
272 | @Override |
273 | ASTNode clone0(AST target) { |
274 | CompilationUnit result = new CompilationUnit(target); |
275 | // n.b do not copy line number table or messages |
276 | result.setSourceRange(getStartPosition(), getLength()); |
277 | if (this.ast.apiLevel >= AST.JLS9_INTERNAL) { |
278 | result.setModule((ModuleDeclaration) ASTNode.copySubtree(target, getModule())); |
279 | } |
280 | result.setPackage( |
281 | (PackageDeclaration) ASTNode.copySubtree(target, getPackage())); |
282 | result.imports().addAll(ASTNode.copySubtrees(target, imports())); |
283 | result.types().addAll(ASTNode.copySubtrees(target, types())); |
284 | return result; |
285 | } |
286 | |
287 | /** |
288 | * Returns the column number corresponding to the given source character |
289 | * position in the original source string. Column number are zero-based. |
290 | * Return <code>-1</code> if it is beyond the valid range or <code>-2</code> |
291 | * if the column number information is unknown. |
292 | * |
293 | * @param position a 0-based character position, possibly |
294 | * negative or out of range |
295 | * @return the 0-based column number, or <code>-1</code> if the character |
296 | * position does not correspond to a source line in the original |
297 | * source file or <code>-2</code> if column number information is |
298 | * unknown for this |
299 | * compilation unit |
300 | * @see ASTParser |
301 | * @since 3.2 |
302 | */ |
303 | public int getColumnNumber(final int position) { |
304 | if (this.lineEndTable == null) |
305 | return -2; |
306 | final int line = getLineNumber(position); |
307 | if (line == -1) { |
308 | return -1; |
309 | } |
310 | if (line == 1) { |
311 | if (position >= getStartPosition() + getLength()) |
312 | return -1; |
313 | return position; |
314 | } |
315 | // length is different from 0 |
316 | int length = this.lineEndTable.length; |
317 | // -1 to for one-based to zero-based conversion. |
318 | // -1, again, to get previous line. |
319 | final int previousLineOffset = this.lineEndTable[line - 2]; |
320 | // previousLineOffset + 1 is the first character of the current line |
321 | final int offsetForLine = previousLineOffset + 1; |
322 | final int currentLineEnd = line == length + 1 ? getStartPosition() + getLength() - 1 |
323 | : this.lineEndTable[line - 1]; |
324 | if (offsetForLine > currentLineEnd) { |
325 | return -1; |
326 | } else { |
327 | return position - offsetForLine; |
328 | } |
329 | } |
330 | |
331 | /** |
332 | * Finds the corresponding AST node in the given compilation unit from |
333 | * which the given binding originated. Returns <code>null</code> if the |
334 | * binding does not correspond to any node in this compilation unit. |
335 | * This method always returns <code>null</code> if bindings were not requested |
336 | * when this AST was built. |
337 | * <p> |
338 | * The following table indicates the expected node type for the various |
339 | * different kinds of bindings: |
340 | * <ul> |
341 | * <li>package - a <code>PackageDeclaration</code></li> |
342 | * <li>class or interface - a <code>TypeDeclaration</code> or a |
343 | * <code>AnonymousClassDeclaration</code> (for anonymous classes)</li> |
344 | * <li>primitive type - none</li> |
345 | * <li>array type - none</li> |
346 | * <li>field - a <code>VariableDeclarationFragment</code> in a |
347 | * <code>FieldDeclaration</code></li> |
348 | * <li>local variable - a <code>SingleVariableDeclaration</code>, or |
349 | * a <code>VariableDeclarationFragment</code> in a |
350 | * <code>VariableDeclarationStatement</code> or |
351 | * <code>VariableDeclarationExpression</code></li> |
352 | * <li>method - a <code>MethodDeclaration</code></li> |
353 | * <li>constructor - a <code>MethodDeclaration</code></li> |
354 | * <li>annotation type - an <code>AnnotationTypeDeclaration</code></li> |
355 | * <li>annotation type member - an |
356 | * <code>AnnotationTypeMemberDeclaration</code></li> |
357 | * <li>enum type - an <code>EnumDeclaration</code></li> |
358 | * <li>enum constant - an <code>EnumConstantDeclaration</code></li> |
359 | * <li>type variable - a <code>TypeParameter</code></li> |
360 | * <li>capture binding - none</li> |
361 | * <li>annotation binding - an <code>Annotation</code></li> |
362 | * <li>member value pair binding - an <code>MemberValuePair</code>, |
363 | * or <code>null</code> if it represents a default value or a single member |
364 | * value</li> |
365 | * </ul> |
366 | * <p> |
367 | * For parameterized or raw type bindings, the declaring node is |
368 | * that of the corresponding generic type. And for parameterized or raw |
369 | * method bindings, the declaring node is that of the corresponding |
370 | * generic method. |
371 | * </p> |
372 | * <p> |
373 | * Each call to |
374 | * {@link ASTParser#createAST(org.eclipse.core.runtime.IProgressMonitor)} with a |
375 | * request for bindings |
376 | * gives rise to separate universe of binding objects. This method always |
377 | * returns |
378 | * <code>null</code> when the binding object comes from a different AST. |
379 | * Use <code>findDeclaringNode(binding.getKey())</code> when the binding comes |
380 | * from a different AST. |
381 | * </p> |
382 | * |
383 | * @param binding the binding |
384 | * @return the corresponding node where the given binding is declared, |
385 | * or <code>null</code> if the binding does not correspond to a node in |
386 | * this |
387 | * compilation unit or if bindings were not requested when this AST was |
388 | * built |
389 | * @see #findDeclaringNode(String) |
390 | */ |
391 | public ASTNode findDeclaringNode(IBinding binding) { |
392 | return this.ast.getBindingResolver().findDeclaringNode(binding); |
393 | } |
394 | |
395 | /** |
396 | * Finds the corresponding AST node in the given compilation unit from |
397 | * which the binding with the given key originated. Returns |
398 | * <code>null</code> if the corresponding node cannot be determined. |
399 | * This method always returns <code>null</code> if bindings were not requested |
400 | * when this AST was built. |
401 | * <p> |
402 | * The following table indicates the expected node type for the various |
403 | * different kinds of binding keys: |
404 | * <ul> |
405 | * <li></li> |
406 | * <li>package - a <code>PackageDeclaration</code></li> |
407 | * <li>class or interface - a <code>TypeDeclaration</code> or a |
408 | * <code>AnonymousClassDeclaration</code> (for anonymous classes)</li> |
409 | * <li>primitive type - none</li> |
410 | * <li>array type - none</li> |
411 | * <li>field - a <code>VariableDeclarationFragment</code> in a |
412 | * <code>FieldDeclaration</code></li> |
413 | * <li>local variable - a <code>SingleVariableDeclaration</code>, or |
414 | * a <code>VariableDeclarationFragment</code> in a |
415 | * <code>VariableDeclarationStatement</code> or |
416 | * <code>VariableDeclarationExpression</code></li> |
417 | * <li>method - a <code>MethodDeclaration</code></li> |
418 | * <li>constructor - a <code>MethodDeclaration</code></li> |
419 | * <li>annotation type - an <code>AnnotationTypeDeclaration</code></li> |
420 | * <li>annotation type member - an |
421 | * <code>AnnotationTypeMemberDeclaration</code></li> |
422 | * <li>enum type - an <code>EnumDeclaration</code></li> |
423 | * <li>enum constant - an <code>EnumConstantDeclaration</code></li> |
424 | * <li>type variable - a <code>TypeParameter</code></li> |
425 | * <li>capture binding - none</li> |
426 | * </ul> |
427 | * For parameterized or raw type bindings, the declaring node is |
428 | * that of the corresponding generic type. And for parameterized or raw |
429 | * method bindings, the declaring node is that of the corresponding |
430 | * generic method. |
431 | * |
432 | * @param key the binding key, or <code>null</code> |
433 | * @return the corresponding node where a binding with the given |
434 | * key is declared, or <code>null</code> if the key is <code>null</code> |
435 | * or if the key does not correspond to a node in this compilation unit |
436 | * or if bindings were not requested when this AST was built |
437 | * @see IBinding#getKey() |
438 | * @since 2.1 |
439 | */ |
440 | public ASTNode findDeclaringNode(String key) { |
441 | return this.ast.getBindingResolver().findDeclaringNode(key); |
442 | } |
443 | |
444 | /** |
445 | * Returns a list of the comments encountered while parsing |
446 | * this compilation unit. |
447 | * <p> |
448 | * Since the Java language allows comments to appear most anywhere |
449 | * in the source text, it is problematic to locate comments in relation |
450 | * to the structure of an AST. The one exception is doc comments |
451 | * which, by convention, immediately precede type, field, and |
452 | * method declarations; these comments are located in the AST |
453 | * by {@link BodyDeclaration#getJavadoc BodyDeclaration.getJavadoc}. |
454 | * Other comments do not show up in the AST. The table of comments |
455 | * is provided for clients that need to find the source ranges of |
456 | * all comments in the original source string. It includes entries |
457 | * for comments of all kinds (line, block, and doc), arranged in order |
458 | * of increasing source position. |
459 | * </p> |
460 | * <p> |
461 | * Note on comment parenting: The {@link ASTNode#getParent() getParent()} |
462 | * of a doc comment associated with a body declaration is the body |
463 | * declaration node; for these comment nodes |
464 | * {@link ASTNode#getRoot() getRoot()} will return the compilation unit |
465 | * (assuming an unmodified AST) reflecting the fact that these nodes |
466 | * are property located in the AST for the compilation unit. |
467 | * However, for other comment nodes, {@link ASTNode#getParent() getParent()} |
468 | * will return <code>null</code>, and {@link ASTNode#getRoot() getRoot()} |
469 | * will return the comment node itself, indicating that these comment nodes |
470 | * are not directly connected to the AST for the compilation unit. The |
471 | * {@link Comment#getAlternateRoot Comment.getAlternateRoot} |
472 | * method provides a way to navigate from a comment to its compilation |
473 | * unit. |
474 | * </p> |
475 | * <p> |
476 | * A note on visitors: The only comment nodes that will be visited when |
477 | * visiting a compilation unit are the doc comments parented by body |
478 | * declarations. To visit all comments in normal reading order, iterate |
479 | * over the comment table and call {@link ASTNode#accept(ASTVisitor) accept} |
480 | * on each element. |
481 | * </p> |
482 | * <p> |
483 | * Clients cannot modify the resulting list. |
484 | * </p> |
485 | * |
486 | * @return an unmodifiable list of comments in increasing order of source |
487 | * start position (element type: {@link Comment}, or <code>null</code> |
488 | * if comment information |
489 | * for this compilation unit is not available |
490 | * @see ASTParser |
491 | * @since 3.0 |
492 | */ |
493 | public List getCommentList() { |
494 | return this.optionalCommentList; |
495 | } |
496 | |
497 | /** |
498 | * Returns the internal comment mapper. |
499 | * |
500 | * @return the comment mapper, or <code>null</code> if none. |
501 | * @since 3.0 |
502 | */ |
503 | DefaultCommentMapper getCommentMapper() { |
504 | return this.commentMapper; |
505 | } |
506 | |
507 | /** |
508 | * Returns the extended source length of the given node. Unlike |
509 | * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, |
510 | * the extended source range may include comments and whitespace |
511 | * immediately before or after the normal source range for the node. |
512 | * |
513 | * @param node the node |
514 | * @return a (possibly 0) length, or <code>0</code> |
515 | * if no source position information is recorded for this node |
516 | * @see #getExtendedStartPosition(ASTNode) |
517 | * @since 3.0 |
518 | */ |
519 | public int getExtendedLength(ASTNode node) { |
520 | if (node == null) { |
521 | throw new IllegalArgumentException(); |
522 | } |
523 | if (this.commentMapper == null || node.getAST() != getAST()) { |
524 | // fall back: use best info available |
525 | return node.getLength(); |
526 | } else { |
527 | return this.commentMapper.getExtendedLength(node); |
528 | } |
529 | } |
530 | |
531 | /** |
532 | * Returns the extended start position of the given node. Unlike |
533 | * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, |
534 | * the extended source range may include comments and whitespace |
535 | * immediately before or after the normal source range for the node. |
536 | * |
537 | * @param node the node |
538 | * @return the 0-based character index, or <code>-1</code> |
539 | * if no source position information is recorded for this node |
540 | * @see #getExtendedLength(ASTNode) |
541 | * @since 3.0 |
542 | */ |
543 | public int getExtendedStartPosition(ASTNode node) { |
544 | if (node == null) { |
545 | throw new IllegalArgumentException(); |
546 | } |
547 | if (this.commentMapper == null || node.getAST() != getAST()) { |
548 | // fall back: use best info available |
549 | return node.getStartPosition(); |
550 | } else { |
551 | return this.commentMapper.getExtendedStartPosition(node); |
552 | } |
553 | } |
554 | |
555 | /** |
556 | * The Java element (an <code>org.eclipse.jdt.core.ICompilationUnit</code> or an |
557 | * <code>org.eclipse.jdt.core.IClassFile</code>) |
558 | * this compilation unit was created from, or <code>null</code> if it was not |
559 | * created from a Java element. |
560 | * |
561 | * @return the Java element this compilation unit was created from, or |
562 | * <code>null</code> if none |
563 | * @since 3.1 |
564 | * @see #getTypeRoot() |
565 | */ |
566 | public IJavaElement getJavaElement() { |
567 | return this.typeRoot; |
568 | } |
569 | |
570 | /** |
571 | * Returns the list of messages reported by the compiler during the parsing |
572 | * or the type checking of this compilation unit. This list might be a subset of |
573 | * errors detected and reported by a Java compiler. |
574 | * <p> |
575 | * This list of messages is suitable for simple clients that do little |
576 | * more than log the messages or display them to the user. Clients that |
577 | * need further details should call <code>getProblems</code> to get |
578 | * compiler problem objects. |
579 | * </p> |
580 | * |
581 | * @return the list of messages, possibly empty |
582 | * @see #getProblems() |
583 | * @see ASTParser |
584 | */ |
585 | public Message[] getMessages() { |
586 | if (this.messages == null) { |
587 | int problemLength = this.problems.length; |
588 | if (problemLength == 0) { |
589 | this.messages = EMPTY_MESSAGES; |
590 | } else { |
591 | this.messages = new Message[problemLength]; |
592 | for (int i = 0; i < problemLength; i++) { |
593 | IProblem problem = this.problems[i]; |
594 | int start = problem.getSourceStart(); |
595 | int end = problem.getSourceEnd(); |
596 | this.messages[i] = new Message(problem.getMessage(), start, end - start + 1); |
597 | } |
598 | } |
599 | } |
600 | return this.messages; |
601 | } |
602 | |
603 | @Override |
604 | final int getNodeType0() { |
605 | return COMPILATION_UNIT; |
606 | } |
607 | |
608 | /** |
609 | * Returns the node for the module declaration of this compilation |
610 | * unit, or <code>null</code> if this compilation unit is not a module info. |
611 | * |
612 | * @return the module declaration node, or <code>null</code> if none |
613 | * @exception UnsupportedOperationException if this operation is used below JLS9 |
614 | * @since 3.14 |
615 | */ |
616 | public ModuleDeclaration getModule() { |
617 | unsupportedBelow9(); |
618 | return this.module; |
619 | } |
620 | |
621 | /** |
622 | * Returns the node for the package declaration of this compilation |
623 | * unit, or <code>null</code> if this compilation unit is in the |
624 | * default package. |
625 | * |
626 | * @return the package declaration node, or <code>null</code> if none |
627 | */ |
628 | public PackageDeclaration getPackage() { |
629 | return this.optionalPackageDeclaration; |
630 | } |
631 | |
632 | /** |
633 | * Given a line number and column number, returns the corresponding |
634 | * position in the original source string. |
635 | * Returns -2 if no line number information is available for this |
636 | * compilation unit. |
637 | * Returns the total size of the source string if <code>line</code> |
638 | * is greater than the actual number lines in the unit. |
639 | * Returns -1 if <code>column</code> is less than 0, |
640 | * or the position of the last character of the line if <code>column</code> |
641 | * is beyond the legal range, or the given line number is less than one. |
642 | * |
643 | * @param line the one-based line number |
644 | * @param column the zero-based column number |
645 | * @return the 0-based character position in the source string; |
646 | * <code>-2</code> if line/column number information is not known |
647 | * for this compilation unit or <code>-1</code> the inputs are not valid |
648 | * @since 3.2 |
649 | */ |
650 | public int getPosition(int line, int column) { |
651 | if (this.lineEndTable == null) |
652 | return -2; |
653 | if (line < 1 || column < 0) |
654 | return -1; |
655 | int length; |
656 | if ((length = this.lineEndTable.length) == 0) { |
657 | if (line != 1) |
658 | return -1; |
659 | return column >= getStartPosition() + getLength() ? -1 : column; |
660 | } |
661 | if (line == 1) { |
662 | final int endOfLine = this.lineEndTable[0]; |
663 | return column > endOfLine ? -1 : column; |
664 | } else if (line > length + 1) { |
665 | // greater than the number of lines in the source string. |
666 | return -1; |
667 | } |
668 | // -1 to for one-based to zero-based conversion. |
669 | // -1, again, to get previous line. |
670 | final int previousLineOffset = this.lineEndTable[line - 2]; |
671 | // previousLineOffset + 1 is the first character of the current line |
672 | final int offsetForLine = previousLineOffset + 1; |
673 | final int currentLineEnd = line == length + 1 ? getStartPosition() + getLength() - 1 |
674 | : this.lineEndTable[line - 1]; |
675 | if ((offsetForLine + column) > currentLineEnd) { |
676 | return -1; |
677 | } else { |
678 | return offsetForLine + column; |
679 | } |
680 | } |
681 | |
682 | /** |
683 | * Returns the list of detailed problem reports noted by the compiler |
684 | * during the parsing or the type checking of this compilation unit. This |
685 | * list might be a subset of errors detected and reported by a Java |
686 | * compiler. |
687 | * <p> |
688 | * Simple clients that do little more than log the messages or display |
689 | * them to the user should probably call <code>getMessages</code> instead. |
690 | * </p> |
691 | * |
692 | * @return the list of detailed problem objects, possibly empty |
693 | * @see #getMessages() |
694 | * @see ASTParser |
695 | * @since 2.1 |
696 | */ |
697 | public IProblem[] getProblems() { |
698 | return this.problems; |
699 | } |
700 | |
701 | /** |
702 | * Internal method |
703 | * |
704 | * This method return internal data used to perform statements recovery. |
705 | * |
706 | * @return internal data used to perform statements recovery. |
707 | * |
708 | * @noreference This method is not intended to be referenced by clients. |
709 | * @since 3.5 |
710 | */ |
711 | public Object getStatementsRecoveryData() { |
712 | return this.statementsRecoveryData; |
713 | } |
714 | |
715 | /** |
716 | * The Java type root (a {@link org.eclipse.jdt.core.ICompilationUnit |
717 | * compilation unit} or a {@link org.eclipse.jdt.core.IClassFile class file}) |
718 | * this compilation unit was created from, or <code>null</code> if it was not |
719 | * created from a Java type root. |
720 | * |
721 | * @return the Java type root this compilation unit was created from, or |
722 | * <code>null</code> if none |
723 | * @since 3.3 |
724 | */ |
725 | public ITypeRoot getTypeRoot() { |
726 | return this.typeRoot; |
727 | } |
728 | |
729 | /** |
730 | * Returns the live list of nodes for the import declarations of this |
731 | * compilation unit, in order of appearance. |
732 | * |
733 | * @return the live list of import declaration nodes |
734 | * (elementType: {@link ImportDeclaration}) |
735 | */ |
736 | public List imports() { |
737 | return this.imports; |
738 | } |
739 | |
740 | /** |
741 | * Return the index in the whole comments list {@link #getCommentList() } |
742 | * of the first leading comments associated with the given node. |
743 | * |
744 | * @param node the node |
745 | * @return 0-based index of first leading comment or -1 if node has no |
746 | * associated |
747 | * comment before its start position. |
748 | * @since 3.2 |
749 | */ |
750 | public int firstLeadingCommentIndex(ASTNode node) { |
751 | if (node == null) { |
752 | throw new IllegalArgumentException(); |
753 | } |
754 | if (this.commentMapper == null || node.getAST() != getAST()) { |
755 | return -1; |
756 | } |
757 | return this.commentMapper.firstLeadingCommentIndex(node); |
758 | } |
759 | |
760 | /** |
761 | * Return the index in the whole comments list {@link #getCommentList() } |
762 | * of the last trailing comments associated with the given node. |
763 | * |
764 | * @param node the node |
765 | * @return 0-based index of last trailing comment or -1 if node has no |
766 | * associated comment after its end position. |
767 | * @since 3.2 |
768 | */ |
769 | public int lastTrailingCommentIndex(ASTNode node) { |
770 | if (node == null) { |
771 | throw new IllegalArgumentException(); |
772 | } |
773 | if (this.commentMapper == null || node.getAST() != getAST()) { |
774 | return -1; |
775 | } |
776 | return this.commentMapper.lastTrailingCommentIndex(node); |
777 | } |
778 | |
779 | /** |
780 | * Initializes the internal comment mapper with the given |
781 | * scanner. |
782 | * |
783 | * @param scanner the scanner |
784 | * @since 3.0 |
785 | */ |
786 | void initCommentMapper(Scanner scanner) { |
787 | this.commentMapper = new DefaultCommentMapper(this.optionalCommentTable); |
788 | this.commentMapper.initialize(this, scanner); |
789 | } |
790 | |
791 | @Override |
792 | final List internalGetChildListProperty(ChildListPropertyDescriptor property) { |
793 | if (property == IMPORTS_PROPERTY) { |
794 | return imports(); |
795 | } |
796 | if (property == TYPES_PROPERTY) { |
797 | return types(); |
798 | } |
799 | // allow default implementation to flag the error |
800 | return super.internalGetChildListProperty(property); |
801 | } |
802 | |
803 | @Override |
804 | final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { |
805 | if (property == MODULE_PROPERTY) { |
806 | if (get) { |
807 | return getModule(); |
808 | } else { |
809 | setModule((ModuleDeclaration) child); |
810 | return null; |
811 | } |
812 | } |
813 | if (property == PACKAGE_PROPERTY) { |
814 | if (get) { |
815 | return getPackage(); |
816 | } else { |
817 | setPackage((PackageDeclaration) child); |
818 | return null; |
819 | } |
820 | } |
821 | // allow default implementation to flag the error |
822 | return super.internalGetSetChildProperty(property, get, child); |
823 | } |
824 | |
825 | @Override |
826 | final List internalStructuralPropertiesForType(int apiLevel) { |
827 | return propertyDescriptors(apiLevel); |
828 | } |
829 | |
830 | /** |
831 | * Returns the line number corresponding to the given source character |
832 | * position in the original source string. The initial line of the |
833 | * compilation unit is numbered 1, and each line extends through the |
834 | * last character of the end-of-line delimiter. The very last line extends |
835 | * through the end of the source string and has no line delimiter. |
836 | * For example, the source string <code>class A\n{\n}</code> has 3 lines |
837 | * corresponding to inclusive character ranges [0,7], [8,9], and [10,10]. |
838 | * Returns 1 for a character position that does not correspond to any |
839 | * source line, or if no line number information is available for this |
840 | * compilation unit. |
841 | * |
842 | * @param position a 0-based character position, possibly |
843 | * negative or out of range |
844 | * @return the 1-based line number, or <code>1</code> if the character |
845 | * position does not correspond to a source line in the original |
846 | * source file or if line number information is not known for this |
847 | * compilation unit |
848 | * @deprecated Use getLineNumber(int) instead. Be careful to handle the negative |
849 | * values. |
850 | * @see ASTParser |
851 | * @see #getLineNumber(int) |
852 | */ |
853 | public int lineNumber(int position) { |
854 | int lineNumber = getLineNumber(position); |
855 | return lineNumber < 1 ? 1 : lineNumber; |
856 | } |
857 | |
858 | /** |
859 | * Returns the line number corresponding to the given source character |
860 | * position in the original source string. The initial line of the |
861 | * compilation unit is numbered 1, and each line extends through the |
862 | * last character of the end-of-line delimiter. The very last line extends |
863 | * through the end of the source string and has no line delimiter. |
864 | * For example, the source string <code>class A\n{\n}</code> has 3 lines |
865 | * corresponding to inclusive character ranges [0,7], [8,9], and [10,10]. |
866 | * Returns -1 for a character position that does not correspond to any |
867 | * source line, or -2 if no line number information is available for this |
868 | * compilation unit. |
869 | * |
870 | * @param position a 0-based character position, possibly |
871 | * negative or out of range |
872 | * @return the 1-based line number, or <code>-1</code> if the character |
873 | * position does not correspond to a source line in the original |
874 | * source file or <code>-2</code> if line number information is not |
875 | * known for this |
876 | * compilation unit |
877 | * @see ASTParser |
878 | * @since 3.2 |
879 | */ |
880 | public int getLineNumber(int position) { |
881 | if (this.lineEndTable == null) |
882 | return -2; |
883 | int length; |
884 | if ((length = this.lineEndTable.length) == 0) { |
885 | if (position >= getStartPosition() + getLength()) { |
886 | return -1; |
887 | } |
888 | return 1; |
889 | } |
890 | int low = 0; |
891 | if (position < 0) { |
892 | // position illegal |
893 | return -1; |
894 | } |
895 | if (position <= this.lineEndTable[low]) { |
896 | // before the first line delimiter |
897 | return 1; |
898 | } |
899 | // assert position > lineEndTable[low+1] && low == 0 |
900 | int hi = length - 1; |
901 | if (position > this.lineEndTable[hi]) { |
902 | // position beyond the last line separator |
903 | if (position >= getStartPosition() + getLength()) { |
904 | // this is beyond the end of the source length |
905 | return -1; |
906 | } else { |
907 | return length + 1; |
908 | } |
909 | } |
910 | // assert lineEndTable[low] < position <= lineEndTable[hi] |
911 | // && low == 0 && hi == length - 1 && low < hi |
912 | |
913 | // binary search line end table |
914 | while (true) { |
915 | // invariant lineEndTable[low] < position <= lineEndTable[hi] |
916 | // && 0 <= low < hi <= length - 1 |
917 | // reducing measure hi - low |
918 | if (low + 1 == hi) { |
919 | // assert lineEndTable[low] < position <= lineEndTable[low+1] |
920 | // position is on line low+1 (line number is low+2) |
921 | return low + 2; |
922 | } |
923 | // assert hi - low >= 2, so average is truly in between |
924 | int mid = low + (hi - low) / 2; |
925 | // assert 0 <= low < mid < hi <= length - 1 |
926 | if (position <= this.lineEndTable[mid]) { |
927 | // assert lineEndTable[low] < position <= lineEndTable[mid] |
928 | // && 0 <= low < mid < hi <= length - 1 |
929 | hi = mid; |
930 | } else { |
931 | // position > lineEndTable[mid] |
932 | // assert lineEndTable[mid] < position <= lineEndTable[hi] |
933 | // && 0 <= low < mid < hi <= length - 1 |
934 | low = mid; |
935 | } |
936 | // in both cases, invariant reachieved with reduced measure |
937 | } |
938 | } |
939 | |
940 | @Override |
941 | int memSize() { |
942 | int size = BASE_NODE_SIZE + 8 * 4; |
943 | if (this.lineEndTable != null) { |
944 | size += HEADERS + 4 * this.lineEndTable.length; |
945 | } |
946 | if (this.optionalCommentTable != null) { |
947 | size += HEADERS + 4 * this.optionalCommentTable.length; |
948 | } |
949 | // ignore the space taken up by optionalCommentList |
950 | return size; |
951 | } |
952 | |
953 | /** |
954 | * Enables the recording of changes to this compilation |
955 | * unit and its descendants. The compilation unit must have |
956 | * been created by {@link ASTParser} and still be in |
957 | * its original state. Once recording is on, |
958 | * arbitrary changes to the subtree rooted at this compilation |
959 | * unit are recorded internally. Once the modification has |
960 | * been completed, call {@link #rewrite(IDocument, Map)} to get an object |
961 | * representing the corresponding edits to the original |
962 | * source code string. |
963 | * <p> |
964 | * Note that this way of manipulating an AST only allows a single line of |
965 | * modifications, |
966 | * and it lacks important functionality like |
967 | * {@link ASTRewrite#createStringPlaceholder(String, int) string placeholders} |
968 | * and support for |
969 | * {@link ASTRewrite#createCopyTarget(ASTNode) copying} nodes including comments |
970 | * and formatting. |
971 | * </p> |
972 | * <p> |
973 | * To future-proof your code, <em>consider using an external {@link ASTRewrite} |
974 | * instead</em>, |
975 | * which doesn't suffer from these limitations and allows to modify an AST in a |
976 | * non-destructive way. |
977 | * </p> |
978 | * |
979 | * @exception IllegalArgumentException if this compilation unit is |
980 | * marked as unmodifiable, or if this |
981 | * compilation unit has already |
982 | * been tampered with, or recording has |
983 | * already been enabled |
984 | * @see ASTRewrite |
985 | * @since 3.0 |
986 | */ |
987 | public void recordModifications() { |
988 | getAST().recordModifications(this); |
989 | } |
990 | |
991 | /** |
992 | * Sets the list of the comments encountered while parsing |
993 | * this compilation unit. |
994 | * |
995 | * @param commentTable a list of comments in increasing order |
996 | * of source start position, or <code>null</code> if comment |
997 | * information for this compilation unit is not available |
998 | * @exception IllegalArgumentException if the comment table is |
999 | * not in increasing order of source |
1000 | * position |
1001 | * @see #getCommentList() |
1002 | * @see ASTParser |
1003 | * @since 3.0 |
1004 | */ |
1005 | void setCommentTable(Comment[] commentTable) { |
1006 | // double check table to ensure that all comments have |
1007 | // source positions and are in strictly increasing order |
1008 | if (commentTable == null) { |
1009 | this.optionalCommentList = null; |
1010 | this.optionalCommentTable = null; |
1011 | } else { |
1012 | int nextAvailablePosition = 0; |
1013 | for (int i = 0; i < commentTable.length; i++) { |
1014 | Comment comment = commentTable[i]; |
1015 | if (comment == null) { |
1016 | throw new IllegalArgumentException(); |
1017 | } |
1018 | int start = comment.getStartPosition(); |
1019 | int length = comment.getLength(); |
1020 | if (start < 0 || length < 0 || start < nextAvailablePosition) { |
1021 | throw new IllegalArgumentException(); |
1022 | } |
1023 | nextAvailablePosition = comment.getStartPosition() + comment.getLength(); |
1024 | } |
1025 | this.optionalCommentTable = commentTable; |
1026 | List commentList = Arrays.asList(commentTable); |
1027 | // protect the list from further modification |
1028 | this.optionalCommentList = Collections.unmodifiableList(commentList); |
1029 | } |
1030 | } |
1031 | |
1032 | /** |
1033 | * Sets the Java type root (a {@link org.eclipse.jdt.core.ICompilationUnit |
1034 | * compilation unit} or a {@link org.eclipse.jdt.core.IClassFile class file}) |
1035 | * this compilation unit was created from, or <code>null</code> if it was not |
1036 | * created from a Java type root. |
1037 | * |
1038 | * @param typeRoot the Java type root this compilation unit was created from |
1039 | */ |
1040 | void setTypeRoot(ITypeRoot typeRoot) { |
1041 | this.typeRoot = typeRoot; |
1042 | } |
1043 | |
1044 | /** |
1045 | * Sets the line end table for this compilation unit. |
1046 | * If <code>lineEndTable[i] == p</code> then line number <code>i+1</code> |
1047 | * ends at character position <code>p</code>. Except for the last line, the |
1048 | * positions are that of (the last character of) the line delimiter. |
1049 | * For example, the source string <code>A\nB\nC</code> has |
1050 | * line end table {1, 3, 4}. |
1051 | * |
1052 | * @param lineEndTable the line end table |
1053 | */ |
1054 | void setLineEndTable(int[] lineEndTable) { |
1055 | if (lineEndTable == null) { |
1056 | throw new NullPointerException(); |
1057 | } |
1058 | // alternate root is *not* considered a structural property |
1059 | // but we protect them nevertheless |
1060 | checkModifiable(); |
1061 | this.lineEndTable = lineEndTable; |
1062 | } |
1063 | |
1064 | /** |
1065 | * Sets or clears the module declaration of this compilation unit |
1066 | * node to the given module declaration node. |
1067 | * |
1068 | * @param module the new module declaration node, or |
1069 | * <code>null</code> if this compilation unit does not have a |
1070 | * module |
1071 | * @exception IllegalArgumentException if: |
1072 | * <ul> |
1073 | * <li>the node belongs to a different |
1074 | * AST</li> |
1075 | * <li>the node already has a |
1076 | * parent</li> |
1077 | * </ul> |
1078 | * @exception UnsupportedOperationException if this operation is used below JLS9 |
1079 | * @since 3.14 |
1080 | */ |
1081 | public void setModule(ModuleDeclaration module) { |
1082 | unsupportedBelow9(); |
1083 | ASTNode oldChild = this.module; |
1084 | preReplaceChild(oldChild, module, MODULE_PROPERTY); |
1085 | this.module = module; |
1086 | postReplaceChild(oldChild, module, MODULE_PROPERTY); |
1087 | } |
1088 | |
1089 | /** |
1090 | * Sets or clears the package declaration of this compilation unit |
1091 | * node to the given package declaration node. |
1092 | * |
1093 | * @param pkgDecl the new package declaration node, or |
1094 | * <code>null</code> if this compilation unit does not have a |
1095 | * package |
1096 | * declaration (that is in the default package) |
1097 | * @exception IllegalArgumentException if: |
1098 | * <ul> |
1099 | * <li>the node belongs to a different |
1100 | * AST</li> |
1101 | * <li>the node already has a parent</li> |
1102 | * </ul> |
1103 | */ |
1104 | public void setPackage(PackageDeclaration pkgDecl) { |
1105 | ASTNode oldChild = this.optionalPackageDeclaration; |
1106 | preReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY); |
1107 | this.optionalPackageDeclaration = pkgDecl; |
1108 | postReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY); |
1109 | } |
1110 | |
1111 | /** |
1112 | * Sets the array of problems reported by the compiler during the parsing or |
1113 | * name resolution of this compilation unit. |
1114 | * |
1115 | * @param problems the list of problems |
1116 | */ |
1117 | void setProblems(IProblem[] problems) { |
1118 | if (problems == null) { |
1119 | throw new IllegalArgumentException(); |
1120 | } |
1121 | this.problems = problems; |
1122 | } |
1123 | |
1124 | /** |
1125 | * Internal method |
1126 | * |
1127 | * Sets internal data used to perform statements recovery. |
1128 | * |
1129 | * @param data |
1130 | * |
1131 | * @since 3.5 |
1132 | */ |
1133 | void setStatementsRecoveryData(Object data) { |
1134 | this.statementsRecoveryData = data; |
1135 | } |
1136 | |
1137 | @Override |
1138 | final boolean subtreeMatch0(ASTMatcher matcher, Object other) { |
1139 | // dispatch to correct overloaded match method |
1140 | return matcher.match(this, other); |
1141 | } |
1142 | |
1143 | @Override |
1144 | int treeSize() { |
1145 | int size = memSize(); |
1146 | if (this.module != null) { |
1147 | size += getModule().treeSize(); |
1148 | } |
1149 | if (this.optionalPackageDeclaration != null) { |
1150 | size += getPackage().treeSize(); |
1151 | } |
1152 | size += this.imports.listSize(); |
1153 | size += this.types.listSize(); |
1154 | // include disconnected comments |
1155 | if (this.optionalCommentList != null) { |
1156 | for (int i = 0; i < this.optionalCommentList.size(); i++) { |
1157 | Comment comment = (Comment) this.optionalCommentList.get(i); |
1158 | if (comment != null && comment.getParent() == null) { |
1159 | size += comment.treeSize(); |
1160 | } |
1161 | } |
1162 | } |
1163 | return size; |
1164 | } |
1165 | |
1166 | /** |
1167 | * Returns the live list of nodes for the top-level type declarations of this |
1168 | * compilation unit, in order of appearance. |
1169 | * <p> |
1170 | * Note that in JLS3, the types may include both enum declarations |
1171 | * and annotation type declarations introduced in J2SE 5. |
1172 | * For JLS2, the elements are always <code>TypeDeclaration</code>. |
1173 | * </p> |
1174 | * |
1175 | * @return the live list of top-level type declaration |
1176 | * nodes (element type: {@link AbstractTypeDeclaration}) |
1177 | */ |
1178 | public List types() { |
1179 | return this.types; |
1180 | } |
1181 | } |
1182 |
Members