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