/* gnu.classpath.tools.gjdoc.Parser Copyright (C) 2001, 2005, 2008 Free Software Foundation, Inc. This file is part of GNU Classpath. GNU Classpath is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU Classpath is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Classpath; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ package gnu.classpath.tools.gjdoc; import java.io.*; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.util.*; import com.sun.javadoc.*; import gnu.classpath.tools.IOToolkit; import gnu.classpath.tools.NotifyingInputStreamReader; import gnu.classpath.tools.MalformedInputListener; import gnu.classpath.tools.MalformedInputEvent; class IgnoredFileParseException extends ParseException { // marker exception } abstract class SourceComponent { abstract int match(char[] source, int index) throws ParseException; int process(Parser parser, char[] source, int startIndex, int endIndex) throws ParseException, IOException { return endIndex; } int getEndIndex(char[] source, int endIndex) throws ParseException { return endIndex; } } abstract class BlockSourceComponent extends SourceComponent { int getEndIndex(char[] source, int endIndex) throws ParseException { return Parser.skipExpression(source, endIndex, 1, '\0'); } } class Whitespace extends SourceComponent { int match(char[] source, int index) { int rc=index; int slen=source.length; while (rc<slen && Parser.WHITESPACE.indexOf(source[rc])>=0) ++rc; return (rc!=index) ? rc : -1; } } class BracketClose extends SourceComponent { int match(char[] source, int index) { if (source[index]=='}') { return index+1; } else { return -1; } } int process(Parser parser, char[] source, int startIndex, int endIndex) throws ParseException, IOException { parser.classClosed(); return endIndex; } } class CommentComponent extends SourceComponent { int match(char[] source, int index) throws ParseException { if (index+1<source.length && source[index]=='/' && source[index+1]=='*') { for (index+=2; index+1<source.length; ++index) { if (source[index]=='*' && source[index+1]=='/') return index+2; } throw new ParseException("unexpected end of input"); } return -1; } int process(Parser parser, char[] source, int startIndex, int endIndex) { if (source[startIndex+0]=='/' && source[startIndex+1]=='*' && source[startIndex+2]=='*') { parser.setLastComment(new String(source, startIndex, endIndex-startIndex)); } else if (null == parser.getBoilerplateComment() && Main.getInstance().isCopyLicenseText()) { String boilerplateComment = new String(source, startIndex + 2, endIndex-startIndex - 4); if (boilerplateComment.toLowerCase().indexOf("copyright") >= 0) { parser.setBoilerplateComment(boilerplateComment); } } return endIndex; } } class SlashSlashCommentComponent extends SourceComponent { int match(char[] source, int index) { if (index+1<source.length && source[index]=='/' && source[index+1]=='/') { index+=2; while (index<source.length && source[index]!='\n') ++index; return index; } else { return -1; } } } class EmptyStatementComponent extends SourceComponent { int match(char[] source, int index) { while (index < source.length && Parser.isWhitespace(source[index])) { ++ index; } if (index < source.length && source[index] == ';') { return index+1; } else { return -1; } } } class ImportComponent extends SourceComponent { int match(char[] source, int index) { if (index+7<source.length) { if (source[index+0]=='i' && source[index+1]=='m' && source[index+2]=='p' && source[index+3]=='o' && source[index+4]=='r' && source[index+5]=='t' && Parser.WHITESPACE.indexOf(source[index+6])>=0) { for (index+=7; index<source.length && source[index]!=';'; ++index) ; return index+1; } } return -1; } int process(Parser parser, char[] source, int startIndex, int endIndex) throws ParseException, IOException { String importString=new String(source,startIndex+7,endIndex-startIndex-7-1).trim(); parser.importEncountered(importString); return endIndex; } } class PackageComponent extends SourceComponent { int match(char[] source, int index) { if (index+10<source.length) { if (source[index+0]=='p' && source[index+1]=='a' && source[index+2]=='c' && source[index+3]=='k' && source[index+4]=='a' && source[index+5]=='g' && source[index+6]=='e' && Parser.WHITESPACE.indexOf(source[index+7])>=0) { for (index+=7; index<source.length && source[index]!=';'; ++index) ; return index+1; } } return -1; } int process(Parser parser, char[] source, int startIndex, int endIndex) { String packageName=new String(source,startIndex+8,endIndex-startIndex-8-1).trim(); parser.packageOpened(packageName); return endIndex; } } class FieldComponent extends SourceComponent { int match(char[] source, int index) throws ParseException { boolean isField=false; final int STATE_NORMAL=1; final int STATE_SLASHC=2; final int STATE_STARC=3; final int STATE_FIELDVAL=4; final int STATE_STRING=5; final int STATE_SINGLEQUOTED=6; final int STATE_STRING_BS=7; final int STATE_SINGLEQUOTED_BS=8; int state=STATE_NORMAL; int prevState=STATE_NORMAL; int fieldValueLevel = 0; for (; index<source.length && !isField; ++index) { if (state==STATE_STARC) { if (index<source.length-1 && source[index]=='*' && source[index+1]=='/') { ++index; state=prevState; } } else if (state==STATE_SLASHC) { if (source[index]=='\n') { state=prevState; } } else if (state==STATE_STRING) { if (source[index]=='\\') { state=STATE_STRING_BS; } else if (source[index]=='\"') { state=prevState; } } else if (state==STATE_STRING_BS) { state=STATE_STRING; } else if (state==STATE_SINGLEQUOTED) { if (source[index]=='\\') { state=STATE_SINGLEQUOTED_BS; } else if (source[index]=='\'') { state=prevState; } } else if (state==STATE_SINGLEQUOTED_BS) { state=STATE_SINGLEQUOTED; } else if (state==STATE_FIELDVAL) { if (source[index]=='/') { if (index<source.length-1 && source[index+1]=='*') { state=STATE_STARC; ++index; } else if (index<source.length-1 && source[index+1]=='/') { state=STATE_SLASHC; ++index; } } else if (source[index]=='{') { ++ fieldValueLevel; } else if (source[index]=='}') { -- fieldValueLevel; } else if (source[index]=='\"') { state=STATE_STRING; } else if (source[index]=='\'') { state=STATE_SINGLEQUOTED; } else if (source[index]==';' && 0 == fieldValueLevel) { isField=true; break; } } else switch (source[index]) { case '/': if (index<source.length-1 && source[index+1]=='*') { state=STATE_STARC; ++index; } else if (index<source.length-1 && source[index+1]=='/') { state=STATE_SLASHC; ++index; } break; case '{': // class case '(': // method return -1; case '=': // field state=STATE_FIELDVAL; prevState=state; continue; case ';': // field isField=true; break; } if (isField) break; } if (!isField || index==source.length) { return -1; } //System.err.println("char is "+source[index]); if (source[index]!=';') { index=Parser.skipExpression(source, index, 0, ';'); } return index+1; } int process(Parser parser, char[] source, int startIndex, int endIndex) { //Debug.log(9,"found package statement: \""+str+"\""); //Debug.log(9,"found function component: '"+str+"'"); //xxx(new FieldDocImpl(ctx.classDoc, ctx.classDoc.containingPackage(), 0, false, false)); // Ignore superfluous semicoli after class definition if (endIndex-startIndex<=1) return endIndex; //assert (parser.ctx!=null); Collection fields=FieldDocImpl.createFromSource(parser.ctx.classDoc, parser.ctx.classDoc.containingPackage(), source, startIndex, endIndex); for (Iterator it=fields.iterator(); it.hasNext(); ) { FieldDocImpl field=(FieldDocImpl)it.next(); boolean fieldHasSerialTag=!field.isTransient() && !field.isStatic(); //field.hasSerialTag(); if ((field.isIncluded() || fieldHasSerialTag) && parser.getAddComments()) { field.setRawCommentText(parser.getLastComment()); } parser.ctx.fieldList.add(field); if (field.isIncluded()) { parser.ctx.filteredFieldList.add(field); } if (fieldHasSerialTag) { parser.ctx.sfieldList.add(field); } } parser.setLastComment(null); return endIndex; } } class FunctionComponent extends BlockSourceComponent { int getEndIndex(char[] source, int endIndex) throws ParseException { if (source[endIndex-1]==';') { return endIndex; } else { return super.getEndIndex(source, endIndex); } } int process(Parser parser, char[] source, int startIndex, int endIndex) throws IOException, ParseException { //ctx.fieldList.add(FieldDocImpl.createFromSource(source, startIndex, endIndex)); //System.out.println("function match '"+new String(source,startIndex,endIndex-startIndex)+"'"); ExecutableMemberDocImpl execDoc=MethodDocImpl.createFromSource(parser.ctx.classDoc, parser.ctx.classDoc.containingPackage(), source, startIndex, endIndex); if (parser.getAddComments()) execDoc.setRawCommentText(parser.getLastComment()); parser.setLastComment(null); if (execDoc.isMethod()) { parser.ctx.methodList.add(execDoc); if (execDoc.isIncluded()) { parser.ctx.filteredMethodList.add(execDoc); } } else { parser.ctx.constructorList.add(execDoc); if (execDoc.isIncluded()) { parser.ctx.filteredConstructorList.add(execDoc); } } if (execDoc.isMethod() && (execDoc.name().equals("readObject") || execDoc.name().equals("writeObject") || execDoc.name().equals("readExternal") || execDoc.name().equals("writeExternal") || execDoc.name().equals("readResolve"))) { // FIXME: add readExternal here? parser.ctx.maybeSerMethodList.add(execDoc); } return endIndex; } int match(char[] source, int index) { boolean isFunc=false; final int STATE_NORMAL=1; final int STATE_SLASHC=2; final int STATE_STARC=3; int state=STATE_NORMAL; for (; index<source.length && !isFunc; ++index) { if (state==STATE_STARC) { if (source[index]=='*' && source[index+1]=='/') { ++index; state=STATE_NORMAL; } } else if (state==STATE_SLASHC) { if (source[index]=='\n') { state=STATE_NORMAL; } } else switch (source[index]) { case '/': if (source[index+1]=='*') { state=STATE_STARC; ++index; } else if (source[index+1]=='/') { state=STATE_SLASHC; ++index; } break; case '=': // field case ';': // field case '{': // class return -1; case '(': isFunc=true; break; } if (isFunc) break; } if (!isFunc || index==source.length) return -1; for (; index<source.length && (state!=STATE_NORMAL || (source[index]!='{' && source[index]!=';')); ++index) if (state==STATE_SLASHC && source[index]=='\n') { state=STATE_NORMAL; } else if (index<source.length-1) { if (state==STATE_STARC) { if (source[index]=='*' && source[index+1]=='/') { state=STATE_NORMAL; } } else { if (source[index]=='/' && source[index+1]=='*') { state=STATE_STARC; } else if (source[index]=='/' && source[index+1]=='/') { state=STATE_SLASHC; } } } return index+1; } } class StaticBlockComponent extends BlockSourceComponent { int process(Parser parser, char[] source, int startIndex, int endIndex) { //Debug.log(9,"found package statement: \""+str+"\""); //Debug.log(9,"found function component: '"+str+"'"); parser.setLastComment(null); return endIndex; } int match(char[] source, int index) { if (source[index]=='{') return index+1; if (index+7<source.length) { if (source[index+0]=='s' && source[index+1]=='t' && source[index+2]=='a' && source[index+3]=='t' && source[index+4]=='i' && source[index+5]=='c') { for (index+=6; index<source.length && Parser.WHITESPACE.indexOf(source[index])>=0; ++index) ; if (index<source.length && source[index]=='{') return index+1; else return -1; } } return -1; } } class ClassComponent extends SourceComponent { int match(char[] source, int index) { boolean isClass=false; for (; index<source.length && !isClass; ++index) { switch (source[index]) { case '/': // possible comment if (index<source.length-1) { char c = source[index+1]; if ('/' == c) { index += 2; while (index<source.length && source[index]!=10) { ++ index; } } else if ('*' == c) { index += 3; while (index<source.length && (source[index-1] != '*' || source[index]!='/')) { ++ index; } } } break; case '@': // annotation index += 1; while(index<source.length && Character.isJavaIdentifierPart(source[index])) { ++ index; } if (index<source.length && source[index]=='(') { int parLevel = 1; index += 1; while (index<source.length && parLevel>0) { if (source[index] == '(') ++ parLevel; if (source[index] == ')') -- parLevel; ++ index; if (parLevel==0) break; } } break; case '=': // field case ';': // field case '(': // function return -1; case '{': isClass=true; break; } if (isClass) break; } if (!isClass || index>=source.length) return -1; return index+1; } int process(Parser parser, char[] source, int startIndex, int endIndex) throws ParseException, IOException { parser.classOpened(source, startIndex, endIndex); if (parser.getAddComments()) parser.ctx.classDoc.setRawCommentText(parser.getLastComment()); parser.setLastComment(null); if (parser.ctx.classDoc.isEnum()) { int depth = 0; for (int a = endIndex; a < source.length; ++a) { Debug.log(9, "Enum skipping " + a); if (source[a] == '{') { Debug.log(1, "Found inner { in enum"); ++depth; } if (source[a] == '}') { if (depth > 0) { Debug.log(1, "Found inner } in enum"); --depth; } else { Debug.log(1, "Found enum }"); parser.classClosed(); return a + 1; } } } } int rc=parser.parse(source, endIndex, parser.getClassLevelComponents()); return rc; } } public class Parser { static int skipExpression(char[] source, int endIndex, int level, char delimiter) throws ParseException { int orgEndIndex=endIndex; final int STATE_NORMAL=1; final int STATE_STARC=2; final int STATE_SLASHC=3; final int STATE_CHAR=4; final int STATE_STRING=5; int state=STATE_NORMAL; int prev=0; for (; !((level==0 && state==STATE_NORMAL && (delimiter=='\0' || source[endIndex]==delimiter))) && endIndex<source.length; ++endIndex) { int c=source[endIndex]; if (state==STATE_NORMAL) { if (c=='}') --level; else if (c=='{') ++level; else if (c=='/' && prev=='/') { state=STATE_SLASHC; c=0; } else if (c=='*' && prev=='/') { state=STATE_STARC; c=0; } else if (c=='\'' && prev!='\\') { state=STATE_CHAR; c=0; } else if (c=='\"' && prev!='\\') { state=STATE_STRING; c=0; } } else if (state==STATE_SLASHC) { if (c=='\n') state=STATE_NORMAL; } else if (state==STATE_CHAR) { if (c=='\'' && prev!='\\') state=STATE_NORMAL; else if (c=='\\' && prev=='\\') c=0; } else if (state==STATE_STRING) { if (c=='\"' && prev!='\\') state=STATE_NORMAL; else if (c=='\\' && prev=='\\') c=0; } else { if (c=='/' && prev=='*') { state=STATE_NORMAL; c=0; } } prev=c; } if (level>0) throw new ParseException("Unexpected end of source."); else { String rc=new String(source, orgEndIndex, endIndex-orgEndIndex); return endIndex; } } private boolean addComments = false; public boolean getAddComments() { return this.addComments; } public static final String WHITESPACE=" \t\r\n "; public static final boolean isWhitespace(char c) { return (c == ' ' || c == '\t' || c == '\n' || c == '\r' || c == ' '); //return WHITESPACE.indexOf(c)>=0; } private int currentLine; static char[] loadFile(final File file, String encoding) throws IOException { InputStream in = new FileInputStream(file); NotifyingInputStreamReader notifyingInput = new NotifyingInputStreamReader(in, encoding); notifyingInput.addMalformedInputListener(new MalformedInputListener() { public void malformedInputEncountered(MalformedInputEvent event) { Main.getRootDoc().printWarning("Illegal character in file " + file + ", line " + event.getLineNumber() + ", column " + event.getColumnNumber()); try { Main.getRootDoc().printWarning(IOToolkit.getLineFromFile(file, event.getLineNumber())); Main.getRootDoc().printWarning(IOToolkit.getColumnDisplayLine(event.getColumnNumber())); } catch (IOException ignore) { } } }); Reader reader = new BufferedReader(notifyingInput); char[] result = IOToolkit.readFully(reader); reader.close(); return result; } private SourceComponent[] sourceLevelComponents; private SourceComponent[] classLevelComponents; public SourceComponent[] getClassLevelComponents() { return this.classLevelComponents; } public Parser() { try { sourceLevelComponents=new SourceComponent[] { new Whitespace(), new CommentComponent(), new SlashSlashCommentComponent(), new PackageComponent(), new EmptyStatementComponent(), new ImportComponent(), new ClassComponent(), }; classLevelComponents=new SourceComponent[] { new Whitespace(), new BracketClose(), new CommentComponent(), new SlashSlashCommentComponent(), new FunctionComponent(), new StaticBlockComponent(), new ImportComponent(), new ClassComponent(), new FieldComponent(), }; } catch (Exception e) { e.printStackTrace(); } } public int getNumberOfProcessedFiles() { return processedFiles.size(); } static Set processedFiles = new HashSet(); ClassDocImpl processSourceFile(File file, boolean addComments, String encoding, String expectedPackageName) throws IOException, ParseException { //System.err.println("Processing " + file + "..."); this.currentFile = file; this.currentPackage = null; this.currentPackageName = null; this.expectedPackageName = expectedPackageName; this.outerClass = null; this.boilerplateComment = null; this.addComments=addComments; if (processedFiles.contains(file)) { return null; } processedFiles.add(file); Debug.log(1,"Processing file "+file); contextStack.clear(); ctx=null; importedClassesList.clear(); importedStringList.clear(); importedPackagesList.clear(); importedStatementList.clear(); currentLine = 1; char[] source = loadFile(file, encoding); try { parse(source, 0, sourceLevelComponents); ClassDoc[] importedClasses=(ClassDoc[])importedClassesList.toArray(new ClassDoc[0]); PackageDoc[] importedPackages=(PackageDoc[])importedPackagesList.toArray(new PackageDoc[0]); if (Main.DESCEND_IMPORTED) { for (int i=0; i<importedClasses.length; ++i) { Main.getRootDoc().scheduleClass(currentClass, importedClasses[i].qualifiedName()); } } if (contextStack.size()>0) { Debug.log(1,"-->contextStack not empty! size is "+contextStack.size()); } return outerClass; } catch (IgnoredFileParseException ignore) { Debug.log(1, "File ignored: " + ignore); return null; } } int parse(char[] source, int index, SourceComponent[] componentTypes) throws ParseException, IOException { while (index<source.length) { int match=-1; int i=0; for (; i<componentTypes.length; ++i) { if ((match=componentTypes[i].match(source, index))>=0) { //Debug.log(1,componentTypes[i].getClass().getName()+" ("+match+"/"+source.length+")"); break; } } if (i<componentTypes.length) { int endIndex=componentTypes[i].getEndIndex(source, match); Debug.log(9, "Processing " + new String(source,index,endIndex-index) + " with " + componentTypes[i]); index=componentTypes[i].process(this, source, index, endIndex); if (index<0) { //Debug.log(9,"exiting parse because of "+componentTypes[i].getClass().getName()+" (\""+new String(source, index, endIndex-index)+"\")"); return endIndex; } } else { //Debug.log(9,"index="+index+", source.length()="+source.length); throw new ParseException("unmatched input in line "+currentLine+": "+new String(source, index, Math.min(50,source.length-index))); } } //Debug.log(9,"exiting parse normally, index="+index+" source.length="+source.length); return index; } private static int countNewLines(String source) { int i=0; int rc=0; while ((i=source.indexOf('\n',i)+1)>0) ++rc; return rc; } public void processSourceDir(File dir, String encoding, String expectedPackageName) throws IOException, ParseException { Debug.log(9,"Processing "+dir.getParentFile().getName()+"."+dir.getName()); File[] files=dir.listFiles(); if (null!=files) { for (int i=0; i<files.length; ++i) { if (files[i].getName().toLowerCase().endsWith(".java")) { processSourceFile(files[i], true, encoding, expectedPackageName); } } } } void classOpened(char[] source, int startIndex, int endIndex) throws ParseException, IOException { referencedClassesList.clear(); if (null == currentPackage) { if (expectedPackageName != null) { if (null == currentPackageName || !currentPackageName.equals(expectedPackageName)) { Main.getRootDoc().printWarning("Ignoring file " + currentFile + ": (wrong package, " + currentPackageName + "!=" + expectedPackageName + ")"); throw new IgnoredFileParseException(); } } if (null != currentPackageName) { currentPackage = Main.getRootDoc().findOrCreatePackageDoc(currentPackageName); } else { currentPackage = Main.getRootDoc().findOrCreatePackageDoc(""); } } if (currentPackageName != null) importedStatementList.add(currentPackageName + ".*"); importedStatementList.add("java.lang.*"); ClassDocImpl classDoc = ClassDocImpl.createInstance((ctx!=null)?(ctx.classDoc):null, currentPackage, null, (PackageDoc[])importedPackagesList.toArray(new PackageDoc[0]), source, startIndex, endIndex, importedStatementList); if (ctx != null) { ctx.innerClassesList.add(classDoc); if (classDoc.isIncluded()) { ctx.filteredInnerClassesList.add(classDoc); } } if (importedClassesList.isEmpty()) { for (Iterator it=importedStringList.iterator(); it.hasNext(); ) { importedClassesList.add(new ClassDocProxy((String)it.next(), classDoc)); } } classDoc.setImportedClasses((ClassDoc[])importedClassesList.toArray(new ClassDoc[0])); currentPackage.addClass(classDoc); currentClass = classDoc; if (null == outerClass) { outerClass = classDoc; } if (classDoc.superclass()!=null) referencedClassesList.add(classDoc.superclass()); Debug.log(1,"classOpened "+classDoc+", adding superclass "+classDoc.superclass()); Debug.log(1,"Pushing " + ctx); contextStack.push(ctx); ctx=new Context(classDoc); //Debug.log(9,"ctx="+ctx); } private Doc[] toArray(List list, Doc[] template) { Doc[] result = (Doc[])list.toArray(template); return result; } void classClosed() throws ParseException, IOException { ctx.classDoc.setFields((FieldDoc[])toArray(ctx.fieldList, new FieldDoc[0])); ctx.classDoc.setFilteredFields((FieldDoc[])toArray(ctx.filteredFieldList, new FieldDoc[0])); ctx.classDoc.setSerializableFields((FieldDoc[])toArray(ctx.sfieldList, new FieldDoc[0])); ctx.classDoc.setMethods((MethodDoc[])toArray(ctx.methodList, new MethodDoc[0])); ctx.classDoc.setFilteredMethods((MethodDoc[])toArray(ctx.filteredMethodList, new MethodDoc[0])); ctx.classDoc.setMaybeSerMethodList(ctx.maybeSerMethodList); ctx.classDoc.setConstructors((ConstructorDoc[])toArray(ctx.constructorList, new ConstructorDoc[0])); ctx.classDoc.setFilteredConstructors((ConstructorDoc[])toArray(ctx.filteredConstructorList, new ConstructorDoc[0])); ctx.classDoc.setInnerClasses((ClassDocImpl[])toArray(ctx.innerClassesList, new ClassDocImpl[0])); ctx.classDoc.setFilteredInnerClasses((ClassDocImpl[])toArray(ctx.filteredInnerClassesList, new ClassDocImpl[0])); ctx.classDoc.setBoilerplateComment(boilerplateComment); Main.getRootDoc().addClassDoc(ctx.classDoc); if (Main.DESCEND_INTERFACES) { for (int i=0; i<ctx.classDoc.interfaces().length; ++i) { Main.getRootDoc().scheduleClass(ctx.classDoc, ctx.classDoc.interfaces()[i].qualifiedName()); } } Debug.log(1,"classClosed: "+ctx.classDoc); ctx=(Context)contextStack.pop(); Debug.log(1, "Popping " + ctx); ClassDoc[] referencedClasses=(ClassDoc[])referencedClassesList.toArray(new ClassDoc[0]); if (Main.DESCEND_SUPERCLASS) { for (int i=0; i<referencedClasses.length; ++i) { Main.getRootDoc().scheduleClass(currentClass, referencedClasses[i].qualifiedName()); } } } Context ctx = null; Stack contextStack = new Stack(); class Context { Context(ClassDocImpl classDoc) { this.classDoc=classDoc; } ClassDocImpl classDoc = null; List fieldList = new LinkedList(); List filteredFieldList = new LinkedList(); List sfieldList = new LinkedList(); List methodList = new LinkedList(); List filteredMethodList = new LinkedList(); List maybeSerMethodList = new LinkedList(); List constructorList = new LinkedList(); List filteredConstructorList = new LinkedList(); List innerClassesList = new LinkedList(); List filteredInnerClassesList = new LinkedList(); } File currentFile = null; String lastComment = null; String expectedPackageName = null; String currentPackageName = null; PackageDocImpl currentPackage = null; ClassDocImpl currentClass = null; ClassDocImpl outerClass = null; List ordinaryClassesList = new LinkedList(); List allClassesList = new LinkedList(); List interfacesList = new LinkedList(); List importedClassesList = new LinkedList(); List importedStringList = new LinkedList(); List importedPackagesList = new LinkedList(); List importedStatementList = new LinkedList(); List referencedClassesList = new LinkedList(); String boilerplateComment = null; void packageOpened(String packageName) { currentPackageName = packageName; } void importEncountered(String importString) throws ParseException, IOException { //Debug.log(9,"importing '"+importString+"'"); importedStatementList.add(importString); if (importString.endsWith(".*")) { importedPackagesList.add(Main.getRootDoc().findOrCreatePackageDoc(importString.substring(0,importString.length()-2))); } else { importedStringList.add(importString); } } void setLastComment(String lastComment) { this.lastComment=lastComment; } String getLastComment() { return this.lastComment; } void setBoilerplateComment(String boilerplateComment) { this.boilerplateComment = boilerplateComment; } String getBoilerplateComment() { return boilerplateComment; } }