KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > google > gwt > dev > jdt > TypeOracleBuilder


1 /*
2  * Copyright 2007 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */

16 package com.google.gwt.dev.jdt;
17
18 import com.google.gwt.core.ext.TreeLogger;
19 import com.google.gwt.core.ext.UnableToCompleteException;
20 import com.google.gwt.core.ext.typeinfo.CompilationUnitProvider;
21 import com.google.gwt.core.ext.typeinfo.HasMetaData;
22 import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
23 import com.google.gwt.core.ext.typeinfo.JClassType;
24 import com.google.gwt.core.ext.typeinfo.JConstructor;
25 import com.google.gwt.core.ext.typeinfo.JField;
26 import com.google.gwt.core.ext.typeinfo.JMethod;
27 import com.google.gwt.core.ext.typeinfo.JPackage;
28 import com.google.gwt.core.ext.typeinfo.JParameter;
29 import com.google.gwt.core.ext.typeinfo.JPrimitiveType;
30 import com.google.gwt.core.ext.typeinfo.JType;
31 import com.google.gwt.core.ext.typeinfo.TypeOracle;
32 import com.google.gwt.dev.util.Empty;
33 import com.google.gwt.dev.util.Util;
34
35 import org.eclipse.jdt.core.compiler.CharOperation;
36 import org.eclipse.jdt.core.compiler.IProblem;
37 import org.eclipse.jdt.internal.compiler.ASTVisitor;
38 import org.eclipse.jdt.internal.compiler.CompilationResult;
39 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
40 import org.eclipse.jdt.internal.compiler.ast.Argument;
41 import org.eclipse.jdt.internal.compiler.ast.Clinit;
42 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
43 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
44 import org.eclipse.jdt.internal.compiler.ast.Initializer;
45 import org.eclipse.jdt.internal.compiler.ast.Javadoc;
46 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
47 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
48 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
49 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
50 import org.eclipse.jdt.internal.compiler.env.IGenericType;
51 import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
52 import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
53 import org.eclipse.jdt.internal.compiler.lookup.BinaryTypeBinding;
54 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
55 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
56 import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
57 import org.eclipse.jdt.internal.compiler.lookup.LocalTypeBinding;
58 import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
59 import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
60 import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
61 import org.eclipse.jdt.internal.compiler.lookup.TypeIds;
62
63 import java.io.BufferedReader JavaDoc;
64 import java.io.CharArrayReader JavaDoc;
65 import java.io.File JavaDoc;
66 import java.io.IOException JavaDoc;
67 import java.util.ArrayList JavaDoc;
68 import java.util.Arrays JavaDoc;
69 import java.util.HashMap JavaDoc;
70 import java.util.HashSet JavaDoc;
71 import java.util.Iterator JavaDoc;
72 import java.util.List JavaDoc;
73 import java.util.Map JavaDoc;
74 import java.util.Set JavaDoc;
75 import java.util.regex.Pattern JavaDoc;
76
77 /**
78  * Builds a {@link com.google.gwt.dev.typeinfo.TypeOracle} from a set of
79  * compilation units.
80  * <p>
81  * For example,
82  *
83  * <pre>
84  * TypeOracleBuilder b = new TypeOracleBuilder();
85  * b.addCompilationUnit(unit1);
86  * b.addCompilationUnit(unit2);
87  * b.addCompilationUnit(unit3);
88  * b.excludePackage(&quot;example.pkg&quot;);
89  * TypeOracle oracle = b.build(logger);
90  * JClassType[] allTypes = oracle.getTypes();
91  * </pre>
92  */

93 public class TypeOracleBuilder {
94
95   private static final Pattern JavaDoc PATTERN_WHITESPACE = Pattern.compile("\\s");
96
97   static boolean parseMetaDataTags(char[] unitSource, HasMetaData hasMetaData,
98       Javadoc javadoc) {
99
100     int start = javadoc.sourceStart;
101     int end = javadoc.sourceEnd;
102     char[] comment = CharOperation.subarray(unitSource, start, end + 1);
103     if (comment == null) {
104       comment = new char[0];
105     }
106     BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new CharArrayReader JavaDoc(comment));
107     String JavaDoc activeTag = null;
108     final List JavaDoc tagValues = new ArrayList JavaDoc();
109     try {
110       String JavaDoc line = reader.readLine();
111       boolean firstLine = true;
112       while (line != null) {
113         if (firstLine) {
114           firstLine = false;
115           int commentStart = line.indexOf("/**");
116           if (commentStart == -1) {
117             // Malformed.
118
return false;
119           }
120           line = line.substring(commentStart + 3);
121         }
122
123         String JavaDoc[] tokens = PATTERN_WHITESPACE.split(line);
124         boolean canIgnoreStar = true;
125         for (int i = 0; i < tokens.length; i++) {
126           String JavaDoc token = tokens[i];
127
128           // Check for the end.
129
//
130
if (token.endsWith("*/")) {
131             token = token.substring(0, token.length() - 2);
132           }
133
134           // Check for an ignored leading star.
135
//
136
if (canIgnoreStar && token.startsWith("*")) {
137             token = token.substring(1);
138             canIgnoreStar = false;
139           }
140
141           // Decide what to do with whatever is left.
142
//
143
if (token.length() > 0) {
144             canIgnoreStar = false;
145             if (token.startsWith("@")) {
146               // A new tag has been introduced.
147
// Subsequent tokens will attach to it.
148
// Make sure we finish the previously active tag before moving on.
149
//
150
if (activeTag != null) {
151                 finishTag(hasMetaData, activeTag, tagValues);
152               }
153               activeTag = token.substring(1);
154             } else if (activeTag != null) {
155               // Attach this item to the active tag.
156
//
157
tagValues.add(token);
158             } else {
159               // Just ignore it.
160
//
161
}
162           }
163         }
164
165         line = reader.readLine();
166       }
167     } catch (IOException JavaDoc e) {
168       return false;
169     }
170
171     // To catch the last batch of values, if any.
172
//
173
finishTag(hasMetaData, activeTag, tagValues);
174     return true;
175   }
176
177   private static void finishTag(HasMetaData hasMetaData, String JavaDoc tagName,
178       List JavaDoc tagValues) {
179     // Add the values even if the list is empty, because the presence of the
180
// tag itself might be important.
181
//
182
String JavaDoc[] values = (String JavaDoc[]) tagValues.toArray(Empty.STRINGS);
183     hasMetaData.addMetaData(tagName, values);
184     tagValues.clear();
185   }
186
187   private static void removeInfectedUnits(final TreeLogger logger,
188       final Map JavaDoc cudsByFileName) {
189
190     final Set JavaDoc pendingRemovals = new HashSet JavaDoc();
191     TypeRefVisitor trv = new TypeRefVisitor() {
192       protected void onTypeRef(SourceTypeBinding referencedType,
193           CompilationUnitDeclaration unitOfReferrer) {
194         // If the referenced type belongs to a compilation unit that is
195
// not in the list of valid units, then the unit in which it
196
// is referenced must also be removed.
197
//
198
String JavaDoc referencedFn = String.valueOf(referencedType.getFileName());
199         CompilationUnitDeclaration referencedCud = (CompilationUnitDeclaration) cudsByFileName.get(referencedFn);
200         if (referencedCud == null) {
201           // This is a referenced to a bad or non-existent unit.
202
// So, remove the referrer's unit if it hasn't been already.
203
//
204
String JavaDoc referrerFn = String.valueOf(unitOfReferrer.getFileName());
205           if (cudsByFileName.containsKey(referrerFn)
206               && !pendingRemovals.contains(referrerFn)) {
207             TreeLogger branch = logger.branch(TreeLogger.TRACE,
208                 "Cascaded removal of compilation unit '" + referrerFn + "'",
209                 null);
210             final String JavaDoc badTypeName = CharOperation.toString(referencedType.compoundName);
211             branch.branch(TreeLogger.TRACE,
212                 "Due to reference to unavailable type: " + badTypeName, null);
213             pendingRemovals.add(referrerFn);
214           }
215         }
216       }
217     };
218
219     do {
220       // Perform any pending removals.
221
//
222
for (Iterator JavaDoc iter = pendingRemovals.iterator(); iter.hasNext();) {
223         String JavaDoc fnToRemove = (String JavaDoc) iter.next();
224         Object JavaDoc removed = cudsByFileName.remove(fnToRemove);
225         assert (removed != null);
226       }
227
228       // Start fresh for this iteration.
229
//
230
pendingRemovals.clear();
231
232       // Find references to type in units that aren't valid.
233
//
234
for (Iterator JavaDoc iter = cudsByFileName.values().iterator(); iter.hasNext();) {
235         CompilationUnitDeclaration cud = (CompilationUnitDeclaration) iter.next();
236         cud.traverse(trv, cud.scope);
237       }
238     } while (!pendingRemovals.isEmpty());
239   }
240
241   private static void removeUnitsWithErrors(TreeLogger logger,
242       Map JavaDoc cudsByFileName) {
243     // Start by removing units with a known problem.
244
//
245
boolean anyRemoved = false;
246     for (Iterator JavaDoc iter = cudsByFileName.values().iterator(); iter.hasNext();) {
247       CompilationUnitDeclaration cud = (CompilationUnitDeclaration) iter.next();
248       CompilationResult result = cud.compilationResult;
249       IProblem[] errors = result.getErrors();
250       if (errors != null && errors.length > 0) {
251         anyRemoved = true;
252         iter.remove();
253
254         String JavaDoc fileName = CharOperation.charToString(cud.getFileName());
255         char[] source = cud.compilationResult.compilationUnit.getContents();
256         Util.maybeDumpSource(logger, fileName, source, null);
257         logger.log(TreeLogger.TRACE, "Removing problematic compilation unit '"
258             + fileName + "'", null);
259       }
260     }
261
262     if (anyRemoved) {
263       // Then removing anything else that won't compile as a result.
264
//
265
removeInfectedUnits(logger, cudsByFileName);
266     }
267   }
268
269   private final CacheManager cacheManager;
270
271   /**
272    * Constructs a default instance, with a default cacheManager. This is not to
273    * be used in Hosted Mode, as caching will then not work.
274    */

275   public TypeOracleBuilder() {
276     cacheManager = new CacheManager();
277   }
278
279   /**
280    * Constructs an instance from the supplied cacheManager, using the
281    * <code>TypeOracle</code> contained therein. This is to be used in Hosted
282    * Mode, so that caching will work, assuming the cacheManager has a cache
283    * directory.
284    */

285   public TypeOracleBuilder(CacheManager cacheManager) {
286     this.cacheManager = cacheManager;
287   }
288
289   /**
290    * Constructs an instance from the supplied typeOracle, with a cacheManager
291    * using the same typeOracle. This is not to be used in Hosted Mode, as
292    * caching will then not work.
293    */

294   public TypeOracleBuilder(TypeOracle typeOracle) {
295     cacheManager = new CacheManager(typeOracle);
296   }
297
298   /**
299    * Includes the specified logical compilation unit into the set of units this
300    * builder will parse and analyze. If a previous compilation unit was
301    * specified in the same location, it will be replaced if it is older.
302    */

303   public void addCompilationUnit(CompilationUnitProvider cup)
304       throws UnableToCompleteException {
305     cacheManager.addCompilationUnit(cup);
306   }
307
308   public TypeOracle build(final TreeLogger logger)
309       throws UnableToCompleteException {
310     Set JavaDoc addedCups = cacheManager.getAddedCups();
311     TypeOracle oracle = cacheManager.getTypeOracle();
312     // Make a copy that we can sort.
313
//
314
for (Iterator JavaDoc iter = addedCups.iterator(); iter.hasNext();) {
315       CompilationUnitProvider cup = (CompilationUnitProvider) iter.next();
316       String JavaDoc location = cup.getLocation();
317       if (!((location.indexOf("http://") != -1) || (location.indexOf("ftp://") != -1))) {
318         location = Util.findFileName(location);
319         if (!(new File JavaDoc(location).exists() || cup.isTransient())) {
320           iter.remove();
321           logger.log(
322               TreeLogger.TRACE,
323               "The file "
324                   + location
325                   + " was removed by the user. All types therein are now unavailable.",
326               null);
327         }
328       }
329     }
330     CompilationUnitProvider[] cups = (CompilationUnitProvider[]) Util.toArray(
331         CompilationUnitProvider.class, addedCups);
332     Arrays.sort(cups, CompilationUnitProvider.LOCATION_COMPARATOR);
333
334     // Make sure we can find the java.lang.Object compilation unit.
335
//
336
boolean foundJavaLangPackage = oracle.findPackage("java.lang") != null;
337
338     // Adapt to JDT idioms.
339
//
340
ICompilationUnit[] units = new ICompilationUnit[cups.length];
341     for (int i = 0; i < cups.length; i++) {
342       if (!foundJavaLangPackage && cups[i].getPackageName().equals("java.lang")) {
343         foundJavaLangPackage = true;
344       }
345       units[i] = cacheManager.findUnitForCup(cups[i]);
346     }
347
348     // Error if no java.lang.
349
if (!foundJavaLangPackage) {
350       Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
351       throw new UnableToCompleteException();
352     }
353     cacheManager.invalidateOnRefresh(oracle);
354     CompilationUnitDeclaration[] cuds = cacheManager.getAstCompiler().getCompilationUnitDeclarations(
355         logger, units);
356
357     // Build a list that makes it easy to remove problems.
358
//
359
final Map JavaDoc cudsByFileName = new HashMap JavaDoc();
360     for (int i = 0; i < cuds.length; i++) {
361       CompilationUnitDeclaration cud = cuds[i];
362       char[] location = cud.getFileName();
363       cudsByFileName.put(String.valueOf(location), cud);
364     }
365     cacheManager.getCudsByFileName().putAll(cudsByFileName);
366
367     // Remove bad cuds and all the other cuds that are affected.
368
//
369
removeUnitsWithErrors(logger, cudsByFileName);
370
371     // Also remove any compilation units that we've seen before.
372
//
373
for (Iterator JavaDoc iter = cudsByFileName.values().iterator(); iter.hasNext();) {
374       CompilationUnitDeclaration cud = (CompilationUnitDeclaration) iter.next();
375       // If we've seen this compilation unit before, the type oracle will
376
// tell us about it and so we don't assimilate it again.
377
//
378
ICompilationUnit unit = cud.compilationResult.compilationUnit;
379       ICompilationUnitAdapter adapter = ((ICompilationUnitAdapter) unit);
380       CompilationUnitProvider cup = adapter.getCompilationUnitProvider();
381       JClassType[] seen = oracle.getTypesInCompilationUnit(cup);
382       if (seen.length > 0) {
383         // This compilation unit has already been assimilated.
384
//
385
iter.remove();
386       }
387     }
388
389     // Perform a shallow pass to establish identity for new types.
390
//
391
final CacheManager.Mapper identityMapper = cacheManager.getIdentityMapper();
392     for (Iterator JavaDoc iter = cudsByFileName.values().iterator(); iter.hasNext();) {
393       CompilationUnitDeclaration cud = (CompilationUnitDeclaration) iter.next();
394
395       cud.traverse(new ASTVisitor() {
396         public boolean visit(TypeDeclaration typeDecl, BlockScope scope) {
397           JClassType enclosingType = identityMapper.get((SourceTypeBinding) typeDecl.binding.enclosingType());
398           processType(typeDecl, enclosingType, true);
399           return true;
400         }
401
402         public boolean visit(TypeDeclaration typeDecl, ClassScope scope) {
403           JClassType enclosingType = identityMapper.get((SourceTypeBinding) typeDecl.binding.enclosingType());
404           processType(typeDecl, enclosingType, false);
405           return true;
406         }
407
408         public boolean visit(TypeDeclaration typeDecl,
409             CompilationUnitScope scope) {
410           processType(typeDecl, null, false);
411           return true;
412         }
413       }, cud.scope);
414     }
415
416     // Perform a deep pass to resolve all types in terms of our types.
417
//
418
for (Iterator JavaDoc iter = cudsByFileName.values().iterator(); iter.hasNext();) {
419       CompilationUnitDeclaration cud = (CompilationUnitDeclaration) iter.next();
420       String JavaDoc loc = String.valueOf(cud.getFileName());
421       String JavaDoc processing = "Processing types in compilation unit: " + loc;
422       final TreeLogger cudLogger = logger.branch(TreeLogger.SPAM, processing,
423           null);
424       final char[] source = cud.compilationResult.compilationUnit.getContents();
425
426       cud.traverse(new ASTVisitor() {
427         public boolean visit(TypeDeclaration typeDecl, BlockScope scope) {
428           if (!resolveTypeDeclaration(cudLogger, source, typeDecl)) {
429             String JavaDoc name = String.valueOf(typeDecl.binding.readableName());
430             String JavaDoc msg = "Unexpectedly unable to fully resolve type " + name;
431             logger.log(TreeLogger.WARN, msg, null);
432           }
433           return true;
434         }
435
436         public boolean visit(TypeDeclaration typeDecl, ClassScope scope) {
437           if (!resolveTypeDeclaration(cudLogger, source, typeDecl)) {
438             String JavaDoc name = String.valueOf(typeDecl.binding.readableName());
439             String JavaDoc msg = "Unexpectedly unable to fully resolve type " + name;
440             logger.log(TreeLogger.WARN, msg, null);
441           }
442           return true;
443         }
444
445         public boolean visit(TypeDeclaration typeDecl,
446             CompilationUnitScope scope) {
447           if (!resolveTypeDeclaration(cudLogger, source, typeDecl)) {
448             String JavaDoc name = String.valueOf(typeDecl.binding.readableName());
449             String JavaDoc msg = "Unexpectedly unable to fully resolve type " + name;
450             logger.log(TreeLogger.WARN, msg, null);
451           }
452           return true;
453         }
454       }, cud.scope);
455     }
456     Util.invokeInaccessableMethod(TypeOracle.class, "refresh",
457         new Class JavaDoc[] {TreeLogger.class}, oracle, new Object JavaDoc[] {logger});
458     return oracle;
459   }
460
461   private CompilationUnitProvider getCup(TypeDeclaration typeDecl) {
462     ICompilationUnit icu = typeDecl.compilationResult.compilationUnit;
463     ICompilationUnitAdapter icua = (ICompilationUnitAdapter) icu;
464     return icua.getCompilationUnitProvider();
465   }
466
467   private String JavaDoc getPackage(TypeDeclaration typeDecl) {
468     final char[][] pkgParts = typeDecl.compilationResult.compilationUnit.getPackageName();
469     return String.valueOf(CharOperation.concatWith(pkgParts, '.'));
470   }
471
472   private String JavaDoc getQualifiedName(ReferenceBinding binding) {
473     return CharOperation.toString(binding.compoundName);
474   }
475
476   private String JavaDoc getSimpleName(TypeDeclaration typeDecl) {
477     return String.valueOf(typeDecl.name);
478   }
479
480   private boolean isInterface(TypeDeclaration typeDecl) {
481     if (typeDecl.kind() == IGenericType.INTERFACE_DECL) {
482       return true;
483     } else {
484       return false;
485     }
486   }
487
488   /**
489    * Maps a TypeDeclaration into a JClassType.
490    */

491   private void processType(TypeDeclaration typeDecl, JClassType enclosingType,
492       boolean isLocalType) {
493     TypeOracle oracle = cacheManager.getTypeOracle();
494
495     // Create our version of the type structure unless it already exists in the
496
// type oracle.
497
//
498
SourceTypeBinding binding = typeDecl.binding;
499     if (binding.constantPoolName() == null) {
500       /*
501        * Weird case: if JDT determines that this local class is totally
502        * uninstantiable, it won't bother allocating a local name.
503        */

504       return;
505     }
506
507     String JavaDoc qname;
508     String JavaDoc jclassName;
509     if (binding instanceof LocalTypeBinding) {
510       char[] localName = binding.constantPoolName();
511       for (int i = 0, c = localName.length; i < c; ++i) {
512         if (localName[i] == '/' || localName[i] == '$') {
513           localName[i] = '.';
514         }
515       }
516       qname = String.valueOf(localName);
517       jclassName = qname.substring(qname.lastIndexOf('.') + 1);
518     } else {
519       qname = getQualifiedName(binding);
520       jclassName = getSimpleName(typeDecl);
521     }
522     if (oracle.findType(qname) != null) {
523       // The oracle already knew about this type.
524
// Don't re-add it.
525
//
526
return;
527     }
528
529     String JavaDoc jpkgName = getPackage(typeDecl);
530     JPackage pkg = oracle.getOrCreatePackage(jpkgName);
531     final boolean jclassIsIntf = isInterface(typeDecl);
532     CompilationUnitProvider cup = getCup(typeDecl);
533
534     int declStart = typeDecl.declarationSourceStart;
535     int declEnd = typeDecl.declarationSourceEnd;
536     int bodyStart = typeDecl.bodyStart;
537     int bodyEnd = typeDecl.bodyEnd;
538
539     JClassType type = new JClassType(oracle, cup, pkg, enclosingType,
540         isLocalType, jclassName, declStart, declEnd, bodyStart, bodyEnd,
541         jclassIsIntf);
542
543     cacheManager.setTypeForBinding(binding, type);
544   }
545
546   private boolean resolveField(TreeLogger logger, char[] unitSource,
547       JClassType enclosingType, FieldDeclaration jfield) {
548
549     if (jfield instanceof Initializer) {
550       // Pretend we didn't see this.
551
//
552
return true;
553     }
554
555     String JavaDoc name = String.valueOf(jfield.name);
556     JField field = new JField(enclosingType, name);
557
558     // Get modifiers.
559
//
560
field.addModifierBits(Shared.bindingToModifierBits(jfield.binding));
561
562     // Set the field type.
563
//
564
TypeBinding jfieldType = jfield.binding.type;
565
566     JType fieldType = resolveType(logger, jfieldType);
567     if (fieldType == null) {
568       // Unresolved type.
569
//
570
return false;
571     }
572     field.setType(fieldType);
573
574     // Get tags.
575
//
576
if (jfield.javadoc != null) {
577       if (!parseMetaDataTags(unitSource, field, jfield.javadoc)) {
578         return false;
579       }
580     }
581
582     return true;
583   }
584
585   private boolean resolveFields(TreeLogger logger, char[] unitSource,
586       JClassType type, FieldDeclaration[] jfields) {
587     if (jfields != null) {
588       for (int i = 0; i < jfields.length; i++) {
589         FieldDeclaration jfield = jfields[i];
590         if (!resolveField(logger, unitSource, type, jfield)) {
591           return false;
592         }
593       }
594     }
595     return true;
596   }
597
598   private boolean resolveMethod(TreeLogger logger, char[] unitSource,
599       JClassType enclosingType, AbstractMethodDeclaration jmethod) {
600     JAbstractMethod method;
601
602     if (jmethod instanceof Clinit) {
603       // Pretend we didn't see this.
604
//
605
return true;
606     }
607
608     String JavaDoc name = null;
609     int declStart = jmethod.declarationSourceStart;
610     int declEnd = jmethod.declarationSourceEnd;
611     int bodyStart = jmethod.bodyStart;
612     int bodyEnd = jmethod.bodyEnd;
613
614     if (jmethod.isConstructor()) {
615       name = String.valueOf(enclosingType.getSimpleSourceName());
616       method = new JConstructor(enclosingType, name, declStart, declEnd,
617           bodyStart, bodyEnd);
618     } else {
619       name = String.valueOf(jmethod.binding.selector);
620       method = new JMethod(enclosingType, name, declStart, declEnd, bodyStart,
621           bodyEnd);
622
623       // Set the return type.
624
//
625
TypeBinding jreturnType = ((MethodDeclaration) jmethod).returnType.resolvedType;
626       JType returnType = resolveType(logger, jreturnType);
627       if (returnType == null) {
628         // Unresolved type.
629
//
630
return false;
631       }
632       ((JMethod) method).setReturnType(returnType);
633     }
634
635     // Parse modifiers.
636
//
637
method.addModifierBits(Shared.bindingToModifierBits(jmethod.binding));
638     if (enclosingType.isInterface() != null) {
639       // Always add implicit modifiers on interface methods.
640
//
641
method.addModifierBits(Shared.MOD_PUBLIC | Shared.MOD_ABSTRACT);
642     }
643
644     // Add the parameters.
645
//
646
Argument[] jparams = jmethod.arguments;
647     if (!resolveParameters(logger, method, jparams)) {
648       return false;
649     }
650
651     // Add throws.
652
//
653
TypeReference[] jthrows = jmethod.thrownExceptions;
654     if (!resolveThrownTypes(logger, method, jthrows)) {
655       return false;
656     }
657
658     // Get tags.
659
//
660
if (jmethod.javadoc != null) {
661       if (!parseMetaDataTags(unitSource, method, jmethod.javadoc)) {
662         return false;
663       }
664     }
665
666     return true;
667   }
668
669   private boolean resolveMethods(TreeLogger logger, char[] unitSource,
670       JClassType type, AbstractMethodDeclaration[] jmethods) {
671     if (jmethods != null) {
672       for (int i = 0; i < jmethods.length; i++) {
673         AbstractMethodDeclaration jmethod = jmethods[i];
674         if (!resolveMethod(logger, unitSource, type, jmethod)) {
675           return false;
676         }
677       }
678     }
679     return true;
680   }
681
682   private boolean resolveParameter(TreeLogger logger, JAbstractMethod method,
683       Argument jparam) {
684     TypeBinding jtype = jparam.binding.type;
685     JType type = resolveType(logger, jtype);
686     if (type == null) {
687       // Unresolved.
688
//
689
return false;
690     }
691
692     String JavaDoc name = String.valueOf(jparam.name);
693     new JParameter(method, type, name);
694     return true;
695   }
696
697   private boolean resolveParameters(TreeLogger logger, JAbstractMethod method,
698       Argument[] jparams) {
699     if (jparams != null) {
700       for (int i = 0; i < jparams.length; i++) {
701         Argument jparam = jparams[i];
702         if (!resolveParameter(logger, method, jparam)) {
703           return false;
704         }
705       }
706     }
707     return true;
708   }
709
710   private boolean resolveThrownType(TreeLogger logger, JAbstractMethod method,
711       TypeReference jthrown) {
712
713     JType type = resolveType(logger, jthrown.resolvedType);
714     if (type == null) {
715       // Not resolved.
716
//
717
return false;
718     }
719
720     method.addThrows(type);
721
722     return true;
723   }
724
725   private boolean resolveThrownTypes(TreeLogger logger, JAbstractMethod method,
726       TypeReference[] jthrows) {
727     if (jthrows != null) {
728       for (int i = 0; i < jthrows.length; i++) {
729         TypeReference jthrown = jthrows[i];
730         if (!resolveThrownType(logger, method, jthrown)) {
731           return false;
732         }
733       }
734     }
735     return true;
736   }
737
738   private JType resolveType(TreeLogger logger, TypeBinding binding) {
739     TypeOracle oracle = cacheManager.getTypeOracle();
740     // Check for primitives.
741
//
742
if (binding instanceof BaseTypeBinding) {
743       switch (binding.id) {
744         case TypeIds.T_boolean:
745           return JPrimitiveType.BOOLEAN;
746         case TypeIds.T_byte:
747           return JPrimitiveType.BYTE;
748         case TypeIds.T_char:
749           return JPrimitiveType.CHAR;
750         case TypeIds.T_short:
751           return JPrimitiveType.SHORT;
752         case TypeIds.T_int:
753           return JPrimitiveType.INT;
754         case TypeIds.T_long:
755           return JPrimitiveType.LONG;
756         case TypeIds.T_float:
757           return JPrimitiveType.FLOAT;
758         case TypeIds.T_double:
759           return JPrimitiveType.DOUBLE;
760         case TypeIds.T_void:
761           return JPrimitiveType.VOID;
762         default:
763           assert false : "Unexpected base type id " + binding.id;
764       }
765     }
766
767     // Check for a user-defined type.
768
//
769
if (binding instanceof SourceTypeBinding) {
770       SourceTypeBinding sourceTypeBinding = (SourceTypeBinding) binding;
771
772       // First check the type oracle to prefer type identity with the type
773
// oracle we're assimilating into.
774
//
775
String JavaDoc typeName = String.valueOf(sourceTypeBinding.readableName());
776       JType resolvedType = oracle.findType(typeName);
777       if (resolvedType != null) {
778         return resolvedType;
779       }
780
781       // Otherwise, it should be something we've mapped during this build.
782
//
783
resolvedType = cacheManager.getTypeForBinding(sourceTypeBinding);
784       if (resolvedType != null) {
785         return resolvedType;
786       }
787     }
788
789     // Check for an array.
790
//
791
if (binding instanceof ArrayBinding) {
792       ArrayBinding arrayBinding = (ArrayBinding) binding;
793
794       // Start by resolving the leaf type.
795
//
796
TypeBinding leafBinding = arrayBinding.leafComponentType;
797       JType resolvedType = resolveType(logger, leafBinding);
798       if (resolvedType != null) {
799         int dims = arrayBinding.dimensions;
800         for (int i = 0; i < dims; ++i) {
801           // By using the oracle to intern, we guarantee correct identity
802
// mapping of lazily-created array types.
803
//
804
resolvedType = oracle.getArrayType(resolvedType);
805         }
806         return resolvedType;
807       } else {
808         // Fall-through to failure.
809
//
810
}
811     }
812
813     // Log other cases we know about that don't make sense.
814
//
815
if (binding instanceof BinaryTypeBinding) {
816       logger.log(TreeLogger.WARN,
817           "Source not available for this type, so it cannot be resolved", null);
818     }
819
820     String JavaDoc name = String.valueOf(binding.readableName());
821     logger.log(TreeLogger.WARN, "Unable to resolve type: " + name, null);
822     return null;
823   }
824
825   private boolean resolveTypeDeclaration(TreeLogger logger, char[] unitSource,
826       TypeDeclaration jclass) {
827     SourceTypeBinding binding = jclass.binding;
828     if (binding.constantPoolName() == null) {
829       /*
830        * Weird case: if JDT determines that this local class is totally
831        * uninstantiable, it won't bother allocating a local name.
832        */

833       return true;
834     }
835
836     String JavaDoc qname = String.valueOf(binding.qualifiedSourceName());
837     logger.log(TreeLogger.SPAM, "Found type '" + qname + "'", null);
838
839     JClassType type = (JClassType) resolveType(logger, binding);
840     if (type == null) {
841       // Failed to resolve.
842
//
843
return false;
844     }
845
846     // Add modifiers.
847
//
848
type.addModifierBits(Shared.bindingToModifierBits(jclass.binding));
849
850     // Resolve superclass (for classes only).
851
//
852
if (type.isInterface() == null) {
853       ReferenceBinding superclassRef = binding.superclass;
854       if (superclassRef != null) {
855         JClassType superclass = (JClassType) resolveType(logger, superclassRef);
856         if (superclass == null) {
857           return false;
858         }
859         type.setSuperclass(superclass);
860       }
861     }
862
863     // Resolve superinterfaces.
864
//
865
ReferenceBinding[] superintfRefs = binding.superInterfaces;
866     for (int i = 0; i < superintfRefs.length; i++) {
867       ReferenceBinding superintfRef = superintfRefs[i];
868       JClassType intf = (JClassType) resolveType(logger, superintfRef);
869       if (intf == null) {
870         // Failed to resolve.
871
//
872
return false;
873       }
874       type.addImplementedInterface(intf);
875     }
876
877     // Resolve fields.
878
//
879
FieldDeclaration[] jfields = jclass.fields;
880     if (!resolveFields(logger, unitSource, type, jfields)) {
881       return false;
882     }
883
884     // Resolve methods.
885
//
886
AbstractMethodDeclaration[] jmethods = jclass.methods;
887     if (!resolveMethods(logger, unitSource, type, jmethods)) {
888       return false;
889     }
890
891     // Get tags.
892
//
893
if (jclass.javadoc != null) {
894       if (!parseMetaDataTags(unitSource, type, jclass.javadoc)) {
895         return false;
896       }
897     }
898
899     return true;
900   }
901
902 }
903
Popular Tags