0001: /*******************************************************************************
0002: * Copyright (c) 2000, 2006 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.core.dom;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Arrays;
0014: import java.util.Collections;
0015: import java.util.List;
0016: import java.util.Map;
0017:
0018: import org.eclipse.jdt.core.IJavaElement;
0019: import org.eclipse.jdt.core.ITypeRoot;
0020: import org.eclipse.jdt.core.compiler.IProblem;
0021: import org.eclipse.jdt.internal.compiler.parser.Scanner;
0022: import org.eclipse.jdt.internal.compiler.util.Util;
0023: import org.eclipse.jface.text.IDocument;
0024: import org.eclipse.text.edits.TextEdit;
0025:
0026: /**
0027: * Java compilation unit AST node type. This is the type of the root of an AST.
0028: * <p>
0029: * The source range for this type of node is ordinarily the entire source file,
0030: * including leading and trailing whitespace and comments.
0031: * </p>
0032: * For JLS2:
0033: * <pre>
0034: * CompilationUnit:
0035: * [ PackageDeclaration ]
0036: * { ImportDeclaration }
0037: * { TypeDeclaration | <b>;</b> }
0038: * </pre>
0039: * For JLS3, the kinds of type declarations
0040: * grew to include enum and annotation type declarations:
0041: * <pre>
0042: * CompilationUnit:
0043: * [ PackageDeclaration ]
0044: * { ImportDeclaration }
0045: * { TypeDeclaration | EnumDeclaration | AnnotationTypeDeclaration | <b>;</b> }
0046: * </pre>
0047: *
0048: * @since 2.0
0049: */
0050: public class CompilationUnit extends ASTNode {
0051:
0052: /**
0053: * Canonical empty list of messages.
0054: */
0055: private static final Message[] EMPTY_MESSAGES = new Message[0];
0056:
0057: /**
0058: * Canonical empty list of problems.
0059: */
0060: private static final IProblem[] EMPTY_PROBLEMS = new IProblem[0];
0061:
0062: /**
0063: * The "imports" structural property of this node type.
0064: *
0065: * @since 3.0
0066: */
0067: public static final ChildListPropertyDescriptor IMPORTS_PROPERTY = new ChildListPropertyDescriptor(
0068: CompilationUnit.class,
0069: "imports", ImportDeclaration.class, NO_CYCLE_RISK); //$NON-NLS-1$
0070:
0071: /**
0072: * The "package" structural property of this node type.
0073: *
0074: * @since 3.0
0075: */
0076: public static final ChildPropertyDescriptor PACKAGE_PROPERTY = new ChildPropertyDescriptor(
0077: CompilationUnit.class,
0078: "package", PackageDeclaration.class, OPTIONAL, NO_CYCLE_RISK); //$NON-NLS-1$
0079:
0080: /**
0081: * A list of property descriptors (element type:
0082: * {@link StructuralPropertyDescriptor}),
0083: * or null if uninitialized.
0084: * @since 3.0
0085: */
0086: private static final List PROPERTY_DESCRIPTORS;
0087:
0088: /**
0089: * The "types" structural property of this node type.
0090: *
0091: * @since 3.0
0092: */
0093: public static final ChildListPropertyDescriptor TYPES_PROPERTY = new ChildListPropertyDescriptor(
0094: CompilationUnit.class,
0095: "types", AbstractTypeDeclaration.class, CYCLE_RISK); //$NON-NLS-1$
0096:
0097: static {
0098: List properyList = new ArrayList(4);
0099: createPropertyList(CompilationUnit.class, properyList);
0100: addProperty(PACKAGE_PROPERTY, properyList);
0101: addProperty(IMPORTS_PROPERTY, properyList);
0102: addProperty(TYPES_PROPERTY, properyList);
0103: PROPERTY_DESCRIPTORS = reapPropertyList(properyList);
0104: }
0105:
0106: /**
0107: * Returns a list of structural property descriptors for this node type.
0108: * Clients must not modify the result.
0109: *
0110: * @param apiLevel the API level; one of the
0111: * <code>AST.JLS*</code> constants
0112:
0113: * @return a list of property descriptors (element type:
0114: * {@link StructuralPropertyDescriptor})
0115: * @since 3.0
0116: */
0117: public static List propertyDescriptors(int apiLevel) {
0118: return PROPERTY_DESCRIPTORS;
0119: }
0120:
0121: /**
0122: * The comment mapper, or <code>null</code> if none;
0123: * initially <code>null</code>.
0124: * @since 3.0
0125: */
0126: private DefaultCommentMapper commentMapper = null;
0127:
0128: /**
0129: * The Java type root (an <code>org.eclipse.jdt.core.ICompilationUnit</code> or an <code>org.eclipse.jdt.core.IClassFile</code>)
0130: * this compilation unit was created from, or <code>null</code> if it was not created from a Java type root.
0131: */
0132: private ITypeRoot typeRoot = null;
0133:
0134: /**
0135: * The list of import declarations in textual order order;
0136: * initially none (elementType: <code>ImportDeclaration</code>).
0137: */
0138: private ASTNode.NodeList imports = new ASTNode.NodeList(
0139: IMPORTS_PROPERTY);
0140:
0141: /**
0142: * Line end table. If <code>lineEndTable[i] == p</code> then the
0143: * line number <code>i+1</code> ends at character position
0144: * <code>p</code>. Except for the last line, the positions are that
0145: * of the last character of the line delimiter.
0146: * For example, the source string <code>A\nB\nC</code> has
0147: * line end table {1, 3} (if \n is one character).
0148: */
0149: private int[] lineEndTable = Util.EMPTY_INT_ARRAY;
0150:
0151: /**
0152: * Messages reported by the compiler during parsing or name resolution.
0153: */
0154: private Message[] messages;
0155:
0156: /**
0157: * The comment list (element type: <code>Comment</code>,
0158: * or <code>null</code> if none; initially <code>null</code>.
0159: * @since 3.0
0160: */
0161: private List optionalCommentList = null;
0162:
0163: /**
0164: * The comment table, or <code>null</code> if none; initially
0165: * <code>null</code>. This array is the storage underlying
0166: * the <code>optionalCommentList</code> ArrayList.
0167: * @since 3.0
0168: */
0169: Comment[] optionalCommentTable = null;
0170:
0171: /**
0172: * The package declaration, or <code>null</code> if none; initially
0173: * <code>null</code>.
0174: */
0175: private PackageDeclaration optionalPackageDeclaration = null;
0176:
0177: /**
0178: * Problems reported by the compiler during parsing or name resolution.
0179: */
0180: private IProblem[] problems = EMPTY_PROBLEMS;
0181:
0182: /**
0183: * The list of type declarations in textual order order;
0184: * initially none (elementType: <code>AbstractTypeDeclaration</code>)
0185: */
0186: private ASTNode.NodeList types = new ASTNode.NodeList(
0187: TYPES_PROPERTY);
0188:
0189: /**
0190: * Creates a new AST node for a compilation owned by the given AST.
0191: * The compilation unit initially has no package declaration, no
0192: * import declarations, and no type declarations.
0193: * <p>
0194: * N.B. This constructor is package-private; all subclasses must be
0195: * declared in the same package; clients are unable to declare
0196: * additional subclasses.
0197: * </p>
0198: *
0199: * @param ast the AST that is to own this node
0200: */
0201: CompilationUnit(AST ast) {
0202: super (ast);
0203: }
0204:
0205: /* (omit javadoc for this method)
0206: * Method declared on ASTNode.
0207: */
0208: void accept0(ASTVisitor visitor) {
0209: boolean visitChildren = visitor.visit(this );
0210: if (visitChildren) {
0211: // visit children in normal left to right reading order
0212: acceptChild(visitor, getPackage());
0213: acceptChildren(visitor, this .imports);
0214: acceptChildren(visitor, this .types);
0215: }
0216: visitor.endVisit(this );
0217: }
0218:
0219: /* (omit javadoc for this method)
0220: * Method declared on ASTNode.
0221: */
0222: ASTNode clone0(AST target) {
0223: CompilationUnit result = new CompilationUnit(target);
0224: // n.b do not copy line number table or messages
0225: result
0226: .setSourceRange(this .getStartPosition(), this
0227: .getLength());
0228: result.setPackage((PackageDeclaration) ASTNode.copySubtree(
0229: target, getPackage()));
0230: result.imports()
0231: .addAll(ASTNode.copySubtrees(target, imports()));
0232: result.types().addAll(ASTNode.copySubtrees(target, types()));
0233: return result;
0234: }
0235:
0236: /**
0237: * Returns the column number corresponding to the given source character
0238: * position in the original source string. Column number are zero-based.
0239: * Return <code>-1</code> if it is beyond the valid range or <code>-2</code>
0240: * if the column number information is unknown.
0241: *
0242: * @param position a 0-based character position, possibly
0243: * negative or out of range
0244: * @return the 0-based column number, or <code>-1</code> if the character
0245: * position does not correspond to a source line in the original
0246: * source file or <code>-2</code> if column number information is unknown for this
0247: * compilation unit
0248: * @see ASTParser
0249: * @since 3.2
0250: */
0251: public int getColumnNumber(final int position) {
0252: if (this .lineEndTable == null)
0253: return -2;
0254: final int line = getLineNumber(position);
0255: if (line == -1) {
0256: return -1;
0257: }
0258: if (line == 1) {
0259: if (position >= getStartPosition() + getLength())
0260: return -1;
0261: return position;
0262: }
0263: // length is different from 0
0264: int length = this .lineEndTable.length;
0265: // -1 to for one-based to zero-based conversion.
0266: // -1, again, to get previous line.
0267: final int previousLineOffset = this .lineEndTable[line - 2];
0268: // previousLineOffset + 1 is the first character of the current line
0269: final int offsetForLine = previousLineOffset + 1;
0270: final int currentLineEnd = line == length + 1 ? getStartPosition()
0271: + getLength() - 1
0272: : this .lineEndTable[line - 1];
0273: if (offsetForLine > currentLineEnd) {
0274: return -1;
0275: } else {
0276: return position - offsetForLine;
0277: }
0278: }
0279:
0280: /**
0281: * Finds the corresponding AST node in the given compilation unit from
0282: * which the given binding originated. Returns <code>null</code> if the
0283: * binding does not correspond to any node in this compilation unit.
0284: * This method always returns <code>null</code> if bindings were not requested
0285: * when this AST was built.
0286: * <p>
0287: * The following table indicates the expected node type for the various
0288: * different kinds of bindings:
0289: * <ul>
0290: * <li>package - a <code>PackageDeclaration</code></li>
0291: * <li>class or interface - a <code>TypeDeclaration</code> or a
0292: * <code>AnonymousClassDeclaration</code> (for anonymous classes)</li>
0293: * <li>primitive type - none</li>
0294: * <li>array type - none</li>
0295: * <li>field - a <code>VariableDeclarationFragment</code> in a
0296: * <code>FieldDeclaration</code> </li>
0297: * <li>local variable - a <code>SingleVariableDeclaration</code>, or
0298: * a <code>VariableDeclarationFragment</code> in a
0299: * <code>VariableDeclarationStatement</code> or
0300: * <code>VariableDeclarationExpression</code></li>
0301: * <li>method - a <code>MethodDeclaration</code> </li>
0302: * <li>constructor - a <code>MethodDeclaration</code> </li>
0303: * <li>annotation type - an <code>AnnotationTypeDeclaration</code></li>
0304: * <li>annotation type member - an <code>AnnotationTypeMemberDeclaration</code></li>
0305: * <li>enum type - an <code>EnumDeclaration</code></li>
0306: * <li>enum constant - an <code>EnumConstantDeclaration</code></li>
0307: * <li>type variable - a <code>TypeParameter</code></li>
0308: * <li>capture binding - none</li>
0309: * <li>annotation binding - an <code>Annotation</code></li>
0310: * <li>member value pair binding - an <code>MemberValuePair</code>,
0311: * or <code>null</code> if it represents a default value or a single member value</li>
0312: * </ul>
0313: * For parameterized or raw type bindings, the declaring node is
0314: * that of the corresponding generic type. And for parameterized or raw
0315: * method bindings, the declaring node is that of the corresponding
0316: * generic method.
0317: * </p>
0318: * <p>
0319: * Each call to {@link ASTParser#createAST(org.eclipse.core.runtime.IProgressMonitor)} with a request for bindings
0320: * gives rise to separate universe of binding objects. This method always returns
0321: * <code>null</code> when the binding object comes from a different AST.
0322: * Use <code>findDeclaringNode(binding.getKey())</code> when the binding comes
0323: * from a different AST.
0324: * </p>
0325: *
0326: * @param binding the binding
0327: * @return the corresponding node where the given binding is declared,
0328: * or <code>null</code> if the binding does not correspond to a node in this
0329: * compilation unit or if bindings were not requested when this AST was built
0330: * @see #findDeclaringNode(String)
0331: */
0332: public ASTNode findDeclaringNode(IBinding binding) {
0333: return this .ast.getBindingResolver().findDeclaringNode(binding);
0334: }
0335:
0336: /**
0337: * Finds the corresponding AST node in the given compilation unit from
0338: * which the binding with the given key originated. Returns
0339: * <code>null</code> if the corresponding node cannot be determined.
0340: * This method always returns <code>null</code> if bindings were not requested
0341: * when this AST was built.
0342: * <p>
0343: * The following table indicates the expected node type for the various
0344: * different kinds of binding keys:
0345: * <ul>
0346: * <li></li>
0347: * <li>package - a <code>PackageDeclaration</code></li>
0348: * <li>class or interface - a <code>TypeDeclaration</code> or a
0349: * <code>AnonymousClassDeclaration</code> (for anonymous classes)</li>
0350: * <li>primitive type - none</li>
0351: * <li>array type - none</li>
0352: * <li>field - a <code>VariableDeclarationFragment</code> in a
0353: * <code>FieldDeclaration</code> </li>
0354: * <li>local variable - a <code>SingleVariableDeclaration</code>, or
0355: * a <code>VariableDeclarationFragment</code> in a
0356: * <code>VariableDeclarationStatement</code> or
0357: * <code>VariableDeclarationExpression</code></li>
0358: * <li>method - a <code>MethodDeclaration</code> </li>
0359: * <li>constructor - a <code>MethodDeclaration</code> </li>
0360: * <li>annotation type - an <code>AnnotationTypeDeclaration</code></li>
0361: * <li>annotation type member - an <code>AnnotationTypeMemberDeclaration</code></li>
0362: * <li>enum type - an <code>EnumDeclaration</code></li>
0363: * <li>enum constant - an <code>EnumConstantDeclaration</code></li>
0364: * <li>type variable - a <code>TypeParameter</code></li>
0365: * <li>capture binding - none</li>
0366: * </ul>
0367: * For parameterized or raw type bindings, the declaring node is
0368: * that of the corresponding generic type. And for parameterized or raw
0369: * method bindings, the declaring node is that of the corresponding
0370: * generic method.
0371: * </p>
0372: *
0373: * @param key the binding key, or <code>null</code>
0374: * @return the corresponding node where a binding with the given
0375: * key is declared, or <code>null</code> if the key is <code>null</code>
0376: * or if the key does not correspond to a node in this compilation unit
0377: * or if bindings were not requested when this AST was built
0378: * @see IBinding#getKey()
0379: * @since 2.1
0380: */
0381: public ASTNode findDeclaringNode(String key) {
0382: return this .ast.getBindingResolver().findDeclaringNode(key);
0383: }
0384:
0385: /**
0386: * Returns a list of the comments encountered while parsing
0387: * this compilation unit.
0388: * <p>
0389: * Since the Java language allows comments to appear most anywhere
0390: * in the source text, it is problematic to locate comments in relation
0391: * to the structure of an AST. The one exception is doc comments
0392: * which, by convention, immediately precede type, field, and
0393: * method declarations; these comments are located in the AST
0394: * by {@link BodyDeclaration#getJavadoc BodyDeclaration.getJavadoc}.
0395: * Other comments do not show up in the AST. The table of comments
0396: * is provided for clients that need to find the source ranges of
0397: * all comments in the original source string. It includes entries
0398: * for comments of all kinds (line, block, and doc), arranged in order
0399: * of increasing source position.
0400: * </p>
0401: * <p>
0402: * Note on comment parenting: The {@link ASTNode#getParent() getParent()}
0403: * of a doc comment associated with a body declaration is the body
0404: * declaration node; for these comment nodes
0405: * {@link ASTNode#getRoot() getRoot()} will return the compilation unit
0406: * (assuming an unmodified AST) reflecting the fact that these nodes
0407: * are property located in the AST for the compilation unit.
0408: * However, for other comment nodes, {@link ASTNode#getParent() getParent()}
0409: * will return <code>null</code>, and {@link ASTNode#getRoot() getRoot()}
0410: * will return the comment node itself, indicating that these comment nodes
0411: * are not directly connected to the AST for the compilation unit. The
0412: * {@link Comment#getAlternateRoot Comment.getAlternateRoot}
0413: * method provides a way to navigate from a comment to its compilation
0414: * unit.
0415: * </p>
0416: * <p>
0417: * A note on visitors: The only comment nodes that will be visited when
0418: * visiting a compilation unit are the doc comments parented by body
0419: * declarations. To visit all comments in normal reading order, iterate
0420: * over the comment table and call {@link ASTNode#accept(ASTVisitor) accept}
0421: * on each element.
0422: * </p>
0423: * <p>
0424: * Clients cannot modify the resulting list.
0425: * </p>
0426: *
0427: * @return an unmodifiable list of comments in increasing order of source
0428: * start position, or <code>null</code> if comment information
0429: * for this compilation unit is not available
0430: * @see ASTParser
0431: * @since 3.0
0432: */
0433: public List getCommentList() {
0434: return this .optionalCommentList;
0435: }
0436:
0437: /**
0438: * Returns the internal comment mapper.
0439: *
0440: * @return the comment mapper, or <code>null</code> if none.
0441: * @since 3.0
0442: */
0443: DefaultCommentMapper getCommentMapper() {
0444: return this .commentMapper;
0445: }
0446:
0447: /**
0448: * Returns the extended source length of the given node. Unlike
0449: * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()},
0450: * the extended source range may include comments and whitespace
0451: * immediately before or after the normal source range for the node.
0452: *
0453: * @param node the node
0454: * @return a (possibly 0) length, or <code>0</code>
0455: * if no source position information is recorded for this node
0456: * @see #getExtendedStartPosition(ASTNode)
0457: * @since 3.0
0458: */
0459: public int getExtendedLength(ASTNode node) {
0460: if (node == null) {
0461: throw new IllegalArgumentException();
0462: }
0463: if (this .commentMapper == null || node.getAST() != getAST()) {
0464: // fall back: use best info available
0465: return node.getLength();
0466: } else {
0467: return this .commentMapper.getExtendedLength(node);
0468: }
0469: }
0470:
0471: /**
0472: * Returns the extended start position of the given node. Unlike
0473: * {@link ASTNode#getStartPosition()} and {@link ASTNode#getLength()},
0474: * the extended source range may include comments and whitespace
0475: * immediately before or after the normal source range for the node.
0476: *
0477: * @param node the node
0478: * @return the 0-based character index, or <code>-1</code>
0479: * if no source position information is recorded for this node
0480: * @see #getExtendedLength(ASTNode)
0481: * @since 3.0
0482: */
0483: public int getExtendedStartPosition(ASTNode node) {
0484: if (node == null) {
0485: throw new IllegalArgumentException();
0486: }
0487: if (this .commentMapper == null || node.getAST() != getAST()) {
0488: // fall back: use best info available
0489: return node.getStartPosition();
0490: } else {
0491: return this .commentMapper.getExtendedStartPosition(node);
0492: }
0493: }
0494:
0495: /**
0496: * The Java element (an <code>org.eclipse.jdt.core.ICompilationUnit</code> or an <code>org.eclipse.jdt.core.IClassFile</code>)
0497: * this compilation unit was created from, or <code>null</code> if it was not created from a Java element.
0498: *
0499: * @return the Java element this compilation unit was created from, or <code>null</code> if none
0500: * @since 3.1
0501: * @see #getTypeRoot()
0502: */
0503: public IJavaElement getJavaElement() {
0504: return this .typeRoot;
0505: }
0506:
0507: /**
0508: * Returns the list of messages reported by the compiler during the parsing
0509: * or the type checking of this compilation unit. This list might be a subset of
0510: * errors detected and reported by a Java compiler.
0511: * <p>
0512: * This list of messages is suitable for simple clients that do little
0513: * more than log the messages or display them to the user. Clients that
0514: * need further details should call <code>getProblems</code> to get
0515: * compiler problem objects.
0516: * </p>
0517: *
0518: * @return the list of messages, possibly empty
0519: * @see #getProblems()
0520: * @see ASTParser
0521: */
0522: public Message[] getMessages() {
0523: if (this .messages == null) {
0524: int problemLength = this .problems.length;
0525: if (problemLength == 0) {
0526: this .messages = EMPTY_MESSAGES;
0527: } else {
0528: this .messages = new Message[problemLength];
0529: for (int i = 0; i < problemLength; i++) {
0530: IProblem problem = this .problems[i];
0531: int start = problem.getSourceStart();
0532: int end = problem.getSourceEnd();
0533: messages[i] = new Message(problem.getMessage(),
0534: start, end - start + 1);
0535: }
0536: }
0537: }
0538: return this .messages;
0539: }
0540:
0541: /* (omit javadoc for this method)
0542: * Method declared on ASTNode.
0543: */
0544: final int getNodeType0() {
0545: return COMPILATION_UNIT;
0546: }
0547:
0548: /**
0549: * Returns the node for the package declaration of this compilation
0550: * unit, or <code>null</code> if this compilation unit is in the
0551: * default package.
0552: *
0553: * @return the package declaration node, or <code>null</code> if none
0554: */
0555: public PackageDeclaration getPackage() {
0556: return this .optionalPackageDeclaration;
0557: }
0558:
0559: /**
0560: * Given a line number and column number, returns the corresponding
0561: * position in the original source string.
0562: * Returns -2 if no line number information is available for this
0563: * compilation unit.
0564: * Returns the total size of the source string if <code>line</code>
0565: * is greater than the actual number lines in the unit.
0566: * Returns -1 if <code>column</code> is less than 0,
0567: * or the position of the last character of the line if <code>column</code>
0568: * is beyond the legal range, or the given line number is less than one.
0569: *
0570: * @param line the one-based line number
0571: * @param column the zero-based column number
0572: * @return the 0-based character position in the source string;
0573: * <code>-2</code> if line/column number information is not known
0574: * for this compilation unit or <code>-1</code> the inputs are not valid
0575: * @since 3.2
0576: */
0577: public int getPosition(int line, int column) {
0578: if (this .lineEndTable == null)
0579: return -2;
0580: if (line < 1 || column < 0)
0581: return -1;
0582: int length;
0583: if ((length = this .lineEndTable.length) == 0) {
0584: if (line != 1)
0585: return -1;
0586: return column >= getStartPosition() + getLength() ? -1
0587: : column;
0588: }
0589: if (line == 1) {
0590: final int endOfLine = this .lineEndTable[0];
0591: return column > endOfLine ? -1 : column;
0592: } else if (line > length + 1) {
0593: // greater than the number of lines in the source string.
0594: return -1;
0595: }
0596: // -1 to for one-based to zero-based conversion.
0597: // -1, again, to get previous line.
0598: final int previousLineOffset = this .lineEndTable[line - 2];
0599: // previousLineOffset + 1 is the first character of the current line
0600: final int offsetForLine = previousLineOffset + 1;
0601: final int currentLineEnd = line == length + 1 ? getStartPosition()
0602: + getLength() - 1
0603: : this .lineEndTable[line - 1];
0604: if ((offsetForLine + column) > currentLineEnd) {
0605: return -1;
0606: } else {
0607: return offsetForLine + column;
0608: }
0609: }
0610:
0611: /**
0612: * Returns the list of detailed problem reports noted by the compiler
0613: * during the parsing or the type checking of this compilation unit. This
0614: * list might be a subset of errors detected and reported by a Java
0615: * compiler.
0616: * <p>
0617: * Simple clients that do little more than log the messages or display
0618: * them to the user should probably call <code>getMessages</code> instead.
0619: * </p>
0620: *
0621: * @return the list of detailed problem objects, possibly empty
0622: * @see #getMessages()
0623: * @see ASTParser
0624: * @since 2.1
0625: */
0626: public IProblem[] getProblems() {
0627: return this .problems;
0628: }
0629:
0630: /**
0631: * The Java type root (a {@link org.eclipse.jdt.core.ICompilationUnit compilation unit} or a {@link org.eclipse.jdt.core.IClassFile class file})
0632: * this compilation unit was created from, or <code>null</code> if it was not created from a Java type root.
0633: *
0634: * @return the Java type root this compilation unit was created from, or <code>null</code> if none
0635: * @since 3.3
0636: */
0637: public ITypeRoot getTypeRoot() {
0638: return this .typeRoot;
0639: }
0640:
0641: /**
0642: * Returns the live list of nodes for the import declarations of this
0643: * compilation unit, in order of appearance.
0644: *
0645: * @return the live list of import declaration nodes
0646: * (elementType: <code>ImportDeclaration</code>)
0647: */
0648: public List imports() {
0649: return this .imports;
0650: }
0651:
0652: /**
0653: * Return the index in the whole comments list {@link #getCommentList() }
0654: * of the first leading comments associated with the given node.
0655: *
0656: * @param node the node
0657: * @return 0-based index of first leading comment or -1 if node has no associated
0658: * comment before its start position.
0659: * @since 3.2
0660: */
0661: public int firstLeadingCommentIndex(ASTNode node) {
0662: if (node == null) {
0663: throw new IllegalArgumentException();
0664: }
0665: if (this .commentMapper == null || node.getAST() != getAST()) {
0666: return -1;
0667: }
0668: return this .commentMapper.firstLeadingCommentIndex(node);
0669: }
0670:
0671: /**
0672: * Return the index in the whole comments list {@link #getCommentList() }
0673: * of the last trailing comments associated with the given node.
0674: *
0675: * @param node the node
0676: * @return 0-based index of last trailing comment or -1 if node has no
0677: * associated comment after its end position.
0678: * @since 3.2
0679: */
0680: public int lastTrailingCommentIndex(ASTNode node) {
0681: if (node == null) {
0682: throw new IllegalArgumentException();
0683: }
0684: if (this .commentMapper == null || node.getAST() != getAST()) {
0685: return -1;
0686: }
0687: return this .commentMapper.lastTrailingCommentIndex(node);
0688: }
0689:
0690: /**
0691: * Initializes the internal comment mapper with the given
0692: * scanner.
0693: *
0694: * @param scanner the scanner
0695: * @since 3.0
0696: */
0697: void initCommentMapper(Scanner scanner) {
0698: this .commentMapper = new DefaultCommentMapper(
0699: this .optionalCommentTable);
0700: this .commentMapper.initialize(this , scanner);
0701: }
0702:
0703: /* (omit javadoc for this method)
0704: * Method declared on ASTNode.
0705: */
0706: final List internalGetChildListProperty(
0707: ChildListPropertyDescriptor property) {
0708: if (property == IMPORTS_PROPERTY) {
0709: return imports();
0710: }
0711: if (property == TYPES_PROPERTY) {
0712: return types();
0713: }
0714: // allow default implementation to flag the error
0715: return super .internalGetChildListProperty(property);
0716: }
0717:
0718: /* (omit javadoc for this method)
0719: * Method declared on ASTNode.
0720: */
0721: final ASTNode internalGetSetChildProperty(
0722: ChildPropertyDescriptor property, boolean get, ASTNode child) {
0723: if (property == PACKAGE_PROPERTY) {
0724: if (get) {
0725: return getPackage();
0726: } else {
0727: setPackage((PackageDeclaration) child);
0728: return null;
0729: }
0730: }
0731: // allow default implementation to flag the error
0732: return super .internalGetSetChildProperty(property, get, child);
0733: }
0734:
0735: /* (omit javadoc for this method)
0736: * Method declared on ASTNode.
0737: * @since 3.0
0738: */
0739: final List internalStructuralPropertiesForType(int apiLevel) {
0740: return propertyDescriptors(apiLevel);
0741: }
0742:
0743: /**
0744: * Returns the line number corresponding to the given source character
0745: * position in the original source string. The initial line of the
0746: * compilation unit is numbered 1, and each line extends through the
0747: * last character of the end-of-line delimiter. The very last line extends
0748: * through the end of the source string and has no line delimiter.
0749: * For example, the source string <code>class A\n{\n}</code> has 3 lines
0750: * corresponding to inclusive character ranges [0,7], [8,9], and [10,10].
0751: * Returns 1 for a character position that does not correspond to any
0752: * source line, or if no line number information is available for this
0753: * compilation unit.
0754: *
0755: * @param position a 0-based character position, possibly
0756: * negative or out of range
0757: * @return the 1-based line number, or <code>1</code> if the character
0758: * position does not correspond to a source line in the original
0759: * source file or if line number information is not known for this
0760: * compilation unit
0761: * @deprecated Use getLineNumber(int) instead. Be careful to handle the negative values.
0762: * @see ASTParser
0763: * @see #getLineNumber(int)
0764: */
0765: public int lineNumber(int position) {
0766: int lineNumber = getLineNumber(position);
0767: return lineNumber < 1 ? 1 : lineNumber;
0768: }
0769:
0770: /**
0771: * Returns the line number corresponding to the given source character
0772: * position in the original source string. The initial line of the
0773: * compilation unit is numbered 1, and each line extends through the
0774: * last character of the end-of-line delimiter. The very last line extends
0775: * through the end of the source string and has no line delimiter.
0776: * For example, the source string <code>class A\n{\n}</code> has 3 lines
0777: * corresponding to inclusive character ranges [0,7], [8,9], and [10,10].
0778: * Returns -1 for a character position that does not correspond to any
0779: * source line, or -2 if no line number information is available for this
0780: * compilation unit.
0781: *
0782: * @param position a 0-based character position, possibly
0783: * negative or out of range
0784: * @return the 1-based line number, or <code>-1</code> if the character
0785: * position does not correspond to a source line in the original
0786: * source file or <code>-2</code> if line number information is not known for this
0787: * compilation unit
0788: * @see ASTParser
0789: * @since 3.2
0790: */
0791: public int getLineNumber(int position) {
0792: if (this .lineEndTable == null)
0793: return -2;
0794: int length;
0795: if ((length = this .lineEndTable.length) == 0) {
0796: if (position >= getStartPosition() + getLength()) {
0797: return -1;
0798: }
0799: return 1;
0800: }
0801: int low = 0;
0802: if (position < 0) {
0803: // position illegal
0804: return -1;
0805: }
0806: if (position <= this .lineEndTable[low]) {
0807: // before the first line delimiter
0808: return 1;
0809: }
0810: // assert position > lineEndTable[low+1] && low == 0
0811: int hi = length - 1;
0812: if (position > this .lineEndTable[hi]) {
0813: // position beyond the last line separator
0814: if (position >= getStartPosition() + getLength()) {
0815: // this is beyond the end of the source length
0816: return -1;
0817: } else {
0818: return length + 1;
0819: }
0820: }
0821: // assert lineEndTable[low] < position <= lineEndTable[hi]
0822: // && low == 0 && hi == length - 1 && low < hi
0823:
0824: // binary search line end table
0825: while (true) {
0826: // invariant lineEndTable[low] < position <= lineEndTable[hi]
0827: // && 0 <= low < hi <= length - 1
0828: // reducing measure hi - low
0829: if (low + 1 == hi) {
0830: // assert lineEndTable[low] < position <= lineEndTable[low+1]
0831: // position is on line low+1 (line number is low+2)
0832: return low + 2;
0833: }
0834: // assert hi - low >= 2, so average is truly in between
0835: int mid = low + (hi - low) / 2;
0836: // assert 0 <= low < mid < hi <= length - 1
0837: if (position <= this .lineEndTable[mid]) {
0838: // assert lineEndTable[low] < position <= lineEndTable[mid]
0839: // && 0 <= low < mid < hi <= length - 1
0840: hi = mid;
0841: } else {
0842: // position > lineEndTable[mid]
0843: // assert lineEndTable[mid] < position <= lineEndTable[hi]
0844: // && 0 <= low < mid < hi <= length - 1
0845: low = mid;
0846: }
0847: // in both cases, invariant reachieved with reduced measure
0848: }
0849: }
0850:
0851: /* (omit javadoc for this method)
0852: * Method declared on ASTNode.
0853: */
0854: int memSize() {
0855: int size = BASE_NODE_SIZE + 8 * 4;
0856: if (this .lineEndTable != null) {
0857: size += HEADERS + 4 * this .lineEndTable.length;
0858: }
0859: if (this .optionalCommentTable != null) {
0860: size += HEADERS + 4 * this .optionalCommentTable.length;
0861: }
0862: // ignore the space taken up by optionalCommentList
0863: return size;
0864: }
0865:
0866: /**
0867: * Enables the recording of changes to this compilation
0868: * unit and its descendents. The compilation unit must have
0869: * been created by <code>ASTParser</code> and still be in
0870: * its original state. Once recording is on,
0871: * arbitrary changes to the subtree rooted at this compilation
0872: * unit are recorded internally. Once the modification has
0873: * been completed, call <code>rewrite</code> to get an object
0874: * representing the corresponding edits to the original
0875: * source code string.
0876: *
0877: * @exception IllegalArgumentException if this compilation unit is
0878: * marked as unmodifiable, or if this compilation unit has already
0879: * been tampered with, or recording has already been enabled
0880: * @since 3.0
0881: */
0882: public void recordModifications() {
0883: getAST().recordModifications(this );
0884: }
0885:
0886: /**
0887: * Converts all modifications recorded for this compilation
0888: * unit into an object representing the corresponding text
0889: * edits to the given document containing the original source
0890: * code for this compilation unit.
0891: * <p>
0892: * The compilation unit must have been created by
0893: * <code>ASTParser</code> from the source code string in the
0894: * given document, and recording must have been turned
0895: * on with a prior call to <code>recordModifications</code>
0896: * while the AST was still in its original state.
0897: * </p>
0898: * <p>
0899: * Calling this methods does not discard the modifications
0900: * on record. Subsequence modifications made to the AST
0901: * are added to the ones already on record. If this method
0902: * is called again later, the resulting text edit object will
0903: * accurately reflect the net cumulative affect of all those
0904: * changes.
0905: * </p>
0906: *
0907: * @param document original document containing source code
0908: * for this compilation unit
0909: * @param options the table of formatter options
0910: * (key type: <code>String</code>; value type: <code>String</code>);
0911: * or <code>null</code> to use the standard global options
0912: * {@link org.eclipse.jdt.core.JavaCore#getOptions() JavaCore.getOptions()}.
0913: * @return text edit object describing the changes to the
0914: * document corresponding to the recorded AST modifications
0915: * @exception IllegalArgumentException if the document passed is
0916: * <code>null</code> or does not correspond to this AST
0917: * @exception IllegalStateException if <code>recordModifications</code>
0918: * was not called to enable recording
0919: * @see #recordModifications()
0920: * @since 3.0
0921: */
0922: public TextEdit rewrite(IDocument document, Map options) {
0923: return getAST().rewrite(document, options);
0924: }
0925:
0926: /**
0927: * Sets the list of the comments encountered while parsing
0928: * this compilation unit.
0929: *
0930: * @param commentTable a list of comments in increasing order
0931: * of source start position, or <code>null</code> if comment
0932: * information for this compilation unit is not available
0933: * @exception IllegalArgumentException if the comment table is
0934: * not in increasing order of source position
0935: * @see #getCommentList()
0936: * @see ASTParser
0937: * @since 3.0
0938: */
0939: void setCommentTable(Comment[] commentTable) {
0940: // double check table to ensure that all comments have
0941: // source positions and are in strictly increasing order
0942: if (commentTable == null) {
0943: this .optionalCommentList = null;
0944: this .optionalCommentTable = null;
0945: } else {
0946: int nextAvailablePosition = 0;
0947: for (int i = 0; i < commentTable.length; i++) {
0948: Comment comment = commentTable[i];
0949: if (comment == null) {
0950: throw new IllegalArgumentException();
0951: }
0952: int start = comment.getStartPosition();
0953: int length = comment.getLength();
0954: if (start < 0 || length < 0
0955: || start < nextAvailablePosition) {
0956: throw new IllegalArgumentException();
0957: }
0958: nextAvailablePosition = comment.getStartPosition()
0959: + comment.getLength();
0960: }
0961: this .optionalCommentTable = commentTable;
0962: List commentList = Arrays.asList(commentTable);
0963: // protect the list from further modification
0964: this .optionalCommentList = Collections
0965: .unmodifiableList(commentList);
0966: }
0967: }
0968:
0969: /**
0970: * Sets the Java type root (a {@link org.eclipse.jdt.core.ICompilationUnit compilation unit} or a {@link org.eclipse.jdt.core.IClassFile class file})
0971: * this compilation unit was created from, or <code>null</code> if it was not created from a Java type root.
0972: *
0973: * @param typeRoot the Java type root this compilation unit was created from
0974: */
0975: void setTypeRoot(ITypeRoot typeRoot) {
0976: this .typeRoot = typeRoot;
0977: }
0978:
0979: /**
0980: * Sets the line end table for this compilation unit.
0981: * If <code>lineEndTable[i] == p</code> then line number <code>i+1</code>
0982: * ends at character position <code>p</code>. Except for the last line, the
0983: * positions are that of (the last character of) the line delimiter.
0984: * For example, the source string <code>A\nB\nC</code> has
0985: * line end table {1, 3, 4}.
0986: *
0987: * @param lineEndTable the line end table
0988: */
0989: void setLineEndTable(int[] lineEndTable) {
0990: if (lineEndTable == null) {
0991: throw new NullPointerException();
0992: }
0993: // alternate root is *not* considered a structural property
0994: // but we protect them nevertheless
0995: checkModifiable();
0996: this .lineEndTable = lineEndTable;
0997: }
0998:
0999: /**
1000: * Sets or clears the package declaration of this compilation unit
1001: * node to the given package declaration node.
1002: *
1003: * @param pkgDecl the new package declaration node, or
1004: * <code>null</code> if this compilation unit does not have a package
1005: * declaration (that is in the default package)
1006: * @exception IllegalArgumentException if:
1007: * <ul>
1008: * <li>the node belongs to a different AST</li>
1009: * <li>the node already has a parent</li>
1010: * </ul>
1011: */
1012: public void setPackage(PackageDeclaration pkgDecl) {
1013: ASTNode oldChild = this .optionalPackageDeclaration;
1014: preReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY);
1015: this .optionalPackageDeclaration = pkgDecl;
1016: postReplaceChild(oldChild, pkgDecl, PACKAGE_PROPERTY);
1017: }
1018:
1019: /**
1020: * Sets the array of problems reported by the compiler during the parsing or
1021: * name resolution of this compilation unit.
1022: *
1023: * @param problems the list of problems
1024: */
1025: void setProblems(IProblem[] problems) {
1026: if (problems == null) {
1027: throw new IllegalArgumentException();
1028: }
1029: this .problems = problems;
1030: }
1031:
1032: /* (omit javadoc for this method)
1033: * Method declared on ASTNode.
1034: */
1035: final boolean subtreeMatch0(ASTMatcher matcher, Object other) {
1036: // dispatch to correct overloaded match method
1037: return matcher.match(this , other);
1038: }
1039:
1040: /* (omit javadoc for this method)
1041: * Method declared on ASTNode.
1042: */
1043: int treeSize() {
1044: int size = memSize();
1045: if (this .optionalPackageDeclaration != null) {
1046: size += getPackage().treeSize();
1047: }
1048: size += this .imports.listSize();
1049: size += this .types.listSize();
1050: // include disconnected comments
1051: if (this .optionalCommentList != null) {
1052: for (int i = 0; i < this .optionalCommentList.size(); i++) {
1053: Comment comment = (Comment) this .optionalCommentList
1054: .get(i);
1055: if (comment != null && comment.getParent() == null) {
1056: size += comment.treeSize();
1057: }
1058: }
1059: }
1060: return size;
1061: }
1062:
1063: /**
1064: * Returns the live list of nodes for the top-level type declarations of this
1065: * compilation unit, in order of appearance.
1066: * <p>
1067: * Note that in JLS3, the types may include both enum declarations
1068: * and annotation type declarations introduced in J2SE 5.
1069: * For JLS2, the elements are always <code>TypeDeclaration</code>.
1070: * </p>
1071: *
1072: * @return the live list of top-level type declaration
1073: * nodes (elementType: <code>AbstractTypeDeclaration</code>)
1074: */
1075: public List types() {
1076: return this.types;
1077: }
1078: }
|