/******************************************************************************* | |
* Copyright (c) 2001 International Business Machines Corp. and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Common Public License v0.5 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/cpl-v05.html | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
******************************************************************************/ | |
package org.eclipse.jdt.core.dom; | |
import java.util.List; | |
/** | |
* Java compilation unit AST node type. This is the type of the root of an AST. | |
* | |
* Range 0: first character through last character of the source file. | |
* | |
* <pre> | |
* CompilationUnit: | |
* [ PackageDeclaration ] | |
* { ImportDeclaration } | |
* { TypeDeclaration | <b>;</b> } | |
* </pre> | |
* | |
* @since 2.0 | |
*/ | |
public class CompilationUnit extends ASTNode { | |
/** | |
* The package declaration, or <code>null</code> if none; initially | |
* <code>null</code>. | |
*/ | |
private PackageDeclaration optionalPackageDeclaration = null; | |
/** | |
* The list of import declarations in textual order order; | |
* initially none (elementType: <code>ImportDeclaration</code>). | |
*/ | |
private ASTNode.NodeList imports = | |
new ASTNode.NodeList(false, ImportDeclaration.class); | |
/** | |
* The list of type declarations in textual order order; | |
* initially none (elementType: <code>TypeDeclaration</code>) | |
*/ | |
private ASTNode.NodeList types = | |
new ASTNode.NodeList(false, TypeDeclaration.class); | |
/** | |
* 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, 4}. | |
*/ | |
private int[] lineEndTable = new int[0]; | |
/** | |
* Canonical empty list of messages. | |
*/ | |
private static final Message[] EMPTY_MESSAGES = new Message[0]; | |
/** | |
* Messages reported by the compiler during parsing or name resolution; | |
* defaults to the empty list. | |
*/ | |
private Message[] messages = EMPTY_MESSAGES; | |
/** | |
* 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(); | |
} | |
modifying(); | |
this.lineEndTable = lineEndTable; | |
} | |
/** | |
* 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. | |
*/ | |
ASTNode clone(AST target) { | |
CompilationUnit result = new CompilationUnit(target); | |
// n.b do not copy line number table or messages | |
result.setPackage( | |
(PackageDeclaration) ASTNode.copySubtree(target, getPackage())); | |
result.imports().addAll(ASTNode.copySubtrees(target, imports())); | |
result.types().addAll(ASTNode.copySubtrees(target, types())); | |
return result; | |
} | |
/* (omit javadoc for this method) | |
* Method declared on ASTNode. | |
*/ | |
boolean equalSubtrees(Object other) { | |
if (!(other instanceof CompilationUnit)) { | |
return false; | |
} | |
CompilationUnit o = (CompilationUnit) other; | |
return | |
(ASTNode.equalNodes(getPackage(), o.getPackage()) | |
&& ASTNode.equalLists(imports(), o.imports()) | |
&& ASTNode.equalLists(types(), o.types())); | |
} | |
/* (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, imports); | |
acceptChildren(visitor, types); | |
} | |
visitor.endVisit(this); | |
} | |
/** | |
* 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 optionalPackageDeclaration; | |
} | |
/** | |
* 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 is not have no package | |
* declaration (that is, is to be in the default package) | |
* @exception $precondition-violation:different-ast$ | |
* @exception $precondition-violation:not-unparented$ | |
*/ | |
public void setPackage(PackageDeclaration pkgDecl) { | |
replaceChild(this.optionalPackageDeclaration, pkgDecl, false); | |
this.optionalPackageDeclaration = pkgDecl; | |
} | |
/** | |
* Returns the live list of nodes for the import declaration of this | |
* compilation unit, in order of appearance. | |
* | |
* @return the live list of import declaration nodes | |
* (elementType: <code>ImportDeclaration</code>) | |
*/ | |
public List imports() { | |
return imports; | |
} | |
/** | |
* Returns the live list of nodes for the top-level type declaration of this | |
* compilation unit, in order of appearance. | |
* | |
* @return the live list of top-level type declaration | |
* nodes (elementType: <code>TypeDeclaration</code>) | |
*/ | |
public List types() { | |
return types; | |
} | |
/** | |
* 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. | |
* <p> | |
* The following table indicates the expected node type for the various | |
* different kinds of bindings: | |
* <ul> | |
* <li></li> | |
* <li>package - a <code>PackageDeclaration</code></li> | |
* <li>class or interface - a <code>TypeDeclaration</code> or a | |
* <code>ClassInstanceCreation</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> | |
* </ul> | |
* </p> | |
* <p> | |
* Note that bindings are generally unavailable unless requested when the | |
* AST is being built. | |
* </p> | |
* | |
* @param binding the binding | |
* @return the corresponding node where the bindings is declared, | |
* or <code>null</code> if none | |
*/ | |
public ASTNode findDeclaringNode(IBinding binding) { | |
return getAST().getBindingResolver().findDeclaringNode(binding); | |
} | |
/** | |
* 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,8], [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 | |
* @see AST#parseCompilationUnit | |
*/ | |
public int lineNumber(int position) { | |
int length = lineEndTable.length; | |
if (length == 0) { | |
// no line number info | |
return 1; | |
} | |
int low = 0; | |
if (position <= lineEndTable[low]) { | |
// position illegal or before the first line delimiter | |
return 1; | |
} | |
// assert position > lineEndTable[low+1] && low == 0 | |
int hi = length - 1; | |
if (position > lineEndTable[length - 1]) { | |
// position beyond the end of last line | |
return 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) / 2; | |
// assert 0 <= low < mid < hi <= length - 1 | |
if (position <= 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 | |
} | |
} | |
/** | |
* Returns the list of messages reported by the compiler during the parsing | |
* or name resolution of this compilation unit. | |
* | |
* @return the list of messages, possibly empty | |
* @see AST#parseCompilationUnit | |
*/ | |
public Message[] getMessages() { | |
return messages; | |
} | |
/** | |
* Sets the array of messages reported by the compiler during the parsing or | |
* name resolution of this compilation unit. | |
* | |
* @param messages the list of messages | |
*/ | |
void setMessages(Message[] messages) { | |
if (messages == null) { | |
throw new IllegalArgumentException(); | |
} | |
this.messages = messages; | |
} | |
/* (omit javadoc for this method) | |
* Method declared on ASTNode. | |
*/ | |
int memSize() { | |
int size = BASE_NODE_SIZE + 4 * 4; | |
if (lineEndTable != null) { | |
size += HEADERS + 4 * lineEndTable.length; | |
} | |
return size; | |
} | |
/* (omit javadoc for this method) | |
* Method declared on ASTNode. | |
*/ | |
int treeSize() { | |
return | |
memSize() | |
+ (optionalPackageDeclaration == null ? 0 : getPackage().treeSize()) | |
+ imports.listSize() | |
+ types.listSize(); | |
} | |
} | |