| /* |
| * 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; |
| } |
| |
| } |