* Copyright (C) 2010 Robert Futrell
* robert_futrell at users.sourceforge.net
* http://fifesoft.com/rsyntaxtextarea
* This library is distributed under a modified BSD license. See the included
* RSTALanguageSupport.License.txt file for details.
package org.fife.rsta.ac.java.rjc.ast;
import java.util.ArrayList;
import java.util.Iterator;
import org.fife.rsta.ac.java.rjc.lexer.Offset;
import org.fife.rsta.ac.java.rjc.lexer.Token;
import org.fife.rsta.ac.java.rjc.notices.ParserNotice;
* A <code>CompilationUnit</code> is the root node of an AST for a Java
* [[Annotations] 'package' QualifiedIdentifier ';' ] {ImportDeclaration} {TypeDeclaration}
public class CompilationUnit extends AbstractASTNode
implements TypeDeclarationContainer {
private List annotations;
private List typeDeclarations;
private static final Offset ZERO_OFFSET = new ZeroOffset();
public CompilationUnit(String name) {
super(name, ZERO_OFFSET);
imports = new ArrayList(3); // Usually not many,
typeDeclarations = new ArrayList(1); // Usually only 1
public void addImportDeclaration(ImportDeclaration dec) {
* Shorthand for "<tt>addParserNotice(new ParserNotice(t, msg))</tt>".
public void addParserNotice(Token t, String msg) {
addParserNotice(new ParserNotice(t, msg));
public void addParserNotice(ParserNotice notice) {
notices = new ArrayList();
public void addTypeDeclaration(TypeDeclaration typeDec) {
typeDeclarations.add(typeDec);
public int getAnnotationCount() {
return annotations.size();
public Iterator getAnnotationIterator() {
return annotations.iterator();
* Returns the deepest-nested type declaration that contains a given
* @param offs The offset.
* @return The deepest-nested type declaration containing the offset, or
* <code>null</code> if the offset is outside of any type
* declaration (such as in the import statements, etc.).
* @see #getTypeDeclarationAtOffset(int)
public TypeDeclaration getDeepestTypeDeclarationAtOffset(int offs) {
TypeDeclaration td = getTypeDeclarationAtOffset(offs);
TypeDeclaration next = td.getChildTypeAtOffset(offs);
next = td.getChildTypeAtOffset(offs);
* TODO: Return range for more instances than just class methods.
* Also handle child TypeDeclarations.
* @return The starting and ending offset of the enclosing method range.
public Point getEnclosingMethodRange(int offs) {
for (Iterator i=getTypeDeclarationIterator(); i.hasNext(); ) {
TypeDeclaration td = (TypeDeclaration)i.next();
int start = td.getBodyStartOffset();
int end = td.getBodyEndOffset();
if (offs>=start && offs<=end) {
if (td instanceof NormalClassDeclaration) {
NormalClassDeclaration ncd = (NormalClassDeclaration)td;
for (Iterator j=ncd.getMemberIterator(); j.hasNext(); ) {
Member m = (Member)j.next();
if (m instanceof Method) {
Method method = (Method)m;
CodeBlock body = method.getBody();
int start2 = method.getNameStartOffset();
//int start2 = body.getStartOffset();
int end2 = body.getNameEndOffset();
if (offs>=start2 && offs<=end2) {
range = new Point(start2, end2);
if (range==null) { // Default to the entire class' body.
range = new Point(start, end);
public int getImportCount() {
* Returns the import declarations of this compilation unit. This is a
* copy of the list of imports, but the actual individual
* {@link ImportDeclaration}s are not copies, so modifying them will modify
* @return A list or imports, or an empty list if there are none.
public List getImports() {
return new ArrayList(imports);
public Iterator getImportIterator() {
return imports.iterator();
* Returns the package of this compilation unit.
* @return The package of this compilation unit, or <code>null</code> if
* this compilation unit is not in a package.
public Package getPackage() {
* Returns the fully-qualified package name of this compilation unit.
* @return The package name, or <code>null</code> if this compilation unit
* is not in a package (in the default package).
public String getPackageName() {
return pkg==null ? null : pkg.getName();
public ParserNotice getParserNotice(int index) {
throw new IndexOutOfBoundsException("No parser notices available");
return (ParserNotice)notices.get(index);
public int getParserNoticeCount() {
return notices==null ? 0 : notices.size();
public TypeDeclaration getTypeDeclaration(int index) {
return (TypeDeclaration)typeDeclarations.get(index);
* Returns the type declaration in this file that contains the specified
* @param offs The offset.
* @return The type declaration, or <code>null</code> if the offset is
* outside of any type declaration.
* @see #getDeepestTypeDeclarationAtOffset(int)
public TypeDeclaration getTypeDeclarationAtOffset(int offs) {
TypeDeclaration typeDec = null;
for (Iterator i=getTypeDeclarationIterator(); i.hasNext(); ) {
TypeDeclaration td = (TypeDeclaration)i.next();
if (td.getBodyContainsOffset(offs)) {
public int getTypeDeclarationCount() {
return typeDeclarations.size();
public Iterator getTypeDeclarationIterator() {
return typeDeclarations.iterator();
public void setPackage(Package pkg) {
* An offset that always returns 0.
private static class ZeroOffset implements Offset {