KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > javacore > parser > ClassFileInfoUtil


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.javacore.parser;
20
21 import java.io.FileNotFoundException JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.net.URL JavaDoc;
25 import java.util.*;
26 import java.util.regex.Matcher JavaDoc;
27 import java.util.regex.Pattern JavaDoc;
28 import org.netbeans.api.java.classpath.ClassPath;
29 import org.netbeans.api.java.queries.JavadocForBinaryQuery;
30 import org.netbeans.api.java.queries.JavadocForBinaryQuery.Result;
31 import org.netbeans.modules.classfile.*;
32 import org.netbeans.modules.javacore.JMManager;
33 import org.netbeans.modules.javacore.jmiimpl.javamodel.FeatureImpl;
34 import org.openide.ErrorManager;
35 import org.openide.filesystems.FileObject;
36 import org.openide.filesystems.FileStateInvalidException;
37 import org.openide.filesystems.URLMapper;
38 import org.openide.util.Utilities;
39
40 public final class ClassFileInfoUtil {
41     private static final String JavaDoc NAME_CLASS_INIT = "<clinit>"; // NOI18N
42
private static final String JavaDoc NAME_INIT = "<init>"; // NOI18N
43

44     /**
45      * Only for debugging reasons, used for sumarize time consumption for
46      * getting parameters from javadoc.
47      */

48     private static long javadocTT = 0;
49     private static long lastPrinted = 0;
50     
51     public ClassInfo createClassInfo(FileObject folder, String JavaDoc partName, int mods) {
52         FileObject file = null;
53         try {
54             file = folder.getFileObject(partName.replace('.', '$'), "class"); // NOI18N
55
} catch (Exception JavaDoc e) {
56         }
57         if (file == null) {
58             return null;
59         }
60         return createClassInfo (folder, file, mods);
61     }
62     
63     public ClassInfo createClassInfo(FileObject folder, FileObject file, int mods) {
64         ClassFile clsFile;
65         
66         try {
67             InputStream JavaDoc is=file.getInputStream();
68             try {
69                 clsFile = new ClassFile(is, true);
70             } finally {
71                 is.close();
72             }
73         } catch (Exception JavaDoc ex) {
74             throw new RuntimeException JavaDoc("Inconsistent storage: class file for " + file.getNameExt() + " not created", ex); // NOI18N
75
}
76         
77         String JavaDoc name = clsFile.getName().getExternalName();
78         if (mods < 0) {
79             mods = (clsFile.getAccess() & ~Access.SYNCHRONIZED) | (clsFile.isDeprecated() ? FeatureImpl.DEPRECATED : 0);
80         }
81         boolean isInterface = (mods & Access.INTERFACE) > 0;
82         String JavaDoc typeSignature = clsFile.getTypeSignature();
83         boolean isGeneric = typeSignature != null;
84         TypeParamInfo[] tpi = null;
85         NameRef[] interfaces;
86         NameRef superName;
87
88         if (isGeneric) {
89             char[] sigChars = typeSignature.toCharArray();
90             int[] pos = new int[] {0};
91             tpi = parseTypeParams(sigChars, pos);
92             superName = (NameRef)sigToTypeRef(sigChars, pos);
93             ArrayList list = new ArrayList(6);
94             while (pos[0] < sigChars.length) {
95                 list.add(sigToTypeRef(sigChars, pos));
96             }
97             interfaces = new NameRef[list.size()];
98             list.toArray(interfaces);
99         } else {
100             ClassName className = clsFile.getSuperClass();
101             superName = null;
102             if (className != null) {
103                 superName = new NameRef(className.getExternalName(), null, null);
104             }
105
106             Collection coll = clsFile.getInterfaces();
107             int size = coll.size();
108             interfaces = new NameRef[size];
109             Iterator iter = coll.iterator();
110             for (int x = 0; iter.hasNext(); x++) {
111                 interfaces[x] = new NameRef(((ClassName) iter.next()).getExternalName(), null, null);
112             }
113         }
114         
115         boolean isAnnotation = clsFile.isAnnotation();
116         int methodCount = clsFile.getMethodCount();
117         int fieldCount = clsFile.getVariableCount();
118         Collection innerClasses = clsFile.getInnerClasses();
119         ClassName clsName = clsFile.getName();
120         List featuresList = new ArrayList (innerClasses.size() + methodCount + fieldCount);
121         for (Iterator it = innerClasses.iterator(); it.hasNext();) {
122             InnerClass innerClass = (InnerClass) it.next();
123             ClassName outerName = innerClass.getOuterClassName();
124             if (clsName.equals(outerName)) {
125                 String JavaDoc fn = innerClass.getName().getSimpleName();
126                 
127                 int index = fn.lastIndexOf ('.') + 1;
128                 if ((index > 0) && (fn.length() > index) && Character.isDigit(fn.charAt (index))) {
129                     continue;
130                 }
131         
132                 fn = fn.replace('.', '$');
133                 FileObject fo = folder.getFileObject(fn, "class"); // NOI18N
134
if (fo != null) {
135                     featuresList.add(createClassInfo(folder, fo, -1));
136                 }
137             }
138         }
139
140         Iterator iter = clsFile.getMethods().iterator();
141         for (int x = 0; x < methodCount; x++) {
142             Method method = (Method) iter.next();
143             if (!method.isSynthetic()) {
144                 if (isAnnotation) {
145                     featuresList.add(createAttributeInfo(method));
146                 } else {
147                     featuresList.add(createMethodInfo(name, method, file));
148                 }
149             }
150         }
151         List enumConstants = new ArrayList();
152         iter = clsFile.getVariables().iterator();
153         for (int x = 0 ; x < fieldCount; x++) {
154             Variable variable = (Variable) iter.next();
155             if (!variable.isSynthetic()) {
156                 if (variable.isEnumConstant()) {
157                     enumConstants.add(variable);
158                 } else {
159                     featuresList.add(createFieldInfo (variable));
160                 }
161             }
162         }
163         FeatureInfo[] features = new FeatureInfo[featuresList.size()];
164         featuresList.toArray(features);
165         AnnotationInfo[] annos = createAnnotations(clsFile.getAnnotations());
166         
167         if (clsFile.isEnum()) {
168             ElementInfo[] constants = new ElementInfo[enumConstants.size()];
169             Iterator it = enumConstants.iterator();
170             for (int x = 0; it.hasNext(); x++) {
171                 Variable c = (Variable)it.next();
172                 constants[x] = new FeatureInfo(null, FeatureInfo.ENUM_CONSTANT_TYPE, (String JavaDoc)c.getName(), 0, null);
173             }
174             return new EnumInfo(
175                 null, EnumInfo.ENUM_TYPE, name, mods, features, interfaces, constants, annos
176             );
177         } else if (isAnnotation) {
178             return new AnnotationTypeInfo(null, AnnotationTypeInfo.ANNOTATIONTYPE_TYPE, name, mods,
179                 features, annos
180             );
181         } else {
182             return new ClassInfo(null,
183                 isInterface ? ClassInfo.INTERFACE_TYPE : ClassInfo.CLASS_TYPE,
184                 name, mods, features, superName, interfaces, tpi, annos
185             );
186         }
187     }
188     
189     public FeatureInfo createMethodInfo (String JavaDoc className, Method method, FileObject file) {
190         String JavaDoc name = method.getName();
191         int mods = method.getAccess() | (method.isDeprecated() ? FeatureImpl.DEPRECATED : 0);
192         AnnotationInfo[] annos = createAnnotations(method.getAnnotations());
193         if (NAME_CLASS_INIT.equals(name)) {
194             int infoType = (mods & Access.STATIC) > 0 ? FeatureInfo.STATIC_INITIALIZER_TYPE :
195                 FeatureInfo.INSTANCE_INITIALIZER_TYPE;
196             return new FeatureInfo (null, infoType, name, mods, annos);
197         }
198         
199         char[] sig = method.getDescriptor().toCharArray();
200         String JavaDoc typeSignature = method.getTypeSignature();
201         char[] typeSig = typeSignature == null ? null : typeSignature.toCharArray();
202         int[] pos = new int[] {1};
203         ParameterInfo[] params;
204         TypeParamInfo[] tpi = null;
205
206         if (typeSignature == null) {
207             params = createParamsInfo(method, sig, pos, file);
208         } else {
209             pos[0] = 0;
210             tpi = parseTypeParams(typeSig, pos);
211             List list = getParamTypes(typeSig, pos);
212             Iterator paramsIter = method.getParameters().iterator();
213             Iterator iter = list.iterator();
214             params = new ParameterInfo[list.size()];
215             for (int x = 0; iter.hasNext(); x++) {
216                 TypeRef type = (TypeRef)iter.next();
217                 boolean isVarArgs = !iter.hasNext() && method.isVarArgs();
218                 Parameter par = paramsIter.hasNext() ? (Parameter)paramsIter.next() : null;
219                 String JavaDoc paramName;
220                 AnnotationInfo[] anns;
221                 if (par == null) {
222                     paramName = "";
223                     anns = null;
224                 } else {
225                     paramName = par.getName();
226                     anns = createAnnotations(par.getAnnotations());
227                 }
228                 params[x] = new ParameterInfo (null, ParameterInfo.PARAMETER_TYPE, paramName, false, type, isVarArgs, anns);
229             }
230         }
231         
232         TypeRef type;
233         int infoType;
234         if (NAME_INIT.equals(name)) {
235             infoType = MethodInfo.CONSTRUCTOR_TYPE;
236             type = new NameRef(className, null, null);
237             if (typeSignature == null) {
238                 sigToTypeRef(sig, pos);
239             } else {
240                 pos[0]++;
241                 sigToTypeRef(typeSig, pos);
242             }
243         } else {
244             infoType = MethodInfo.METHOD_TYPE;
245             if (typeSignature == null) {
246                 type = sigToTypeRef(sig, pos);
247             } else {
248                 pos[0]++;
249                 type = sigToTypeRef(typeSig, pos);
250             }
251         }
252         TypeParamRef[] excNames = new TypeParamRef[0];
253         CPClassInfo[] exceptions = method.getExceptionClasses();
254         if (exceptions.length > 0) {
255             if (typeSignature != null) {
256                 ArrayList list = new ArrayList();
257                 while (pos[0] < typeSig.length) {
258                     if (typeSig[pos[0]] == '^')
259                         pos[0]++;
260                     list.add(sigToTypeRef(typeSig, pos));
261                 }
262                 excNames = (TypeParamRef[]) list.toArray(excNames);
263             }
264             if (excNames.length == 0) {
265                 excNames = new TypeParamRef[exceptions.length];
266                 for (int x = 0; x < exceptions.length; x++) {
267                     excNames[x] = new NameRef(exceptions[x].getClassName().getExternalName(), null, null);
268                 }
269             }
270         }
271         return new MethodInfo (null, infoType, name, mods, type, params, excNames, tpi, annos);
272     }
273
274     public static FieldInfo createFieldInfo(Variable field) {
275         int mods = field.getAccess() | (field.isDeprecated() ? FeatureImpl.DEPRECATED : 0);
276         String JavaDoc name = field.getName();
277         AnnotationInfo[] annos = createAnnotations(field.getAnnotations());
278         String JavaDoc typeSignature = field.getTypeSignature();
279         char[] signature = typeSignature != null ? typeSignature.toCharArray() : field.getDescriptor().toCharArray();
280         int[] pos = new int[] {0};
281         TypeRef type = sigToTypeRef(signature, pos);
282         return new FieldInfo (null, FieldInfo.FIELD_TYPE, name, mods, type, FieldInfo.SINGLE_FIELD_INDEX, annos);
283     }
284     
285     public static AttributeInfo createAttributeInfo(Method method) {
286         int mods = method.getAccess() | (method.isDeprecated() ? FeatureImpl.DEPRECATED : 0);
287         String JavaDoc name = method.getName();
288         AnnotationInfo[] annos = createAnnotations(method.getAnnotations());
289         String JavaDoc desc = method.getDescriptor();
290         int index = desc.indexOf(')');
291         TypeRef type = sigToTypeRef(desc.substring(index + 1).toCharArray(), new int[] {0});
292         ElementValue defValue = method.getAnnotationDefault();
293         AnnotationValueInfo defaultValueInfo = defValue == null ? null : new AnnotationValueInfo(
294             null, getElementValueType(defValue), name, resolveElementValue(defValue)
295         );
296         return new AttributeInfo(null, AttributeInfo.ATTRIBUTE_TYPE, name, mods, type, defaultValueInfo, annos);
297     }
298     
299     public static AnnotationInfo[] createAnnotations(Collection annos) {
300         if (annos == null || annos.size() == 0) {
301             return ElementInfo.EMPTY_ANNOTATIONS;
302         }
303         AnnotationInfo[] result = new AnnotationInfo[annos.size()];
304         Iterator iter = annos.iterator();
305         for (int x = 0; iter.hasNext(); x++) {
306             result[x] = annotationToInfo((Annotation)iter.next());
307         }
308         return result;
309     }
310     
311     public static AnnotationInfo annotationToInfo(Annotation anno) {
312         NameRef name=new NameRef(anno.getType().getExternalName(), null, null);
313         AnnotationComponent[] comps = anno.getComponents();
314         AnnotationValueInfo[] values = new AnnotationValueInfo[comps.length];
315         for (int x = 0; x < comps.length; x++) {
316             values[x] = annotationComponentToInfo(comps[x]);
317         }
318         return new AnnotationInfo(null, AnnotationInfo.ANNOTATION_TYPE, name, values);
319     }
320     
321     public static AnnotationValueInfo annotationComponentToInfo(AnnotationComponent comp) {
322         int infoType = getElementValueType(comp.getValue());
323         return new AnnotationValueInfo(null, infoType, comp.getName(), resolveElementValue(comp.getValue()));
324     }
325     
326     public static int getElementValueType(ElementValue elemValue) {
327         int infoType;
328         if (elemValue instanceof ArrayElementValue) {
329             infoType = AnnotationValueInfo.ANNOTATIONVALUE_ARRAY;
330         } else if (elemValue instanceof PrimitiveElementValue) {
331             infoType = AnnotationValueInfo.ANNOTATIONVALUE_STRING;
332         } else if (elemValue instanceof ClassElementValue) {
333             infoType = AnnotationValueInfo.ANNOTATIONVALUE_STRING;
334         } else if (elemValue instanceof EnumElementValue) {
335             infoType = AnnotationValueInfo.ANNOTATIONVALUE_STRING; // [PENDING]
336
} else { // NestedElementValue
337
infoType = AnnotationValueInfo.ANNOTATIONVALUE_ANNOTATION;
338         }
339         return infoType;
340     }
341     
342     public static Object JavaDoc resolveElementValue(ElementValue elem) {
343         if (elem instanceof ArrayElementValue) {
344             ElementValue[] arrayValues = ((ArrayElementValue)elem).getValues();
345             Object JavaDoc[] value = new Object JavaDoc[arrayValues.length];
346             for (int x = 0; x < arrayValues.length; x++) {
347                 value[x] = resolveElementValue(arrayValues[x]);
348             }
349             return value;
350         }
351         if (elem instanceof PrimitiveElementValue) {
352             return ((PrimitiveElementValue)elem).getValue().getValue().toString();
353         }
354         if (elem instanceof ClassElementValue) {
355             return ((ClassElementValue)elem).getClassName().getExternalName();
356         }
357         if (elem instanceof EnumElementValue) {
358             return ((EnumElementValue)elem).getEnumName(); // [PENDING]
359
}
360         return annotationToInfo(((NestedElementValue)elem).getNestedValue());
361     }
362         
363     public static NameRef sigToNameRef(char[] signature, int[] i, NameRef parent) {
364         StringBuffer JavaDoc name = new StringBuffer JavaDoc();
365         for (; signature[i[0]] != ';' && signature[i[0]] != '<'; i[0]++) {
366             char ch = signature[i[0]];
367             if (ch=='/' || ch=='$') {
368                 ch='.';
369             }
370             if (name.length() > 0 || ch != '.')
371                 name.append(ch);
372         }
373         
374         if (signature[i[0]] == ';')
375             return new NameRef(name.toString(), parent, null);
376         
377         i[0]++;
378         ArrayList typeParams = new ArrayList(5);
379         while(signature[i[0]] != '>') {
380             char ch = signature[i[0]];
381             if (ch == '*') {
382                 typeParams.add(new WildCardRef(false, null));
383                 i[0]++;
384             } else if (ch == '+' || ch == '-') {
385                 i[0]++;
386                 TypeRef tr = sigToTypeRef(signature, i);
387                 typeParams.add(new WildCardRef(ch == '-', tr));
388             } else {
389                 typeParams.add(sigToTypeRef(signature, i));
390             }
391         }
392         i[0]++;
393         TypeRef[] typeRefs = new TypeRef[typeParams.size()];
394         typeParams.toArray(typeRefs);
395         return new NameRef(name.toString(), parent, typeRefs);
396     }
397     
398     public static TypeRef sigToTypeRef(char[] signature, int[] i) {
399         char c = (char) signature[i[0]];
400         switch (c) {
401             case 'B':
402                 i[0]++;
403                 return PrimitiveTypeRef.BYTE;
404             case 'C':
405                 i[0]++;
406                 return PrimitiveTypeRef.CHAR;
407             case 'D':
408                 i[0]++;
409                 return PrimitiveTypeRef.DOUBLE;
410             case 'F':
411                 i[0]++;
412                 return PrimitiveTypeRef.FLOAT;
413             case 'I':
414                 i[0]++;
415                 return PrimitiveTypeRef.INT;
416             case 'J':
417                 i[0]++;
418                 return PrimitiveTypeRef.LONG;
419             case 'T':
420                 i[0]++;
421                 int pos;
422                 StringBuffer JavaDoc buf = new StringBuffer JavaDoc(40);
423                 for (pos = i[0]; (pos < signature.length) && (signature[pos] != ';'); pos++) {
424                     char ch = signature[pos];
425                     if (ch=='/' || ch=='$') ch='.';
426                     buf.append(ch);
427                 }
428                 i[0] = pos + 1;
429                 return new TypeParamRef(buf.toString());
430             case 'L':
431                 i[0]++;
432                 NameRef nameRef = null;
433                 while (signature[i[0]] != ';') {
434                     nameRef = sigToNameRef(signature, i, nameRef);
435                 }
436                 i[0]++;
437                 return nameRef;
438             case 'S':
439                 i[0]++;
440                 return PrimitiveTypeRef.SHORT;
441             case 'V':
442                 i[0]++;
443                 return PrimitiveTypeRef.VOID;
444             case 'Z':
445                 i[0]++;
446                 return PrimitiveTypeRef.BOOLEAN;
447             case '[':
448                 int dimCount = 0;
449                 while (signature[i[0]] == '[') {
450                     dimCount++;
451                     i[0]++;
452                 }
453                 return new ArrayRef((PrimitiveTypeRef)sigToTypeRef(signature, i), dimCount);
454             case ')':
455                 i[0]++;
456                 return null;
457             default:
458                 throw new IllegalArgumentException JavaDoc("Unknown signature: " + new String JavaDoc(signature) + ' ' + i[0]); // NOI18N
459
}
460     }
461     
462     public static TypeParamInfo[] parseTypeParams(char[] sig, int[] i) {
463         Iterator iter;
464         List infos = new ArrayList();
465         if (sig[0] == '<') {
466             i[0] = 1;
467             while (sig[i[0]] != '>') {
468                 // identifier
469
StringBuffer JavaDoc id = new StringBuffer JavaDoc();
470                 while (sig[i[0]] != ':') {
471                     id.append(sig[i[0]]);
472                     i[0]++;
473                 } // while
474
if (sig[i[0] + 1] == ':') {
475                     i[0]++;
476                 }
477                 ArrayList bounds = new ArrayList();
478                 while (sig[i[0]] == ':') {
479                     i[0]++;
480                     bounds.add(sigToTypeRef(sig, i));
481                 } // while
482
TypeParamRef[] bds = new TypeParamRef[bounds.size()];
483                 iter = bounds.iterator();
484                 for (int x = 0; iter.hasNext(); x++) {
485                     bds[x] = (TypeParamRef) iter.next();
486                 }
487                 infos.add(new TypeParamInfo(null, TypeParamInfo.TYPEPARAM_TYPE, id.toString(), bds));
488             } // while
489
i[0]++;
490         } // if
491
TypeParamInfo[] tpi = new TypeParamInfo[infos.size()];
492         iter = infos.iterator();
493         for (int x = 0; iter.hasNext(); x++) {
494             tpi[x] = (TypeParamInfo)iter.next();
495         }
496         return tpi;
497     }
498     
499     public static List getParamTypes (char[] signature, int[] pos) {
500         List params = new ArrayList();
501         pos[0]++;
502         while (signature[pos[0]] != ')') {
503             params.add(sigToTypeRef(signature, pos));
504         }
505         return params;
506     }
507
508     public ParameterInfo[] createParamsInfo (Method method, char[] signature, int[] pos, FileObject file) {
509         List params = new ArrayList();
510         Iterator paramsIter = method.getParameters().iterator();
511         int notKnownNames = 0;
512         while (true) {
513             TypeRef parType = sigToTypeRef(signature, pos);
514             if (parType != null) {
515                 AnnotationInfo[] parameterAnnons;
516                 String JavaDoc parameterName;
517                 if (paramsIter.hasNext()) {
518                     Parameter par = (Parameter) paramsIter.next();
519                     parameterName = par.getName();
520                     parameterAnnons = createAnnotations(par.getAnnotations());
521                     // We cannot get parameter's name from classfile (it is
522
// probably interface or abstract class, which does not have
523
// parameter's name in compiled form even if it is compiled
524
// with debug information. We will try to get it from
525
// javadoc later.
526
if (parameterName.length() == 0) {
527                         notKnownNames++;
528                     }
529                 }
530                 else {
531                     parameterName = "";
532                     parameterAnnons = null;
533                 }
534                 ParameterInfo info = new ParameterInfo (null, ParameterInfo.PARAMETER_TYPE,
535                     parameterName, false, parType, false, parameterAnnons);
536                 params.add(info);
537             }
538             else
539                 break;
540         }
541         ParameterInfo[] parInfos = (ParameterInfo[]) params.toArray(new ParameterInfo[params.size()]);
542         if (method.isVarArgs()) {
543             // [PENDING]
544
parInfos[parInfos.length - 1] = new ParameterInfo(
545                 null, ParameterInfo.PARAMETER_TYPE, parInfos[parInfos.length - 1].name,
546                 false, parInfos[parInfos.length - 1].type, true, parInfos[parInfos.length - 1].annotations
547             );
548         }
549         if (notKnownNames > 0) {
550             if (!getNamesFromJavaDoc(method, parInfos, file)) {
551                 computeArtificalNames(parInfos);
552             }
553         }
554         return parInfos;
555     }
556
557     private boolean getNamesFromJavaDoc(final Method method, final ParameterInfo[] parInfos, final FileObject file) {
558         long startT = 0;
559         if (JMManager.PERF_DEBUG) {
560             startT = System.currentTimeMillis();
561         }
562         try {
563             // Skip rt.jar file as we have src.zip on classpath, which
564
// is enough for obtaining parameters' names.
565
// todo #pf: should be probably beter to name all filesystem
566
// which shouldn't be used for reading parameter names from
567
// javadoc
568
if (file.getFileSystem().getDisplayName().endsWith("rt.jar")) { // NOI18N
569
if (JMManager.PERF_DEBUG) {
570                     javadocTT += (System.currentTimeMillis() - startT);
571                     if ((javadocTT / 100) > lastPrinted) {
572                         System.err.println("DEBUG: createParamsInfo()#javadoc-names " + javadocTT + " ms.");
573                         lastPrinted++;
574                     }
575                 }
576                 return false;
577             }
578         } catch (FileStateInvalidException e) {
579             // we do not care about it
580
ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, e.getMessage());
581             return false;
582         }
583         if (signature2parnames == null) {
584             // fill the data for the class
585
signature2parnames = fillParametersMap(file);
586         }
587         if (signature2parnames != null) {
588             String JavaDoc patternStr = getSignatureKey(method.getName(), parInfos);
589             String JavaDoc[] names = (String JavaDoc[]) signature2parnames.get(patternStr);
590             if (names != null) {
591                 for (int i = 0; i < parInfos.length && i < names.length; i++) {
592                     parInfos[i] = new ParameterInfo(
593                         null,
594                         ParameterInfo.PARAMETER_TYPE,
595                         // this constructor is being called in order to trim the
596
// baggage, it will make a copy of string
597
new String JavaDoc(names[i]),
598                         parInfos[i].isFinal,
599                         parInfos[i].type,
600                         parInfos[i].isVarArg,
601                         parInfos[i].annotations
602                     );
603                 }
604             }
605             if (JMManager.PERF_DEBUG) {
606                 long deltaT = System.currentTimeMillis() - startT;
607                 javadocTT += deltaT;
608                 System.err.println("PERF: createParamsInfo()#javadoc-names '" + method.getName() + "' took " + deltaT + " ms.");
609                 if ((javadocTT / 100) > lastPrinted) {
610                     System.err.println("PERF: createParamsInfo()#javadoc-names " + javadocTT + " ms.");
611                     lastPrinted++;
612                 }
613             }
614             return true;
615         }
616         return false;
617     }
618
619     private void computeArtificalNames(ParameterInfo[] parInfos) {
620         Map names=new HashMap();
621         final Integer JavaDoc zero=new Integer JavaDoc(0);
622         int i;
623         
624         for (i=0;i<parInfos.length;i++) {
625             TypeRef pType=parInfos[i].type;
626             String JavaDoc name;
627             Integer JavaDoc count;
628             
629             if (pType==null) {
630                 pType=NameRef.java_lang_Object;
631             }
632             name=getName(pType);
633             count=(Integer JavaDoc)names.get(name);
634             if (count!=null) {
635                 names.put(name,new Integer JavaDoc(count.intValue()+1));
636                 name=name.concat(count.toString());
637             } else {
638                 names.put(name,zero);
639             }
640             parInfos[i] = new ParameterInfo(
641                 null,
642                 ParameterInfo.PARAMETER_TYPE,
643                 name,
644                 parInfos[i].isFinal,
645                 parInfos[i].type,
646                 parInfos[i].isVarArg,
647                 parInfos[i].annotations
648             );
649         }
650     }
651
652     private static String JavaDoc getName(final TypeRef pType) {
653         if (pType instanceof ArrayRef) {
654             return getName(((ArrayRef)pType).parent);
655         } else if (pType instanceof TypeParamRef) {
656             int index;
657             String JavaDoc name=pType.getName();
658             
659             index=name.lastIndexOf('.');
660             if (index!=-1) {
661                 name=name.substring(index+1);
662             }
663             String JavaDoc loweredName = name.substring(0,1).toLowerCase().concat(name.substring(1));
664             return Utilities.isJavaIdentifier(loweredName) ? loweredName : 'a' + name;
665         } else if (pType instanceof PrimitiveTypeRef) {
666             return pType.getName().substring(0,1);
667         } else if (pType instanceof WildCardRef) { // just in case
668
return getName(((WildCardRef)pType).bound);
669         } else {
670             throw new IllegalArgumentException JavaDoc("Uknow type "+pType.getClass());
671         }
672     }
673
674     /**
675      * Creates signature string for locating method header in map containing
676      * signature as a key and array of parameters' names. (i.e. result
677      * represents key in <tt>signature2parnames</tt> map.)
678      *
679      * @param methodName method name which is looked for
680      * @param parInfo array of parameters of the method
681      * @return string representation of signature
682      */

683     private static String JavaDoc getSignatureKey(String JavaDoc methodName, ParameterInfo[] parInfo) {
684         StringBuffer JavaDoc result = new StringBuffer JavaDoc(); // NOI18N
685
result.append(methodName).append("("); // NOI18N
686
for (int i = 0; i < parInfo.length; i++) {
687             String JavaDoc typeName = parInfo[i].type.getName();
688             result.append(typeName);
689             if ((i+1) < parInfo.length) {
690                 result.append(", "); // NOI18N
691
} else {
692                 result.append(")"); // NOI18N
693
}
694         }
695         return result.toString();
696     }
697     
698     /**
699      * Method signatures in string representation are used as keys. For
700      * every key, array of ordered parameters' names are in value.
701      * Example of item:
702      * Key: <tt>gluTessBeginPolygon(javax.media.opengl.glu.GLUtessellator, java.lang.Object)</tt>
703      * Value: <tt>String[tessellator,data]</tt>
704      *
705      * This data are used when parameters' names are not available in class
706      * or source files.
707      */

708     private Map/*<String, String[]>*/ signature2parnames = null;
709     
710     /**
711      * Simple pattern for finding methods in javadoc.
712      */

713     private static Pattern JavaDoc pattern = Pattern.compile("\\<A NAME\\=\"([^\\)\"]+\\))"); // NOI18N
714

715     /**
716      * Searches for parameters' names in defined section. It starts from
717      * <tt>offset</tt>, going through the <tt>htmlContent</tt> lines till
718      * </pre> tag found.
719      *
720      * @param offset position in string where to start
721      * @param htmlContent content of html file
722      * @return array of parameters' names (ordered)
723      */

724     private static String JavaDoc[] obtainNames(int offset, String JavaDoc htmlContent) {
725         // get section for the method
726
int startOffset = htmlContent.indexOf("<PRE>", offset) + 5;
727         if (startOffset < 5) {
728             return new String JavaDoc[0];
729         }
730         int endOffset = htmlContent.indexOf(")", startOffset) + 1;
731         if (endOffset <= 0) {
732             return new String JavaDoc[0];
733         }
734         String JavaDoc preSection = htmlContent.substring(startOffset, endOffset);
735         startOffset = 0;
736         endOffset = preSection.length()-1;
737         startOffset = preSection.indexOf("&nbsp;", 0); // NOI18N
738
List/*<String>*/ names = new ArrayList(3);
739         int mark = startOffset;
740         while (startOffset != -1 && startOffset < endOffset) {
741             mark = startOffset + 6;
742             startOffset = preSection.indexOf(",", mark); // NOI18N
743
if (startOffset == -1 || startOffset >= endOffset)
744                 startOffset = endOffset; // NOI18N
745
names.add(preSection.substring(mark, startOffset));
746             startOffset = preSection.indexOf("&nbsp;", startOffset); // NOI18N
747
}
748         return (String JavaDoc[]) names.toArray(new String JavaDoc[0]);
749     }
750     
751     /**
752      * Fetch the entire contents of a text file, and return it in a
753      * <tt>String</tt>
754      *
755      * @param aFile is a file which already exists and can be read.
756      * @exception IOException file cannot be read
757      * @exception FileNotFoundException file is not available
758      */

759     static public String JavaDoc getContents(FileObject aFile)
760         throws FileNotFoundException JavaDoc, IOException JavaDoc
761     {
762         int size = (int) aFile.getSize();
763         byte[] b = new byte[size];
764         InputStream JavaDoc is = null;
765         try {
766             is = aFile.getInputStream();
767             is.read(b);
768         } finally {
769             try {
770                 if (is != null) {
771                     is.close();
772                 }
773             } catch (IOException JavaDoc ex) {
774                 // ignore, too bad
775
}
776         }
777         return new String JavaDoc(b);
778     }
779     
780     /**
781      * Looks for the javadoc file related to provided file. Consider that
782      * you read file named 'jar:file:/tmp/library.jar!/foo/Foo.class'. Then
783      * method will try to locate file foo/Foo.html in related javadoc entry. If
784      * the entry does not exist or file does not exist in the entry, it returns
785      * null value. Otherwise it returns found html file.
786      *
787      * @param file look for related html file for this parameter
788      * @return html file object, null if javadoc is not available for parameter
789     */

790     private static FileObject getJavadocFile(FileObject file) {
791         ClassPath cp = ClassPath.getClassPath(file, ClassPath.EXECUTE);
792         if (cp == null) {
793             // We does not have execute classpath for provided parameter,
794
// we will not try to find javadoc file for it.
795
return null;
796         }
797         Result res;
798         try {
799             FileObject cpRoot = cp.findOwnerRoot(file);
800             if (cpRoot == null) return null;
801             res = JavadocForBinaryQuery.findJavadoc(cpRoot.getURL());
802         } catch (FileStateInvalidException e) {
803             // we don't care about it, consider html file was not found.
804
ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, e.getMessage());
805             return null;
806         }
807         URL JavaDoc[] url = res.getRoots();
808         if (url.length > 0) {
809             for (int i = 0; i < url.length; i++) {
810                 FileObject rootDoc = URLMapper.findFileObject(url[i]);
811                 if (rootDoc != null) {
812                     // we finally found javadoc root, we will try to find related
813
// html file in it.
814
String JavaDoc html = cp.getResourceName(file);
815                     html = html.substring(0, html.length()-5).replace('$', '.') + "html"; // NOI18N
816
return rootDoc.getFileObject(html);
817                 }
818             }
819         }
820         // unfortunately there is not related html file for the class file.
821
return null;
822     }
823     
824     /**
825      * Fills the mapping for class file. It uses string representation
826      * of signature as a key and list of strings as a parameters names.
827      * (ordered) If the *.class file does not have related html file
828      * in libary definition, return empty map. Otherwise, it fills
829      * the map with data.
830      *
831      * @param file file representing the *.class file
832      * @return map of methods -> parameters names, null if there is no javadoc file
833      */

834     public static Map fillParametersMap(FileObject file) {
835         long startT = 0;
836         if (JMManager.PERF_DEBUG) {
837             startT = System.currentTimeMillis();
838         }
839         Map/*<String, String[]>*/ pars = null;
840         try {
841             FileObject htmlFile = getJavadocFile(file);
842             if (htmlFile == null)
843                 return null;
844             pars = new HashMap();
845             String JavaDoc htmlContent = getContents(htmlFile);
846             for (Matcher JavaDoc m = pattern.matcher(htmlContent); m.find(); ) {
847                 int start = m.start(1);
848                 int end = m.end(1);
849                 String JavaDoc[] names = obtainNames(start, htmlContent);
850                 pars.put(htmlContent.substring(start, end), names);
851             }
852         } catch (FileNotFoundException JavaDoc ex) {
853             return null;
854         } catch (IOException JavaDoc ex) {
855             return null;
856         }
857         if (JMManager.PERF_DEBUG) {
858             long deltaT = System.currentTimeMillis() - startT;
859             System.err.println("Map for file '" + file.getName() + "' was filled in " + deltaT + " ms.");
860         }
861         return pars;
862     }
863 }
Popular Tags