/* gnu.classpath.tools.gjdoc.ExecutableMemberDocImpl Copyright (C) 2001 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.util.*; import java.io.*; import com.sun.javadoc.*; public class ExecutableMemberDocImpl extends MemberDocImpl implements ExecutableMemberDoc { protected ExecutableMemberDocImpl(ClassDoc containingClass, PackageDoc containingPackage, SourcePosition position) { super(containingClass, containingPackage, position); } protected boolean processModifier(String word) { if (super.processModifier(word)) { return true; } else if (word.equals("synchronized")) { isSynchronized=true; return true; } else if (word.equals("native")) { isNative=true; return true; } else if (word.equals("abstract")) { isAbstract=true; return true; } else { return false; } } private boolean isAbstract=false; private boolean isNative=false; private boolean isSynchronized=false; public boolean isAbstract() { return isAbstract; } public boolean isNative() { return isNative; } public boolean isSynchronized() { return isSynchronized; } public ClassDoc[] thrownExceptions() { return thrownExceptions; } public Parameter[] parameters() { return parameters; } public ThrowsTag[] throwsTags() { return (ThrowsTag[])getTagArr("throws", throwsTagEmptyArr); } public ParamTag[] paramTags() { return (ParamTag[])getTagArr("param", paramTagEmptyArr); } public String signature() { return signature; } public String flatSignature() { return flatSignature; } public ClassDoc overriddenClass() { for (ClassDoc cdi=(ClassDoc)containingClass().superclass(); cdi!=null; cdi=(ClassDoc)cdi.superclass()) { if (null!=ClassDocImpl.findMethod(cdi, name(), signature())) return cdi; } return null; } public static ExecutableMemberDocImpl createFromSource(ClassDoc containingClass, PackageDoc containingPackage, char[] source, int startIndex, int endIndex) throws IOException, ParseException { int lastchar=32; StringBuffer methodName=new StringBuffer(); for (int i=startIndex; i<endIndex && source[i]!='('; ++i) { if ((Parser.WHITESPACE.indexOf(lastchar)>=0 && Parser.WHITESPACE.indexOf(source[i])<0) || (lastchar == ']' && Parser.WHITESPACE.indexOf(source[i])<0 && '[' != source[i])) { methodName.setLength(0); methodName.append(source[i]); } else if (Parser.WHITESPACE.indexOf(source[i])<0) { methodName.append(source[i]); } lastchar=source[i]; } ExecutableMemberDocImpl rc; SourcePosition position = DocImpl.getPosition(containingClass, source, startIndex); if (methodName.toString().equals(((ClassDocImpl)containingClass).getClassName())) { // Constructor rc=new ConstructorDocImpl(containingClass, containingPackage, position); } else { // Normal method rc=new MethodDocImpl(containingClass, containingPackage, position); } if (containingClass.isInterface()) rc.accessLevel=ACCESS_PUBLIC; int ndx=rc.parseModifiers(source, startIndex, endIndex); StringBuffer name = new StringBuffer(); final int STATE_NORMAL=1; final int STATE_STARC=2; final int STATE_SLASHC=3; int state=STATE_NORMAL; while (source[ndx]!='(' && ndx<endIndex) { if (state==STATE_NORMAL) { if (ndx<endIndex-1 && source[ndx]=='/' && source[ndx+1]=='/') { ++ndx; state=STATE_SLASHC; } else if (ndx<endIndex-1 && source[ndx]=='/' && source[ndx+1]=='*') { ++ndx; state=STATE_STARC; } else { name.append(source[ndx]); } } else if (state==STATE_SLASHC) { if (source[ndx]=='\n') state=STATE_NORMAL; } else if (state==STATE_STARC) { if (ndx<endIndex-1 && source[ndx]=='*' && source[ndx+1]=='/') { ++ndx; state=STATE_NORMAL; } } ++ndx; } rc.setName(name.toString().trim()); state=STATE_NORMAL; ++ndx; int endx; String param=""; List parameterList=new ArrayList(); for (endx=ndx; endx<endIndex; ++endx) { if (state==STATE_SLASHC) { if (source[endx]=='\n') { state=STATE_NORMAL; } } else if (state==STATE_STARC) { if (source[endx]=='*' && source[endx+1]=='/') { state=STATE_NORMAL; ++endx; } } else if (source[endx]=='/' && source[endx+1]=='*') { state=STATE_STARC; ++endx; } else if (source[endx]=='/' && source[endx+1]=='/') { state=STATE_SLASHC; ++endx; } else if (source[endx]==',' || source[endx]==')') { param=param.trim(); if (param.length()>0) { int n = param.length()-1; int paramNameStart = 0; while (n >= 0) { char c = param.charAt(n); if ('[' == c || ']' == c || Parser.WHITESPACE.indexOf(c)>=0) { paramNameStart = n + 1; break; } else { -- n; } } while (n >= 0 && ('[' == param.charAt(n) || ']' == param.charAt(n) || Parser.WHITESPACE.indexOf(param.charAt(n))>=0)) { -- n; } int paramTypeEnd = n + 1; int paramTypeStart = 0; while (n >= 0) { char c = param.charAt(n); if ('[' == c || ']' == c || Parser.WHITESPACE.indexOf(c)>=0) { paramTypeStart = n + 1; break; } else { -- n; } } String paramType; String paramName; if (0 != paramNameStart) { paramType=param.substring(paramTypeStart, paramTypeEnd); paramName=param.substring(paramNameStart); } else { paramName = ""; StringBuffer paramTypeBuffer = new StringBuffer(); for (int i=0; i<param.length(); ++i) { char c = param.charAt(i); if ('[' != c && ']' != c && Parser.WHITESPACE.indexOf(c)<0) { paramTypeBuffer.append(c); } } paramType = paramTypeBuffer.toString(); } String dimSuffix=""; for (int i=0; i<param.length(); ++i) { if ('[' == param.charAt(i)) { dimSuffix += "[]"; } } paramType+=dimSuffix; if (paramType.startsWith("[")) { System.err.println("broken param type in " + rc + " in " +containingClass); } parameterList.add(new ParameterImpl(paramName, paramType, ((ClassDocImpl)containingClass).typeForString(paramType))); param=""; } } else param+=source[endx]; if (source[endx]==')' && state==STATE_NORMAL) break; } rc.setParameters((Parameter[])parameterList.toArray(new Parameter[0])); ++endx; String word=""; String dimSuffix=""; boolean haveThrowsKeyword=false; List thrownExceptionsList=new ArrayList(); state=STATE_NORMAL; for (; endx<endIndex; ++endx) { if (state==STATE_SLASHC) { if (source[endx]=='\n') state=STATE_NORMAL; } else if (state==STATE_STARC) { if (source[endx]=='*' && source[endx+1]=='/') { state=STATE_NORMAL; ++endx; } } else if (source[endx]=='/' && source[endx+1]=='*') { state=STATE_STARC; ++endx; } else if (source[endx]=='/' && source[endx+1]=='/') { state=STATE_SLASHC; ++endx; } else if (Parser.WHITESPACE.indexOf(source[endx])>=0) { word=word.trim(); if (!haveThrowsKeyword && word.length()>0) { if (word.equals("throws")) haveThrowsKeyword=true; else System.err.println("ARGH! "+word); word=""; } } else if (source[endx]=='[' || source[endx]==']') { dimSuffix += source[endx]; } else if (source[endx]==',' || source[endx]=='{' || source[endx]==';') { word=word.trim(); if (word.length()>0) { ClassDoc exceptionType=rc.containingClass().findClass(word); if (exceptionType==null) { exceptionType=new ClassDocProxy(word, rc.containingClass()); } thrownExceptionsList.add(exceptionType); } if (source[endx]=='{') { break; } else { word=""; } } else { word+=source[endx]; } } if (dimSuffix.length()>0) { rc.setTypeName(rc.getTypeName()+dimSuffix); } rc.setThrownExceptions((ClassDoc[])thrownExceptionsList.toArray(new ClassDoc[0])); return rc; } private ClassDoc[] thrownExceptions; private Parameter[] parameters; private String signature; private String flatSignature; void setParameters(Parameter[] parameters) { this.parameters=parameters; } void setThrownExceptions(ClassDoc[] thrownExceptions) { this.thrownExceptions=thrownExceptions; } void resolve() { for (int i=0; i<thrownExceptions.length; ++i) { if (thrownExceptions[i] instanceof ClassDocProxy) { String className=thrownExceptions[i].qualifiedName(); ClassDoc realClassDoc=containingClass().findClass(className); if (realClassDoc!=null) thrownExceptions[i]=realClassDoc; } } StringBuffer signatureBuf=new StringBuffer(); StringBuffer flatSignatureBuf=new StringBuffer(); for (int i=0; i<parameters.length; ++i) { ((ParameterImpl)parameters[i]).resolve(containingClass()); if (signatureBuf.length()>0) { signatureBuf.append(","); flatSignatureBuf.append(","); } signatureBuf.append(parameters[i].type().qualifiedTypeName()); flatSignatureBuf.append(parameters[i].type().typeName()); signatureBuf.append(parameters[i].type().dimension()); flatSignatureBuf.append(parameters[i].type().dimension()); } this.signature="("+signatureBuf.toString()+")"; this.flatSignature="("+flatSignatureBuf.toString()+")"; super.resolve(); } public int compareTo(Object other) { int rc; if (other instanceof MemberDocImpl) { MemberDocImpl otherMember = (MemberDocImpl)other; rc = name().compareTo(otherMember.name()); if (0 == rc) { if (other instanceof ExecutableMemberDocImpl) { rc = signature().compareTo(((ExecutableMemberDocImpl)other).signature()); if (0 == rc) { return containingClass().compareTo(otherMember.containingClass()); } } else { rc = 1; } } } else { rc = 1; } return rc; } }