/******************************************************************************* * Copyright (c) 2000, 2009 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.core.dom; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.ITypeRoot; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.internal.compiler.parser.Scanner; import org.eclipse.jdt.internal.compiler.util.Util; import org.eclipse.jface.text.IDocument; import org.eclipse.text.edits.TextEdit; /** * Java compilation unit AST node type. This is the type of the root of an AST. * <p> * The source range for this type of node is ordinarily the entire source file, including leading * and trailing whitespace and comments. * </p> * For JLS2: * * <pre> * CompilationUnit: * [ PackageDeclaration ] * { ImportDeclaration } * { TypeDeclaration | <b>;</b> } * </pre> * * For JLS3, the kinds of type declarations grew to include enum and annotation type declarations: * * <pre> * CompilationUnit: * [ PackageDeclaration ] * { ImportDeclaration } * { TypeDeclaration | EnumDeclaration | AnnotationTypeDeclaration | <b>;</b> } * </pre> * * @since 2.0 * @noinstantiate This class is not intended to be instantiated by clients. */ public class CompilationUnit extends ASTNode { /** * Canonical empty list of messages. */ private static final Message[] EMPTY_MESSAGES= new Message[0]; /** * Canonical empty list of problems. */ private static final IProblem[] EMPTY_PROBLEMS= new IProblem[0]; /** * The "imports" structural property of this node type. * * @since 3.0 */ public static final ChildListPropertyDescriptor IMPORTS_PROPERTY= new ChildListPropertyDescriptor(CompilationUnit.class, "imports", ImportDeclaration.class, NO_CYCLE_RISK); //$NON-NLS-1$ /** * The "package" structural property of this node type. * * @since 3.0 */ public static final ChildPropertyDescriptor PACKAGE_PROPERTY= new ChildPropertyDescriptor(CompilationUnit.class, "package", PackageDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$ /** * A list of property descriptors (element type: {@link StructuralPropertyDescriptor}), or null * if uninitialized. * * @since 3.0 */ private static final List PROPERTY_DESCRIPTORS; /** * The "types" structural property of this node type. * * @since 3.0 */ public static final ChildListPropertyDescriptor TYPES_PROPERTY= new ChildListPropertyDescriptor(CompilationUnit.class, "types", AbstractTypeDeclaration.class, CYCLE_RISK); //$NON-NLS-1$ static { List properyList= new ArrayList(4); createPropertyList(CompilationUnit.class, properyList); addProperty(PACKAGE_PROPERTY, properyList); addProperty(IMPORTS_PROPERTY, properyList); addProperty(TYPES_PROPERTY, properyList); PROPERTY_DESCRIPTORS= reapPropertyList(properyList); } /** * Returns a list of structural property descriptors for this node type. Clients must not modify * the result. * * @param apiLevel the API level; one of the <code>AST.JLS*</code> constants * * @return a list of property descriptors (element type: {@link StructuralPropertyDescriptor}) * @since 3.0 */ public static List propertyDescriptors(int apiLevel) { return PROPERTY_DESCRIPTORS; } /** * The comment mapper, or <code>null</code> if none; initially <code>null</code>. * * @since 3.0 */ private DefaultCommentMapper commentMapper= null; /** * The Java type root (an <code>org.eclipse.jdt.core.ICompilationUnit</code> or an * <code>org.eclipse.jdt.core.IClassFile</code>) this compilation unit was created from, or * <code>null</code> if it was not created from a Java type root. */ private ITypeRoot typeRoot= null; /** * The list of import declarations in textual order order; initially none (elementType: * <code>ImportDeclaration</code>). */ private ASTNode.NodeList imports= new ASTNode.NodeList(IMPORTS_PROPERTY); /** * Line end table. If <code>lineEndTable[i] == p</code> then the line number <code>i+1</code> * ends at character position <code>p</code>. Except for the last line, the positions are that * of the last character of the line delimiter. For example, the source string * <code>A\nB\nC</code> has line end table {1, 3} (if \n is one character). */ private int[] lineEndTable= Util.EMPTY_INT_ARRAY; /** * Messages reported by the compiler during parsing or name resolution. */ private Message[] messages; /** * The comment list (element type: <code>Comment</code>, or <code>null</code> if none; initially * <code>null</code>. * * @since 3.0 */ private List optionalCommentList= null; /** * The comment table, or <code>null</code> if none; initially <code>null</code>. This array is * the storage underlying the <code>optionalCommentList</code> ArrayList. * * @since 3.0 */ Comment[] optionalCommentTable= null; /** * The package declaration, or <code>null</code> if none; initially <code>null</code>. */ private PackageDeclaration optionalPackageDeclaration= null; /** * Problems reported by the compiler during parsing or name resolution. */ private IProblem[] problems= EMPTY_PROBLEMS; /** * Internal data used to perform statements recovery. */ private Object statementsRecoveryData; /** * The list of type declarations in textual order order; initially none (elementType: * <code>AbstractTypeDeclaration</code>) */ private ASTNode.NodeList types= new ASTNode.NodeList(TYPES_PROPERTY); /** * Creates a new AST node for a compilation owned by the given AST. The compilation unit * initially has no package declaration, no import declarations, and no type declarations. * <p> * N.B. This constructor is package-private; all subclasses must be declared in the same * package; clients are unable to declare additional subclasses. * </p> * * @param ast the AST that is to own this node */ CompilationUnit(AST ast) { super(ast); } /* (omit javadoc for this method) * Method declared on ASTNode. */ void accept0(ASTVisitor visitor) { boolean visitChildren= visitor.visit(this); if (visitChildren) { // visit children in normal left to right reading order acceptChild(visitor, getPackage()); acceptChildren(visitor, this.imports); acceptChildren(visitor, this.types); } visitor.endVisit(this); } /* (omit javadoc for this method) * Method declared on ASTNode. */ ASTNode clone0(AST target) { CompilationUnit result= new CompilationUnit(target); // n.b do not copy line number table or messages result.setSourceRange(getStartPosition(), getLength()); result.setPackage( (PackageDeclaration)ASTNode.copySubtree(target, getPackage())); result.imports().addAll(ASTNode.copySubtrees(target, imports())); result.types().addAll(ASTNode.copySubtrees(target, types())); return result; } /** * Returns the column number corresponding to the given source character position in the * original source string. Column number are zero-based. Return <code>-1</code> if it is beyond * the valid range or <code>-2</code> if the column number information is unknown. * * @param position a 0-based character position, possibly negative or out of range * @return the 0-based column number, or <code>-1</code> if the character position does not * correspond to a source line in the original source file or <code>-2</code> if column * number information is unknown for this compilation unit * @see ASTParser * @since 3.2 */ public int getColumnNumber(final int position) { if (this.lineEndTable == null) return -2; final int line= getLineNumber(position); if (line == -1) { return -1; } if (line == 1) { if (position >= getStartPosition() + getLength()) return -1; return position; } // length is different from 0 int length= this.lineEndTable.length; // -1 to for one-based to zero-based conversion. // -1, again, to get previous line. final int previousLineOffset= this.lineEndTable[line - 2]; // previousLineOffset + 1 is the first character of the current line final int offsetForLine= previousLineOffset + 1; final int currentLineEnd= line == length + 1 ? getStartPosition() + getLength() - 1 : this.lineEndTable[line - 1]; if (offsetForLine > currentLineEnd) { return -1; } else { return position - offsetForLine; } } /** * Finds the corresponding AST node in the given compilation unit from which the given binding * originated. Returns <code>null</code> if the binding does not correspond to any node in this * compilation unit. This method always returns <code>null</code> if bindings were not requested * when this AST was built. * <p> * The following table indicates the expected node type for the various different kinds of * bindings: * <ul> * <li>package - a <code>PackageDeclaration</code></li> * <li>class or interface - a <code>TypeDeclaration</code> or a * <code>AnonymousClassDeclaration</code> (for anonymous classes)</li> * <li>primitive type - none</li> * <li>array type - none</li> * <li>field - a <code>VariableDeclarationFragment</code> in a <code>FieldDeclaration</code></li> * <li>local variable - a <code>SingleVariableDeclaration</code>, or a * <code>VariableDeclarationFragment</code> in a <code>VariableDeclarationStatement</code> or * <code>VariableDeclarationExpression</code></li> * <li>method - a <code>MethodDeclaration</code></li> * <li>constructor - a <code>MethodDeclaration</code></li> * <li>annotation type - an <code>AnnotationTypeDeclaration</code></li> * <li>annotation type member - an <code>AnnotationTypeMemberDeclaration</code></li> * <li>enum type - an <code>EnumDeclaration</code></li> * <li>enum constant - an <code>EnumConstantDeclaration</code></li> * <li>type variable - a <code>TypeParameter</code></li> * <li>capture binding - none</li> * <li>annotation binding - an <code>Annotation</code></li> * <li>member value pair binding - an <code>MemberValuePair</code>, or <code>null</code> if it * represents a default value or a single member value</li> * </ul> * For parameterized or raw type bindings, the declaring node is that of the corresponding * generic type. And for parameterized or raw method bindings, the declaring node is that of the * corresponding generic method. * </p> * <p> * Each call to {@link ASTParser#createAST(org.eclipse.core.runtime.IProgressMonitor)} with a * request for bindings gives rise to separate universe of binding objects. This method always * returns <code>null</code> when the binding object comes from a different AST. Use * <code>findDeclaringNode(binding.getKey())</code> when the binding comes from a different AST. * </p> * * @param binding the binding * @return the corresponding node where the given binding is declared, or <code>null</code> if * the binding does not correspond to a node in this compilation unit or if bindings * were not requested when this AST was built * @see #findDeclaringNode(String) */ public ASTNode findDeclaringNode(IBinding binding) { return this.ast.getBindingResolver().findDeclaringNode(binding); } /** * Finds the corresponding AST node in the given compilation unit from which the binding with * the given key originated. Returns <code>null</code> if the corresponding node cannot be * determined. This method always returns <code>null</code> if bindings were not requested when * this AST was built. * <p> * The following table indicates the expected node type for the various different kinds of * binding keys: * <ul> * <li></li> * <li>package - a <code>PackageDeclaration</code></li> * <li>class or interface - a <code>TypeDeclaration</code> or a * <code>AnonymousClassDeclaration</code> (for anonymous classes)</li> * <li>primitive type - none</li> * <li>array type - none</li> * <li>field - a <code>VariableDeclarationFragment</code> in a <code>FieldDeclaration</code></li> * <li>local variable - a <code>SingleVariableDeclaration</code>, or a * <code>VariableDeclarationFragment</code> in a <code>VariableDeclarationStatement</code> or * <code>VariableDeclarationExpression</code></li> * <li>method - a <code>MethodDeclaration</code></li> * <li>constructor - a <code>MethodDeclaration</code></li> * <li>annotation type - an <code>AnnotationTypeDeclaration</code></li> * <li>annotation type member - an <code>AnnotationTypeMemberDeclaration</code></li> * <li>enum type - an <code>EnumDeclaration</code></li> * <li>enum constant - an <code>EnumConstantDeclaration</code></li> * <li>type variable - a <code>TypeParameter</code></li> * <li>capture binding - none</li> * </ul> * For parameterized or raw type bindings, the declaring node is that of the corresponding * generic type. And for parameterized or raw method bindings, the declaring node is that of the * corresponding generic method. * </p> * * @param key the binding key, or <code>null</code> * @return the corresponding node where a binding with the given key is declared, or * <code>null</code> if the key is <code>null</code> or if the key does not correspond * to a node in this compilation unit or if bindings were not requested when this AST * was built * @see IBinding#getKey() * @since 2.1 */ public ASTNode findDeclaringNode(String key) { return this.ast.getBindingResolver().findDeclaringNode(key); } /** * Returns a list of the comments encountered while parsing this compilation unit. * <p> * Since the Java language allows comments to appear most anywhere in the source text, it is * problematic to locate comments in relation to the structure of an AST. The one exception is * doc comments which, by convention, immediately precede type, field, and method declarations; * these comments are located in the AST by {@link BodyDeclaration#getJavadoc * BodyDeclaration.getJavadoc}. Other comments do not show up in the AST. The table of comments * is provided for clients that need to find the source ranges of all comments in the original * source string. It includes entries for comments of all kinds (line, block, and doc), arranged * in order of increasing source position. * </p> * <p> * Note on comment parenting: The {@link ASTNode#getParent() getParent()} of a doc comment * associated with a body declaration is the body declaration node; for these comment nodes * {@link ASTNode#getRoot() getRoot()} will return the compilation unit (assuming an unmodified * AST) reflecting the fact that these nodes are property located in the AST for the compilation * unit. However, for other comment nodes, {@link ASTNode#getParent() getParent()} will return * <code>null</code>, and {@link ASTNode#getRoot() getRoot()} will return the comment node * itself, indicating that these comment nodes are not directly connected to the AST for the * compilation unit. The {@link Comment#getAlternateRoot Comment.getAlternateRoot} method * provides a way to navigate from a comment to its compilation unit. * </p> * <p> * A note on visitors: The only comment nodes that will be visited when visiting a compilation * unit are the doc comments parented by body declarations. To visit all comments in normal * reading order, iterate over the comment table and call {@link ASTNode#accept(ASTVisitor) * accept} on each element. * </p> * <p> * Clients cannot modify the resulting list. * </p> * * @return an unmodifiable list of comments in increasing order of source start position, or * <code>null</code> if comment information for this compilation unit is not available * @see ASTParser * @since 3.0 */ public List getCommentList() { return this.optionalCommentList; } /** * Returns the internal comment mapper. * * @return the comment mapper, or <code>null</code> if none. * @since 3.0 */ DefaultCommentMapper getCommentMapper() { return this.commentMapper; } /** * Returns the extended source length of the given node. Unlike * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, the extended source range * may include comments and whitespace immediately before or after the normal source range for * the node. * * @param node the node * @return a (possibly 0) length, or <code>0</code> if no source position information is * recorded for this node * @see #getExtendedStartPosition(ASTNode) * @since 3.0 */ public int getExtendedLength(ASTNode node) { if (node == null) { throw new IllegalArgumentException(); } if (this.commentMapper == null || node.getAST() != getAST()) { // fall back: use best info available return node.getLength(); } else { return this.commentMapper.getExtendedLength(node); } } /** * Returns the extended start position of the given node. Unlike * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()}, the extended source range * may include comments and whitespace immediately before or after the normal source range for * the node. * * @param node the node * @return the 0-based character index, or <code>-1</code> if no source position information is * recorded for this node * @see #getExtendedLength(ASTNode) * @since 3.0 */ public int getExtendedStartPosition(ASTNode node) { if (node == null) { throw new IllegalArgumentException(); } if (this.commentMapper == null || node.getAST() != getAST()) { // fall back: use best info available return node.getStartPosition(); } else { return this.commentMapper.getExtendedStartPosition(node); } } /** * The Java element (an <code>org.eclipse.jdt.core.ICompilationUnit</code> or an * <code>org.eclipse.jdt.core.IClassFile</code>) this compilation unit was created from, or * <code>null</code> if it was not created from a Java element. * * @return the Java element this compilation unit was created from, or <code>null</code> if none * @since 3.1 * @see #getTypeRoot() */ public IJavaElement getJavaElement() { return this.typeRoot; } /** * Returns the list of messages reported by the compiler during the parsing or the type checking * of this compilation unit. This list might be a subset of errors detected and reported by a * Java compiler. * <p> * This list of messages is suitable for simple clients that do little more than log the * messages or display them to the user. Clients that need further details should call * <code>getProblems</code> to get compiler problem objects. * </p> * * @return the list of messages, possibly empty * @see #getProblems() * @see ASTParser */ public Message[] getMessages() { if (this.messages == null) { int problemLength= this.problems.length; if (problemLength == 0) { this.messages= EMPTY_MESSAGES; } else { this.messages= new Message[problemLength]; for (int i= 0; i < problemLength; i++) { IProblem problem= this.problems[i]; int start= problem.getSourceStart(); int end= problem.getSourceEnd(); this.messages[i]= new Message(problem.getMessage(), start, end - start + 1); } } } return this.messages; } /* (omit javadoc for this method) * Method declared on ASTNode. */ final int getNodeType0() { return COMPILATION_UNIT; } /** * Returns the node for the package declaration of this compilation unit, or <code>null</code> * if this compilation unit is in the default package. * * @return the package declaration node, or <code>null</code> if none */ public PackageDeclaration getPackage() { return this.optionalPackageDeclaration; } /** * Given a line number and column number, returns the corresponding position in the original * source string. Returns -2 if no line number information is available for this compilation * unit. Returns the total size of the source string if <code>line</code> is greater than the * actual number lines in the unit. Returns -1 if <code>column</code> is less than 0, or the * position of the last character of the line if <code>column</code> is beyond the legal range, * or the given line number is less than one. * * @param line the one-based line number * @param column the zero-based column number * @return the 0-based character position in the source string; <code>-2</code> if line/column * number information is not known for this compilation unit or <code>-1</code> the * inputs are not valid * @since 3.2 */ public int getPosition(int line, int column) { if (this.lineEndTable == null) return -2; if (line < 1 || column < 0) return -1; int length; if ((length= this.lineEndTable.length) == 0) { if (line != 1) return -1; return column >= getStartPosition() + getLength() ? -1 : column; } if (line == 1) { final int endOfLine= this.lineEndTable[0]; return column > endOfLine ? -1 : column; } else if (line > length + 1) { // greater than the number of lines in the source string. return -1; } // -1 to for one-based to zero-based conversion. // -1, again, to get previous line. final int previousLineOffset= this.lineEndTable[line - 2]; // previousLineOffset + 1 is the first character of the current line final int offsetForLine= previousLineOffset + 1; final int currentLineEnd= line == length + 1 ? getStartPosition() + getLength() - 1 : this.lineEndTable[line - 1]; if ((offsetForLine + column) > currentLineEnd) { return -1; } else { return offsetForLine + column; } } /** * Returns the list of detailed problem reports noted by the compiler during the parsing or the * type checking of this compilation unit. This list might be a subset of errors detected and * reported by a Java compiler. * <p> * Simple clients that do little more than log the messages or display them to the user should * probably call <code>getMessages</code> instead. * </p> * * @return the list of detailed problem objects, possibly empty * @see #getMessages() * @see ASTParser * @since 2.1 */ public IProblem[] getProblems() { return this.problems; } /** * Internal method * * This method return internal data used to perform statements recovery. * * @return internal data used to perform statements recovery. * * @noreference This method is not intended to be referenced by clients. * @since 3.5 */ public Object getStatementsRecoveryData() { return this.statementsRecoveryData; } /** * The Java type root (a {@link org.eclipse.jdt.core.ICompilationUnit compilation unit} or a * {@link org.eclipse.jdt.core.IClassFile class file}) this compilation unit was created from, * or <code>null</code> if it was not created from a Java type root. * * @return the Java type root this compilation unit was created from, or <code>null</code> if * none * @since 3.3 */ public ITypeRoot getTypeRoot() { return this.typeRoot; } /** * Returns the live list of nodes for the import declarations of this compilation unit, in order * of appearance. * * @return the live list of import declaration nodes (elementType: * <code>ImportDeclaration</code>) */ public List imports() { return this.imports; } /** * Return the index in the whole comments list {@link #getCommentList() } of the first leading * comments associated with the given node. * * @param node the node * @return 0-based index of first leading comment or -1 if node has no associated comment before * its start position. * @since 3.2 */ public int firstLeadingCommentIndex(ASTNode node) { if (node == null) { throw new IllegalArgumentException(); } if (this.commentMapper == null || node.getAST() != getAST()) { return -1; } return this.commentMapper.firstLeadingCommentIndex(node); } /** * Return the index in the whole comments list {@link #getCommentList() } of the last trailing * comments associated with the given node. * * @param node the node * @return 0-based index of last trailing comment or -1 if node has no associated comment after * its end position. * @since 3.2 */ public int lastTrailingCommentIndex(ASTNode node) { if (node == null) { throw new IllegalArgumentException(); } if (this.commentMapper == null || node.getAST() != getAST()) { return -1; } return this.commentMapper.lastTrailingCommentIndex(node); } /** * Initializes the internal comment mapper with the given scanner. * * @param scanner the scanner * @since 3.0 */ void initCommentMapper(Scanner scanner) { this.commentMapper= new DefaultCommentMapper(this.optionalCommentTable); this.commentMapper.initialize(this, scanner); } /* (omit javadoc for this method) * Method declared on ASTNode. */ final List internalGetChildListProperty(ChildListPropertyDescriptor property) { if (property == IMPORTS_PROPERTY) { return imports(); } if (property == TYPES_PROPERTY) { return types(); } // allow default implementation to flag the error return super.internalGetChildListProperty(property); } /* (omit javadoc for this method) * Method declared on ASTNode. */ final ASTNode internalGetSetChildProperty(ChildPropertyDescriptor property, boolean get, ASTNode child) { if (property == PACKAGE_PROPERTY) { if (get) { return getPackage(); } else { setPackage((PackageDeclaration)child); return null; } } // allow default implementation to flag the error return super.internalGetSetChildProperty(property, get, child); } /* (omit javadoc for this method) * Method declared on ASTNode. * @since 3.0 */ final List internalStructuralPropertiesForType(int apiLevel) { return propertyDescriptors(apiLevel); } /** * Returns the line number corresponding to the given source character position in the original * source string. The initial line of the compilation unit is numbered 1, and each line extends * through the last character of the end-of-line delimiter. The very last line extends through * the end of the source string and has no line delimiter. For example, the source string * <code>class A\n{\n}</code> has 3 lines corresponding to inclusive character ranges [0,7], * [8,9], and [10,10]. Returns 1 for a character position that does not correspond to any source * line, or if no line number information is available for this compilation unit. * * @param position a 0-based character position, possibly negative or out of range * @return the 1-based line number, or <code>1</code> if the character position does not * correspond to a source line in the original source file or if line number information * is not known for this compilation unit * @deprecated Use getLineNumber(int) instead. Be careful to handle the negative values. * @see ASTParser * @see #getLineNumber(int) */ public int lineNumber(int position) { int lineNumber= getLineNumber(position); return lineNumber < 1 ? 1 : lineNumber; } /** * Returns the line number corresponding to the given source character position in the original * source string. The initial line of the compilation unit is numbered 1, and each line extends * through the last character of the end-of-line delimiter. The very last line extends through * the end of the source string and has no line delimiter. For example, the source string * <code>class A\n{\n}</code> has 3 lines corresponding to inclusive character ranges [0,7], * [8,9], and [10,10]. Returns -1 for a character position that does not correspond to any * source line, or -2 if no line number information is available for this compilation unit. * * @param position a 0-based character position, possibly negative or out of range * @return the 1-based line number, or <code>-1</code> if the character position does not * correspond to a source line in the original source file or <code>-2</code> if line * number information is not known for this compilation unit * @see ASTParser * @since 3.2 */ public int getLineNumber(int position) { if (this.lineEndTable == null) return -2; int length; if ((length= this.lineEndTable.length) == 0) { if (position >= getStartPosition() + getLength()) { return -1; } return 1; } int low= 0; if (position < 0) { // position illegal return -1; } if (position <= this.lineEndTable[low]) { // before the first line delimiter return 1; } // assert position > lineEndTable[low+1] && low == 0 int hi= length - 1; if (position > this.lineEndTable[hi]) { // position beyond the last line separator if (position >= getStartPosition() + getLength()) { // this is beyond the end of the source length return -1; } else { return length + 1; } } // assert lineEndTable[low] < position <= lineEndTable[hi] // && low == 0 && hi == length - 1 && low < hi // binary search line end table while (true) { // invariant lineEndTable[low] < position <= lineEndTable[hi] // && 0 <= low < hi <= length - 1 // reducing measure hi - low if (low + 1 == hi) { // assert lineEndTable[low] < position <= lineEndTable[low+1] // position is on line low+1 (line number is low+2) return low + 2; } // assert hi - low >= 2, so average is truly in between int mid= low + (hi - low) / 2; // assert 0 <= low < mid < hi <= length - 1 if (position <= this.lineEndTable[mid]) { // assert lineEndTable[low] < position <= lineEndTable[mid] // && 0 <= low < mid < hi <= length - 1 hi= mid; } else { // position > lineEndTable[mid] // assert lineEndTable[mid] < position <= lineEndTable[hi] // && 0 <= low < mid < hi <= length - 1 low= mid; } // in both cases, invariant reachieved with reduced measure } } /* (omit javadoc for this method) * Method declared on ASTNode. */ int memSize() { int size= BASE_NODE_SIZE + 8 * 4; if (this.lineEndTable != null) { size+= HEADERS + 4 * this.lineEndTable.length; } if (this.optionalCommentTable != null) { size+= HEADERS + 4 * this.optionalCommentTable.length; } // ignore the space taken up by optionalCommentList return size; } /** * Enables the recording of changes to this compilation unit and its descendents. The * compilation unit must have been created by <code>ASTParser</code> and still be in its * original state. Once recording is on, arbitrary changes to the subtree rooted at this * compilation unit are recorded internally. Once the modification has been completed, call * <code>rewrite</code> to get an object representing the corresponding edits to the original * source code string. * * @exception IllegalArgumentException if this compilation unit is marked as unmodifiable, or if * this compilation unit has already been tampered with, or recording has already * been enabled * @since 3.0 */ public void recordModifications() { getAST().recordModifications(this); } /** * Converts all modifications recorded for this compilation unit into an object representing the * corresponding text edits to the given document containing the original source code for this * compilation unit. * <p> * The compilation unit must have been created by <code>ASTParser</code> from the source code * string in the given document, and recording must have been turned on with a prior call to * <code>recordModifications</code> while the AST was still in its original state. * </p> * <p> * Calling this methods does not discard the modifications on record. Subsequence modifications * made to the AST are added to the ones already on record. If this method is called again * later, the resulting text edit object will accurately reflect the net cumulative affect of * all those changes. * </p> * * @param document original document containing source code for this compilation unit * @param options the table of formatter options (key type: <code>String</code>; value type: * <code>String</code>); or <code>null</code> to use the standard global options * {@link org.eclipse.jdt.core.JavaCore#getOptions() JavaCore.getOptions()}. * @return text edit object describing the changes to the document corresponding to the recorded * AST modifications * @exception IllegalArgumentException if the document passed is <code>null</code> or does not * correspond to this AST * @exception IllegalStateException if <code>recordModifications</code> was not called to enable * recording * @see #recordModifications() * @since 3.0 */ public TextEdit rewrite(IDocument document, Map options) { return getAST().rewrite(document, options); } /** * Sets the list of the comments encountered while parsing this compilation unit. * * @param commentTable a list of comments in increasing order of source start position, or * <code>null</code> if comment information for this compilation unit is not * available * @exception IllegalArgumentException if the comment table is not in increasing order of source * position * @see #getCommentList() * @see ASTParser * @since 3.0 */ void setCommentTable(Comment[] commentTable) { // double check table to ensure that all comments have // source positions and are in strictly increasing order if (commentTable == null) { this.optionalCommentList= null; this.optionalCommentTable= null; } else { int nextAvailablePosition= 0; for (int i= 0; i < commentTable.length; i++) { Comment comment= commentTable[i]; if (comment == null) { throw new IllegalArgumentException(); } int start= comment.getStartPosition(); int length= comment.getLength(); if (start < 0 || length < 0 || start < nextAvailablePosition) { throw new IllegalArgumentException(); } nextAvailablePosition= comment.getStartPosition() + comment.getLength(); } this.optionalCommentTable= commentTable; List commentList= Arrays.asList(commentTable); // protect the list from further modification this.optionalCommentList= Collections.unmodifiableList(commentList); } } /** * Sets the Java type root (a {@link org.eclipse.jdt.core.ICompilationUnit compilation unit} or * a {@link org.eclipse.jdt.core.IClassFile class file}) this compilation unit was created from, * or <code>null</code> if it was not created from a Java type root. * * @param typeRoot the Java type root this compilation unit was created from */ void setTypeRoot(ITypeRoot typeRoot) { this.typeRoot= typeRoot; } /** * Sets the line end table for this compilation unit. If <code>lineEndTable[i] == p</code> then * line number <code>i+1</code> ends at character position <code>p</code>. Except for the last * line, the positions are that of (the last character of) the line delimiter. For example, the * source string <code>A\nB\nC</code> has line end table {1, 3, 4}. * * @param lineEndTable the line end table */ void setLineEndTable(int[] lineEndTable) { if (lineEndTable == null) { throw new NullPointerException(); } // alternate root is *not* considered a structural property // but we protect them nevertheless checkModifiable(); this.lineEndTable= lineEndTable; } /** * Sets or clears the package declaration of this compilation unit node to the given package * declaration node. * * @param pkgDecl the new package declaration node, or <code>null</code> if this compilation * unit does not have a package declaration (that is in the default package) * @exception IllegalArgumentException if: * <ul> * <li>the node belongs to a different AST</li> * <li>the node already has a parent</li> * </ul> */ public void setPackage(PackageDeclaration pkgDecl) { ASTNode oldChild= this.optionalPackageDeclaration; preReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY); this.optionalPackageDeclaration= pkgDecl; postReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY); } /** * Sets the array of problems reported by the compiler during the parsing or name resolution of * this compilation unit. * * @param problems the list of problems */ void setProblems(IProblem[] problems) { if (problems == null) { throw new IllegalArgumentException(); } this.problems= problems; } /** * Internal method * * Sets internal data used to perform statements recovery. * * @param data * * @noreference This method is not intended to be referenced by clients. * @since 3.5 */ void setStatementsRecoveryData(Object data) { this.statementsRecoveryData= data; } /* (omit javadoc for this method) * Method declared on ASTNode. */ final boolean subtreeMatch0(ASTMatcher matcher, Object other) { // dispatch to correct overloaded match method return matcher.match(this, other); } /* (omit javadoc for this method) * Method declared on ASTNode. */ int treeSize() { int size= memSize(); if (this.optionalPackageDeclaration != null) { size+= getPackage().treeSize(); } size+= this.imports.listSize(); size+= this.types.listSize(); // include disconnected comments if (this.optionalCommentList != null) { for (int i= 0; i < this.optionalCommentList.size(); i++) { Comment comment= (Comment)this.optionalCommentList.get(i); if (comment != null && comment.getParent() == null) { size+= comment.treeSize(); } } } return size; } /** * Returns the live list of nodes for the top-level type declarations of this compilation unit, * in order of appearance. * <p> * Note that in JLS3, the types may include both enum declarations and annotation type * declarations introduced in J2SE 5. For JLS2, the elements are always * <code>TypeDeclaration</code>. * </p> * * @return the live list of top-level type declaration nodes (elementType: * <code>AbstractTypeDeclaration</code>) */ public List types() { return this.types; } }