blob: f16777d5470da911e1a37ce7840be762bcdf046f [file] [log] [blame]
/*
* Copyright 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.doctool;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.Doc;
import com.sun.javadoc.MemberDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.SourcePosition;
import com.sun.javadoc.Tag;
/**
* Methods related to resolving cross-references in source.
*/
public class LinkResolver {
/**
* Abstracts out mechanisms for finding different bits of doc.
*/
public interface ExtraClassResolver {
ClassDoc findClass(String className);
}
public static SourcePosition resolveLink(Tag tag) {
return resolveLink(tag, null);
}
public static SourcePosition resolveLink(Tag tag,
ExtraClassResolver classResolver) {
String linkText = tag.text();
String className;
String methodSig;
int pos = linkText.indexOf('#');
if (pos >= 0) {
className = linkText.substring(0, pos);
methodSig = linkText.substring(pos + 1);
} else {
className = linkText;
methodSig = null;
}
ClassDoc containingClass = null;
Doc holder = tag.holder();
if (holder instanceof ClassDoc) {
containingClass = (ClassDoc) holder;
} else if (holder instanceof MemberDoc) {
containingClass = ((MemberDoc) holder).containingClass();
}
ClassDoc targetClass = null;
if (className.length() == 0) {
targetClass = containingClass;
} else if (holder instanceof PackageDoc) {
targetClass = ((PackageDoc) holder).findClass(className);
} else {
targetClass = containingClass.findClass(className);
}
if (targetClass == null) {
if (classResolver != null) {
targetClass = classResolver.findClass(className);
}
if (targetClass == null) {
System.err.println(tag.position().toString()
+ ": unable to resolve class " + className + " for " + tag);
System.exit(1);
}
}
if (methodSig == null) {
return targetClass.position();
}
String paramSig = methodSig.substring(methodSig.indexOf('(') + 1,
methodSig.lastIndexOf(')'));
String[] resolvedParamTypes;
if (paramSig.length() > 0) {
String[] unresolvedParamTypes = paramSig.split("\\s*,\\s*");
resolvedParamTypes = new String[unresolvedParamTypes.length];
for (int i = 0; i < unresolvedParamTypes.length; ++i) {
ClassDoc paramType = containingClass.findClass(unresolvedParamTypes[i]);
if (paramType == null && classResolver != null) {
paramType = classResolver.findClass(unresolvedParamTypes[i]);
}
if (paramType == null) {
System.err.println(tag.position().toString()
+ ": unable to resolve class " + unresolvedParamTypes[i]
+ " for " + tag);
System.exit(1);
}
resolvedParamTypes[i] = paramType.qualifiedTypeName();
}
} else {
resolvedParamTypes = new String[0];
}
String possibleOverloads = "";
MethodDoc[] methods = targetClass.methods();
outer : for (int i = 0; i < methods.length; ++i) {
MethodDoc methodDoc = methods[i];
if (methodSig.startsWith(methodDoc.name())) {
possibleOverloads += "\n" + methodDoc.flatSignature();
Parameter[] tryParams = methodDoc.parameters();
if (resolvedParamTypes.length != tryParams.length) {
// param count mismatch
continue outer;
}
for (int j = 0; j < tryParams.length; ++j) {
if (!tryParams[j].type().qualifiedTypeName().equals(
resolvedParamTypes[j])) {
// param type mismatch
continue outer;
}
}
return methodDoc.position();
}
}
System.err.println(tag.position().toString()
+ ": unable to resolve method for " + tag);
if (possibleOverloads.length() > 0) {
System.err.println("Possible overloads: " + possibleOverloads);
}
System.exit(1);
return null;
}
}