package x10doc.doc;
import java.util.ArrayList;
import java.util.List;
import polyglot.types.LocalDef;
import polyglot.types.Ref;
import x10.types.ParameterType;
import x10.types.X10MethodDef;
import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.ParamTag;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.Tag;
import com.sun.javadoc.ThrowsTag;
import com.sun.javadoc.Type;
import com.sun.javadoc.TypeVariable;
public class X10MethodDoc extends X10Doc implements MethodDoc {
private X10MethodDef methodDef;
private X10ClassDoc containingClass;
private X10TypeVariable[] typeParams;
private X10RootDoc rootDoc;
private Type returnType;
private ArrayList<X10Parameter> parameters;
private boolean included;
public X10MethodDoc() {
super.processComment("");
}
public X10MethodDoc(X10MethodDef methodDef, X10ClassDoc containingClass, String comment) {
//super(comment);
this.methodDef = methodDef;
this.containingClass = containingClass;
this.rootDoc = X10RootDoc.getRootDoc();
// the following lines simply retrieve the formal parameter types from
// methodDef, to ensure that methodDef.signature() does not contain <unknown> in place
// of formal parameter types; this is a hack, and ideally there should be no need to do it;
// X10ClassDoc.addMethod(...) uses X10MethodDef.signature() as the key against which X10MethodDoc
// objects are mapped
// List<Ref<? extends polyglot.types.Type>> ls = methodDef.formalTypes();
// for (Ref<? extends polyglot.types.Type> ref: ls) {
// polyglot.types.Type formalType = ref.get();
// }
// type parameters should be initialized before return types and parameter types
// because the latter may use the former; further, getType requires access to this
// X10MethodDoc object to find the type parameters, hence the need to add this object to
// the containing class's ClassDoc object
initTypeParameters();
// containingClass.addMethod(this);
// initialize returnType
returnType = rootDoc.getType(methodDef.returnType().get(), typeParams);
// initialize parameters
List<LocalDef> formals = methodDef.formalNames();
int n = ((formals == null) ? 0 : formals.size());
parameters = new ArrayList<X10Parameter>(n);
for (LocalDef ld: formals) {
String paramName = ld.name().toString();
polyglot.types.Type paramType = ld.type().get();
parameters.add(new X10Parameter(paramName, rootDoc.getType(paramType, typeParams)));
}
// X10Doc.isIncluded(..., this) valid only if this.{isPublic(),...,isPrivate()} are valid, which requires
// this.methodDef to have been set appropriately
this.included = X10Doc.isIncluded(rootDoc.accessModFilter(), this);
super.processComment(comment);
}
void initTypeParameters() {
List<ParameterType> params = methodDef.typeParameters();
typeParams = new X10TypeVariable[params.size()];
int i = 0;
for (ParameterType p: params) {
X10TypeVariable v = new X10TypeVariable(p, this);
typeParams[i++] = v;
// typeParams.put(typeParameterKey(p), v);
}
}
// public X10MethodDef getMethodDef() {
// return methodDef;
// }
public static String typeParameterKey(ParameterType p) {
return p.name().toString();
}
public X10Tag[] getX10Tags() {
List<X10Tag> list = new ArrayList<X10Tag>();
addGuardTags(list);
return list.toArray(new X10Tag[list.size()]);
}
public void addDeclTag(String declString) {
if (declString == null) {
return;
}
X10Tag[] declTags = createInlineTags(declString, this).toArray(new X10Tag[0]);
X10Tag[] tags = getX10Tags();
// place declaration before the first sentence of the existing comment so that
// the declaration is displayed in the "Methods Summary" table before the first sentence
firstSentenceTags = concat(declTags, firstSentenceTags);
inlineTags = concat(concat(declTags, tags), inlineTags);
}
public String declString() {
// the X10 method declaration needs to be displayed in the method's comments only if a param type
// or return type is X10-specific (has associated closures, constraints) or the method has contraints
if (!(X10Type.isX10Specific(returnType)) && methodDef.guard() == null) {
boolean hasConstraints = false;
for (X10Parameter p: parameters) {
if (p.isX10Specific()) {
hasConstraints = true;
break;
}
}
if (!hasConstraints) {
return "";
}
}
// code to generate compact constraints; at present, simply prints to console
String desc = this.name() + "(";
boolean first = true;
for (X10Parameter p: parameters) {
if (first) {
first = false;
}
else {
desc += ", ";
}
desc += p.name() + ": " + p.typeName();
if (p.isX10Specific()) {
desc += X10Type.descriptor(p.type());
}
}
desc += ") " + methodDef.guard() + ": " + methodDef.returnType();
if (X10Type.isX10Specific(returnType)) {
desc += X10Type.descriptor(returnType);
}
// System.out.println("X10MethodDoc{" + methodDef.signature() + "}.declString(): descriptor = " + desc);
String guard = (methodDef.guard() == null) ? "" : methodDef.guard().toString();
// construct result from X10 compiler method signatures and toString functions
String result = "<B>Declaration:</B> <TT>" + methodDef.signature() + guard + ": " +
methodDef.returnType().toString() + ".</TT><PRE>\n</PRE>";
// earlier: ... + X10Doc.toString(this.returnType)
return result;
}
public boolean isAbstract() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isAbstract() called.");
return methodDef.flags().isAbstract();
}
@Override
public boolean isIncluded() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isIncluded() called.");
return this.included;
}
@Override
public boolean isMethod() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isMethod() called.");
return true;
}
@Override
public String name() {
if (X10RootDoc.printSwitch)
System.out.println(methodDef.name() + ".name() called.");
return methodDef.name().toString();
}
public ClassDoc overriddenClass() {
// TODO Auto-generated method stub
System.out.println(name() + ".overriddenClass() called.");
return null;
}
public MethodDoc overriddenMethod() {
// TODO Auto-generated method stub
// System.out.println(name() + ".overriddenMethod() called.");
return null;
}
public Type overriddenType() {
// TODO Auto-generated method stub
System.out.println(name() + ".overriddenType() called.");
return null;
}
public boolean overrides(MethodDoc arg0) {
// TODO Auto-generated method stub
// System.out.println(name() + ".overrides(" + arg0.name() + ") called.");
return false;
}
public Type returnType() {
return returnType;
// System.out.print(name() + ".returnType() called. ");
// if (retType == null) return null;
// if (retType.isPrimitive()) {
// System.out.println("Primitive X10Type returned.");
// return new X10Type(retType);
// }
// if (retType.isClass()) {
// System.out.println("X10ClassDoc returned.");
//
// X10ClassDef classDef = (X10ClassDef) retType.toClass().def();
// return createRecClassDoc(classDef);
// }
// System.out.println("null returned.");
// return null;
}
public String flatSignature() {
return signature();
}
public boolean isNative() {
System.out.println(name() + ".isNative() called.");
return methodDef.flags().isNative();
}
public boolean isSynchronized() {
System.out.println(name() + ".isSynchronized() called.");
return false;
}
public boolean isVarArgs() {
// System.out.println(name() + ".isVarArgs() called.");
return false; // no var. args. methods in current implementation of X10
}
public ParamTag[] paramTags() {
// TODO Auto-generated method stub
// System.out.println(name() + ".paramTags() called.");
return paramTags.toArray(new ParamTag[0]);
}
public Parameter[] parameters() {
// System.out.println(name() + ".parameters() called.");
return parameters.toArray(new Parameter[0]);
}
public String signature() {
// System.out.println(name() + ".signature() called. result = " + signature(methodDef));
return signature(methodDef);
// String sig = methodDef.signature();
// return sig.substring(sig.indexOf('('));
}
public static String signature(X10MethodDef md) {
String sig = md.signature();
sig = sig.replaceAll("[^(:,]+:", "");
sig = sig.replaceAll("\\{[^}]+\\}", "");
return sig.substring(sig.indexOf('('));
}
public Type[] thrownExceptionTypes() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".thrownExceptionTypes() called.");
return thrownExceptions();
}
public ClassDoc[] thrownExceptions() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".thrownExceptions() called.");
// TODO: look at the @Throws annotation when we have one
// List<Ref<? extends polyglot.types.Type>> throwTypes = methodDef.throwTypes();
// if(throwTypes != null && throwTypes.size() > 0)
// {
// ClassDoc[] types = new ClassDoc[throwTypes.size()];
// int i = 0;
// for(Ref<? extends polyglot.types.Type> type : throwTypes)
// {
// types[i++] = (ClassDoc)rootDoc.getType(type.get());
// }
//
// return types;
// }
return new ClassDoc[0];
}
public ThrowsTag[] throwsTags() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".throwsTags() called.");
Tag[] tags = tags(X10Tag.THROWS);
ThrowsTag[] newTags = new ThrowsTag[tags.length];
System.arraycopy(tags, 0, newTags, 0, tags.length);
return newTags;
}
public ParamTag[] typeParamTags() {
// TODO Auto-generated method stub
if (X10RootDoc.printSwitch)
System.out.println(name() + ".typeParamTags() called.");
return new ParamTag[0];
}
public TypeVariable[] typeParameters() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".typeParameters() called.");
// return typeParams.values().toArray(new TypeVariable[0]);
return typeParams;
}
public TypeVariable getTypeVariable(ParameterType p) {
// return typeParams.get(typeParameterKey(p));
return null;
}
public boolean isSynthetic() {
// TODO Auto-generated method stub
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isSynthetic() called.");
return false;
}
public AnnotationDesc[] annotations() {
// TODO Auto-generated method stub
if (X10RootDoc.printSwitch)
System.out.println(name() + ".annotations() called.");
return new AnnotationDesc[0];
}
public ClassDoc containingClass() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".containingClass() called.");
return containingClass;
}
public PackageDoc containingPackage() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".containingPackage() called.");
return containingClass.containingPackage();
}
public boolean isFinal() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isFinal() called.");
return methodDef.flags().isFinal();
}
public boolean isPackagePrivate() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isPackagePrivate() called.");
return methodDef.flags().isPackage();
}
public boolean isPrivate() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isPrivate() called.");
return methodDef.flags().isPrivate();
}
public boolean isProtected() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isProtected() called.");
return methodDef.flags().isProtected();
}
public boolean isPublic() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isPublic() called.");
return methodDef.flags().isPublic();
}
public boolean isStatic() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".isStatic() called.");
return methodDef.flags().isStatic();
}
public int modifierSpecifier() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".modifierSpecifier() called.");
// int r = 0;
// for (Object flag : methodDef.flags().flags()) {
// // flag could be "property" which is not in flagsToHex (and not recognized by
// // the standard doclet)
// if (flagsToHex.containsKey((String)flag)) {
// r |= flagsToHex.get((String)flag);
// }
// }
// return r;
return X10Doc.flagsToModifierSpecifier(methodDef.flags().flags());
}
public String modifiers() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".modifiers() called.");
return methodDef.flags().toString();
}
public String qualifiedName() {
if (X10RootDoc.printSwitch)
System.out.println(name() + ".qualifiedName() called.");
return methodDef.name().toString();
}
}