KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > SourceMapper


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core;
12
13 import java.io.File JavaDoc;
14 import java.io.FilenameFilter JavaDoc;
15 import java.io.IOException JavaDoc;
16 import java.util.ArrayList JavaDoc;
17 import java.util.Collections JavaDoc;
18 import java.util.Comparator JavaDoc;
19 import java.util.Enumeration JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.HashSet JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.Set JavaDoc;
25 import java.util.zip.ZipEntry JavaDoc;
26 import java.util.zip.ZipFile JavaDoc;
27
28 import org.eclipse.core.resources.IContainer;
29 import org.eclipse.core.resources.IFile;
30 import org.eclipse.core.resources.IFolder;
31 import org.eclipse.core.resources.IResource;
32 import org.eclipse.core.resources.ResourcesPlugin;
33 import org.eclipse.core.runtime.CoreException;
34 import org.eclipse.core.runtime.IPath;
35 import org.eclipse.core.runtime.IStatus;
36 import org.eclipse.core.runtime.Path;
37 import org.eclipse.jdt.core.Flags;
38 import org.eclipse.jdt.core.IClassFile;
39 import org.eclipse.jdt.core.IField;
40 import org.eclipse.jdt.core.IJavaElement;
41 import org.eclipse.jdt.core.IJavaProject;
42 import org.eclipse.jdt.core.IMember;
43 import org.eclipse.jdt.core.IMethod;
44 import org.eclipse.jdt.core.IPackageFragmentRoot;
45 import org.eclipse.jdt.core.ISourceRange;
46 import org.eclipse.jdt.core.IType;
47 import org.eclipse.jdt.core.ITypeParameter;
48 import org.eclipse.jdt.core.JavaConventions;
49 import org.eclipse.jdt.core.JavaCore;
50 import org.eclipse.jdt.core.JavaModelException;
51 import org.eclipse.jdt.core.Signature;
52 import org.eclipse.jdt.core.compiler.CategorizedProblem;
53 import org.eclipse.jdt.core.compiler.CharOperation;
54 import org.eclipse.jdt.internal.compiler.IProblemFactory;
55 import org.eclipse.jdt.internal.compiler.ISourceElementRequestor;
56 import org.eclipse.jdt.internal.compiler.SourceElementParser;
57 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
58 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
59 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
60 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
61 import org.eclipse.jdt.internal.compiler.util.Util;
62 import org.eclipse.jdt.internal.core.util.ReferenceInfoAdapter;
63
64 /**
65  * A SourceMapper maps source code in a ZIP file to binary types in
66  * a JAR. The SourceMapper uses the fuzzy parser to identify source
67  * fragments in a .java file, and attempts to match the source code
68  * with children in a binary type. A SourceMapper is associated
69  * with a JarPackageFragment by an AttachSourceOperation.
70  *
71  * @see org.eclipse.jdt.internal.core.JarPackageFragment
72  */

73 public class SourceMapper
74     extends ReferenceInfoAdapter
75     implements ISourceElementRequestor, SuffixConstants {
76         
77     public static boolean VERBOSE = false;
78     /**
79      * Specifies the file name filter use to compute the root paths.
80      */

81     private static final FilenameFilter JavaDoc FILENAME_FILTER = new FilenameFilter JavaDoc() {
82         public boolean accept(File JavaDoc dir, String JavaDoc name) {
83             return org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(name);
84         }
85     };
86     /**
87      * Specifies the location of the package fragment roots within
88      * the zip (empty specifies the default root). <code>null</code> is
89      * not a valid root path.
90      */

91     protected ArrayList JavaDoc rootPaths;
92
93     /**
94      * The binary type source is being mapped for
95      */

96     protected BinaryType binaryType;
97
98     /**
99      * The location of the zip file containing source.
100      */

101     protected IPath sourcePath;
102     /**
103      * Specifies the location of the package fragment root within
104      * the zip (empty specifies the default root). <code>null</code> is
105      * not a valid root path.
106      */

107     protected String JavaDoc rootPath = ""; //$NON-NLS-1$
108

109     /**
110      * Table that maps a binary method to its parameter names.
111      * Keys are the method handles, entries are <code>char[][]</code>.
112      */

113     protected HashMap JavaDoc parameterNames;
114     
115     /**
116      * Table that maps a binary element to its <code>SourceRange</code>s.
117      * Keys are the element handles, entries are <code>SourceRange[]</code> which
118      * is a two element array; the first being source range, the second
119      * being name range.
120      */

121     protected HashMap JavaDoc sourceRanges;
122     
123     /*
124      * A map from IJavaElement to String[]
125      */

126     protected HashMap JavaDoc categories;
127     
128
129     /**
130      * The unknown source range {-1, 0}
131      */

132     public static final SourceRange UNKNOWN_RANGE = new SourceRange(-1, 0);
133
134     /**
135      * The position within the source of the start of the
136      * current member element, or -1 if we are outside a member.
137      */

138     protected int[] memberDeclarationStart;
139     /**
140      * The <code>SourceRange</code> of the name of the current member element.
141      */

142     protected SourceRange[] memberNameRange;
143     /**
144      * The name of the current member element.
145      */

146     protected String JavaDoc[] memberName;
147     
148     /**
149      * The parameter names for the current member method element.
150      */

151     protected char[][][] methodParameterNames;
152     
153     /**
154      * The parameter types for the current member method element.
155      */

156     protected char[][][] methodParameterTypes;
157     
158
159     /**
160      * The element searched for
161      */

162     protected IJavaElement searchedElement;
163
164     /**
165      * imports references
166      */

167     private HashMap JavaDoc importsTable;
168     private HashMap JavaDoc importsCounterTable;
169
170     /**
171      * Enclosing type information
172      */

173     IType[] types;
174     int[] typeDeclarationStarts;
175     SourceRange[] typeNameRanges;
176     int[] typeModifiers;
177     int typeDepth;
178     
179     /**
180      * Anonymous counter in case we want to map the source of an anonymous class.
181      */

182     int anonymousCounter;
183     int anonymousClassName;
184     
185     /**
186      *Options to be used
187      */

188     String JavaDoc encoding;
189     Map JavaDoc options;
190     
191     /**
192      * Use to handle root paths inference
193      */

194     private boolean areRootPathsComputed;
195         
196     public SourceMapper() {
197         this.areRootPathsComputed = false;
198     }
199     
200     /**
201      * Creates a <code>SourceMapper</code> that locates source in the zip file
202      * at the given location in the specified package fragment root.
203      */

204     public SourceMapper(IPath sourcePath, String JavaDoc rootPath, Map JavaDoc options) {
205         this.areRootPathsComputed = false;
206         this.options = options;
207         try {
208             this.encoding = ResourcesPlugin.getWorkspace().getRoot().getDefaultCharset();
209         } catch (CoreException e) {
210             // use no encoding
211
}
212         if (rootPath != null) {
213             this.rootPaths = new ArrayList JavaDoc();
214             this.rootPaths.add(rootPath);
215         }
216         this.sourcePath = sourcePath;
217         this.sourceRanges = new HashMap JavaDoc();
218         this.parameterNames = new HashMap JavaDoc();
219         this.importsTable = new HashMap JavaDoc();
220         this.importsCounterTable = new HashMap JavaDoc();
221     }
222     
223     /**
224      * @see ISourceElementRequestor
225      */

226     public void acceptImport(
227             int declarationStart,
228             int declarationEnd,
229             char[][] tokens,
230             boolean onDemand,
231             int modifiers) {
232         char[][] imports = (char[][]) this.importsTable.get(this.binaryType);
233         int importsCounter;
234         if (imports == null) {
235             imports = new char[5][];
236             importsCounter = 0;
237         } else {
238             importsCounter = ((Integer JavaDoc) this.importsCounterTable.get(this.binaryType)).intValue();
239         }
240         if (imports.length == importsCounter) {
241             System.arraycopy(
242                 imports,
243                 0,
244                 (imports = new char[importsCounter * 2][]),
245                 0,
246                 importsCounter);
247         }
248         char[] name = CharOperation.concatWith(tokens, '.');
249         if (onDemand) {
250             int nameLength = name.length;
251             System.arraycopy(name, 0, (name = new char[nameLength + 2]), 0, nameLength);
252             name[nameLength] = '.';
253             name[nameLength + 1] = '*';
254         }
255         imports[importsCounter++] = name;
256         this.importsTable.put(this.binaryType, imports);
257         this.importsCounterTable.put(this.binaryType, new Integer JavaDoc(importsCounter));
258     }
259     
260     /**
261      * @see ISourceElementRequestor
262      */

263     public void acceptLineSeparatorPositions(int[] positions) {
264         //do nothing
265
}
266     
267     /**
268      * @see ISourceElementRequestor
269      */

270     public void acceptPackage(
271         int declarationStart,
272         int declarationEnd,
273         char[] name) {
274         //do nothing
275
}
276     
277     /**
278      * @see ISourceElementRequestor
279      */

280     public void acceptProblem(CategorizedProblem problem) {
281         //do nothing
282
}
283     
284     private void addCategories(IJavaElement element, char[][] elementCategories) {
285         if (elementCategories == null) return;
286         if (this.categories == null)
287             this.categories = new HashMap JavaDoc();
288         this.categories.put(element, CharOperation.toStrings(elementCategories));
289     }
290
291     /**
292      * Closes this <code>SourceMapper</code>'s zip file. Once this is done, this
293      * <code>SourceMapper</code> cannot be used again.
294      */

295     public void close() {
296         this.sourceRanges = null;
297         this.parameterNames = null;
298     }
299
300     /**
301      * Converts these type names to unqualified signatures. This needs to be done in order to be consistent
302      * with the way the source range is retrieved.
303      * @see SourceMapper#getUnqualifiedMethodHandle
304      * @see Signature
305      */

306     private String JavaDoc[] convertTypeNamesToSigs(char[][] typeNames) {
307         if (typeNames == null)
308             return CharOperation.NO_STRINGS;
309         int n = typeNames.length;
310         if (n == 0)
311             return CharOperation.NO_STRINGS;
312         String JavaDoc[] typeSigs = new String JavaDoc[n];
313         for (int i = 0; i < n; ++i) {
314             char[] typeSig = Signature.createCharArrayTypeSignature(typeNames[i], false);
315             
316             // transforms signatures that contains a qualification into unqualified signatures
317
// e.g. "QX<+QMap.Entry;>;" becomes "QX<+QEntry;>;"
318
StringBuffer JavaDoc simpleTypeSig = null;
319             int start = 0;
320             int dot = -1;
321             int length = typeSig.length;
322             for (int j = 0; j < length; j++) {
323                 switch (typeSig[j]) {
324                     case Signature.C_UNRESOLVED:
325                         if (simpleTypeSig != null)
326                             simpleTypeSig.append(typeSig, start, j-start);
327                         start = j;
328                         break;
329                     case Signature.C_DOT:
330                         dot = j;
331                         break;
332                     case Signature.C_GENERIC_START:
333                     case Signature.C_NAME_END:
334                         if (dot > start) {
335                             if (simpleTypeSig == null)
336                                 simpleTypeSig = new StringBuffer JavaDoc().append(typeSig, 0, start);
337                             simpleTypeSig.append(Signature.C_UNRESOLVED);
338                             simpleTypeSig.append(typeSig, dot+1, j-dot-1);
339                             start = j;
340                         }
341                         break;
342                 }
343             }
344             if (simpleTypeSig == null) {
345                 typeSigs[i] = new String JavaDoc(typeSig);
346             } else {
347                 simpleTypeSig.append(typeSig, start, length-start);
348                 typeSigs[i] = simpleTypeSig.toString();
349             }
350         }
351         return typeSigs;
352     }
353     
354     private synchronized void computeAllRootPaths(IType type) {
355         if (this.areRootPathsComputed) {
356             return;
357         }
358         IPackageFragmentRoot root = (IPackageFragmentRoot) type.getPackageFragment().getParent();
359         final HashSet JavaDoc tempRoots = new HashSet JavaDoc();
360         long time = 0;
361         if (VERBOSE) {
362             System.out.println("compute all root paths for " + root.getElementName()); //$NON-NLS-1$
363
time = System.currentTimeMillis();
364         }
365         final HashSet JavaDoc firstLevelPackageNames = new HashSet JavaDoc();
366         boolean containsADefaultPackage = false;
367
368         if (root.isArchive()) {
369             JarPackageFragmentRoot jarPackageFragmentRoot = (JarPackageFragmentRoot) root;
370             IJavaProject project = jarPackageFragmentRoot.getJavaProject();
371             String JavaDoc sourceLevel = null;
372             String JavaDoc complianceLevel = null;
373             JavaModelManager manager = JavaModelManager.getJavaModelManager();
374             ZipFile JavaDoc zip = null;
375             try {
376                 zip = manager.getZipFile(jarPackageFragmentRoot.getPath());
377                 for (Enumeration JavaDoc entries = zip.entries(); entries.hasMoreElements(); ) {
378                     ZipEntry JavaDoc entry = (ZipEntry JavaDoc) entries.nextElement();
379                     String JavaDoc entryName = entry.getName();
380                     if (!entry.isDirectory()) {
381                         int index = entryName.indexOf('/');
382                         if (index != -1 && Util.isClassFileName(entryName)) {
383                             String JavaDoc firstLevelPackageName = entryName.substring(0, index);
384                             if (!firstLevelPackageNames.contains(firstLevelPackageName)) {
385                                 if (sourceLevel == null) {
386                                     sourceLevel = project.getOption(JavaCore.COMPILER_SOURCE, true);
387                                     complianceLevel = project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
388                                 }
389                                 IStatus status = JavaConventions.validatePackageName(firstLevelPackageName, sourceLevel, complianceLevel);
390                                 if (status.isOK() || status.getSeverity() == IStatus.WARNING) {
391                                     firstLevelPackageNames.add(firstLevelPackageName);
392                                 }
393                             }
394                         } else if (Util.isClassFileName(entryName)) {
395                             containsADefaultPackage = true;
396                         }
397                     }
398                 }
399             } catch (CoreException e) {
400                 // ignore
401
} finally {
402                 manager.closeZipFile(zip); // handle null case
403
}
404         } else {
405             Object JavaDoc target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), root.getPath(), true);
406             if (target instanceof IResource) {
407                 IResource resource = (IResource) target;
408                 if (resource instanceof IContainer) {
409                     try {
410                         IResource[] members = ((IContainer) resource).members();
411                         for (int i = 0, max = members.length; i < max; i++) {
412                             IResource member = members[i];
413                             if (member.getType() == IResource.FOLDER) {
414                                 firstLevelPackageNames.add(member.getName());
415                             } else if (Util.isClassFileName(member.getName())) {
416                                 containsADefaultPackage = true;
417                             }
418                         }
419                     } catch (CoreException e) {
420                         // ignore
421
}
422                 }
423             } else if (target instanceof File JavaDoc) {
424                 File JavaDoc file = (File JavaDoc)target;
425                 if (file.isDirectory()) {
426                     File JavaDoc[] files = file.listFiles();
427                     for (int i = 0, max = files.length; i < max; i++) {
428                         File JavaDoc currentFile = files[i];
429                         if (currentFile.isDirectory()) {
430                             firstLevelPackageNames.add(currentFile.getName());
431                         } else if (Util.isClassFileName(currentFile.getName())) {
432                             containsADefaultPackage = true;
433                         }
434                     }
435                 }
436             }
437         }
438
439         if (Util.isArchiveFileName(this.sourcePath.lastSegment())) {
440             JavaModelManager manager = JavaModelManager.getJavaModelManager();
441             ZipFile JavaDoc zip = null;
442             try {
443                 zip = manager.getZipFile(this.sourcePath);
444                 for (Enumeration JavaDoc entries = zip.entries(); entries.hasMoreElements(); ) {
445                     ZipEntry JavaDoc entry = (ZipEntry JavaDoc) entries.nextElement();
446                     String JavaDoc entryName;
447                     if (!entry.isDirectory() && org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(entryName = entry.getName())) {
448                         IPath path = new Path(entryName);
449                         int segmentCount = path.segmentCount();
450                         if (segmentCount > 1) {
451                             for (int i = 0, max = path.segmentCount() - 1; i < max; i++) {
452                                 if (firstLevelPackageNames.contains(path.segment(i))) {
453                                     tempRoots.add(path.uptoSegment(i));
454                                     // don't break here as this path could contain other first level package names (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=74014)
455
}
456                                 if (i == max - 1 && containsADefaultPackage) {
457                                     tempRoots.add(path.uptoSegment(max));
458                                 }
459                             }
460                         } else if (containsADefaultPackage) {
461                             tempRoots.add(new Path("")); //$NON-NLS-1$
462
}
463                     }
464                 }
465             } catch (CoreException e) {
466                 // ignore
467
} finally {
468                 manager.closeZipFile(zip); // handle null case
469
}
470         } else {
471             Object JavaDoc target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), this.sourcePath, true);
472             if (target instanceof IResource) {
473                 if (target instanceof IContainer) {
474                     computeRootPath((IContainer)target, firstLevelPackageNames, containsADefaultPackage, tempRoots);
475                 }
476             } else if (target instanceof File JavaDoc) {
477                 File JavaDoc file = (File JavaDoc)target;
478                 if (file.isDirectory()) {
479                     computeRootPath(file, firstLevelPackageNames, containsADefaultPackage, tempRoots);
480                 }
481             }
482         }
483         int size = tempRoots.size();
484         if (this.rootPaths != null) {
485             for (Iterator JavaDoc iterator = this.rootPaths.iterator(); iterator.hasNext(); ) {
486                 tempRoots.add(new Path((String JavaDoc) iterator.next()));
487             }
488             this.rootPaths.clear();
489         } else {
490             this.rootPaths = new ArrayList JavaDoc(size);
491         }
492         size = tempRoots.size();
493         if (size > 0) {
494             ArrayList JavaDoc sortedRoots = new ArrayList JavaDoc(tempRoots);
495             if (size > 1) {
496                 Collections.sort(sortedRoots, new Comparator JavaDoc() {
497                     public int compare(Object JavaDoc o1, Object JavaDoc o2) {
498                         IPath path1 = (IPath) o1;
499                         IPath path2 = (IPath) o2;
500                         return path1.segmentCount() - path2.segmentCount();
501                     }
502                 });
503             }
504             for (Iterator JavaDoc iter = sortedRoots.iterator(); iter.hasNext();) {
505                 IPath path = (IPath) iter.next();
506                 this.rootPaths.add(path.toString());
507             }
508         }
509         this.areRootPathsComputed = true;
510         if (VERBOSE) {
511             System.out.println("Spent " + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$
512
System.out.println("Found " + size + " root paths"); //$NON-NLS-1$ //$NON-NLS-2$
513
int i = 0;
514             for (Iterator JavaDoc iterator = this.rootPaths.iterator(); iterator.hasNext();) {
515                 System.out.println("root[" + i + "]=" + ((String JavaDoc) iterator.next()));//$NON-NLS-1$ //$NON-NLS-2$
516
i++;
517             }
518         }
519     }
520     
521     private void computeRootPath(File JavaDoc directory, HashSet JavaDoc firstLevelPackageNames, boolean hasDefaultPackage, Set JavaDoc set) {
522         File JavaDoc[] files = directory.listFiles();
523         boolean hasSubDirectories = false;
524         loop: for (int i = 0, max = files.length; i < max; i++) {
525             File JavaDoc file = files[i];
526             if (file.isDirectory()) {
527                 hasSubDirectories = true;
528                 if (firstLevelPackageNames.contains(file.getName())) {
529                     IPath fullPath = new Path(file.getParentFile().getPath());
530                     IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null);
531                     set.add(rootPathEntry);
532                     break loop;
533                 } else {
534                     computeRootPath(file, firstLevelPackageNames, hasDefaultPackage, set);
535                 }
536             } else if (i == max - 1 && !hasSubDirectories && hasDefaultPackage) {
537                 File JavaDoc parentDir = file.getParentFile();
538                 if (parentDir.list(FILENAME_FILTER).length != 0) {
539                     IPath fullPath = new Path(parentDir.getPath());
540                     IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null);
541                     set.add(rootPathEntry);
542                 }
543             }
544         }
545     }
546
547     private void computeRootPath(IContainer container, HashSet JavaDoc firstLevelPackageNames, boolean hasDefaultPackage, Set JavaDoc set) {
548         try {
549             IResource[] resources = container.members();
550             boolean hasSubDirectories = false;
551             loop: for (int i = 0, max = resources.length; i < max; i++) {
552                 IResource resource = resources[i];
553                 if (resource.getType() == IResource.FOLDER) {
554                     hasSubDirectories = true;
555                     if (firstLevelPackageNames.contains(resource.getName())) {
556                         IPath fullPath = container.getFullPath();
557                         IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null);
558                         set.add(rootPathEntry);
559                         break loop;
560                     } else {
561                         computeRootPath((IFolder) resource, firstLevelPackageNames, hasDefaultPackage, set);
562                     }
563                 }
564                 if (i == max - 1 && !hasSubDirectories && hasDefaultPackage) {
565                     // check if one member is a .java file
566
boolean hasJavaSourceFile = false;
567                     for (int j = 0; j < max; j++) {
568                         if (org.eclipse.jdt.internal.core.util.Util.isJavaLikeFileName(resources[i].getName())) {
569                             hasJavaSourceFile = true;
570                             break;
571                         }
572                     }
573                     if (hasJavaSourceFile) {
574                         IPath fullPath = container.getFullPath();
575                         IPath rootPathEntry = fullPath.removeFirstSegments(this.sourcePath.segmentCount()).setDevice(null);
576                         set.add(rootPathEntry);
577                     }
578                 }
579             }
580         } catch (CoreException e) {
581             // ignore
582
}
583     }
584
585     /**
586      * @see ISourceElementRequestor
587      */

588     public void enterType(TypeInfo typeInfo) {
589
590         this.typeDepth++;
591         if (this.typeDepth == this.types.length) { // need to grow
592
System.arraycopy(
593                 this.types,
594                 0,
595                 this.types = new IType[this.typeDepth * 2],
596                 0,
597                 this.typeDepth);
598             System.arraycopy(
599                 this.typeNameRanges,
600                 0,
601                 this.typeNameRanges = new SourceRange[this.typeDepth * 2],
602                 0,
603                 this.typeDepth);
604             System.arraycopy(
605                 this.typeDeclarationStarts,
606                 0,
607                 this.typeDeclarationStarts = new int[this.typeDepth * 2],
608                 0,
609                 this.typeDepth);
610             System.arraycopy(
611                 this.memberName,
612                 0,
613                 this.memberName = new String JavaDoc[this.typeDepth * 2],
614                 0,
615                 this.typeDepth);
616             System.arraycopy(
617                 this.memberDeclarationStart,
618                 0,
619                 this.memberDeclarationStart = new int[this.typeDepth * 2],
620                 0,
621                 this.typeDepth);
622             System.arraycopy(
623                 this.memberNameRange,
624                 0,
625                 this.memberNameRange = new SourceRange[this.typeDepth * 2],
626                 0,
627                 this.typeDepth);
628             System.arraycopy(
629                 this.methodParameterTypes,
630                 0,
631                 this.methodParameterTypes = new char[this.typeDepth * 2][][],
632                 0,
633                 this.typeDepth);
634             System.arraycopy(
635                 this.methodParameterNames,
636                 0,
637                 this.methodParameterNames = new char[this.typeDepth * 2][][],
638                 0,
639                 this.typeDepth);
640             System.arraycopy(
641                 this.typeModifiers,
642                 0,
643                 this.typeModifiers = new int[this.typeDepth * 2],
644                 0,
645                 this.typeDepth);
646         }
647         if (typeInfo.name.length == 0) {
648             this.anonymousCounter++;
649             if (this.anonymousCounter == this.anonymousClassName) {
650                 this.types[typeDepth] = this.getType(this.binaryType.getElementName());
651             } else {
652                 this.types[typeDepth] = this.getType(new String JavaDoc(typeInfo.name));
653             }
654         } else {
655             this.types[typeDepth] = this.getType(new String JavaDoc(typeInfo.name));
656         }
657         this.typeNameRanges[typeDepth] =
658             new SourceRange(typeInfo.nameSourceStart, typeInfo.nameSourceEnd - typeInfo.nameSourceStart + 1);
659         this.typeDeclarationStarts[typeDepth] = typeInfo.declarationStart;
660
661         IType currentType = this.types[typeDepth];
662         
663         // type parameters
664
if (typeInfo.typeParameters != null) {
665             for (int i = 0, length = typeInfo.typeParameters.length; i < length; i++) {
666                 TypeParameterInfo typeParameterInfo = typeInfo.typeParameters[i];
667                 ITypeParameter typeParameter = currentType.getTypeParameter(new String JavaDoc(typeParameterInfo.name));
668                 setSourceRange(
669                     typeParameter,
670                     new SourceRange(
671                         typeParameterInfo.declarationStart,
672                         typeParameterInfo.declarationEnd - typeParameterInfo.declarationStart + 1),
673                     new SourceRange(
674                         typeParameterInfo.nameSourceStart,
675                         typeParameterInfo.nameSourceEnd - typeParameterInfo.nameSourceStart + 1));
676             }
677         }
678         
679         // type modifiers
680
this.typeModifiers[typeDepth] = typeInfo.modifiers;
681
682         // categories
683
addCategories(currentType, typeInfo.categories);
684     }
685
686     /**
687      * @see ISourceElementRequestor
688      */

689     public void enterCompilationUnit() {
690         // do nothing
691
}
692     
693     /**
694      * @see ISourceElementRequestor
695      */

696     public void enterConstructor(MethodInfo methodInfo) {
697         enterAbstractMethod(methodInfo);
698     }
699     
700     /**
701      * @see ISourceElementRequestor
702      */

703     public void enterField(FieldInfo fieldInfo) {
704         if (typeDepth >= 0) {
705             this.memberDeclarationStart[typeDepth] = fieldInfo.declarationStart;
706             this.memberNameRange[typeDepth] =
707                 new SourceRange(fieldInfo.nameSourceStart, fieldInfo.nameSourceEnd - fieldInfo.nameSourceStart + 1);
708             String JavaDoc fieldName = new String JavaDoc(fieldInfo.name);
709             this.memberName[typeDepth] = fieldName;
710             
711             // categories
712
IType currentType = this.types[typeDepth];
713             IField field = currentType.getField(fieldName);
714             addCategories(field, fieldInfo.categories);
715         }
716     }
717     
718     /**
719      * @see ISourceElementRequestor
720      */

721     public void enterInitializer(
722         int declarationSourceStart,
723         int modifiers) {
724         //do nothing
725
}
726     
727     /**
728      * @see ISourceElementRequestor
729      */

730     public void enterMethod(MethodInfo methodInfo) {
731         enterAbstractMethod(methodInfo);
732     }
733     private void enterAbstractMethod(MethodInfo methodInfo) {
734         if (typeDepth >= 0) {
735             this.memberName[typeDepth] = new String JavaDoc(methodInfo.name);
736             this.memberNameRange[typeDepth] =
737                 new SourceRange(methodInfo.nameSourceStart, methodInfo.nameSourceEnd - methodInfo.nameSourceStart + 1);
738             this.memberDeclarationStart[typeDepth] = methodInfo.declarationStart;
739             IType currentType = this.types[typeDepth];
740             int currenTypeModifiers = this.typeModifiers[typeDepth];
741             char[][] parameterTypes = methodInfo.parameterTypes;
742             if (parameterTypes != null && methodInfo.isConstructor && currentType.getDeclaringType() != null && !Flags.isStatic(currenTypeModifiers)) {
743                 IType declaringType = currentType.getDeclaringType();
744                 String JavaDoc declaringTypeName = declaringType.getElementName();
745                 if (declaringTypeName.length() == 0) {
746                     IClassFile classFile = declaringType.getClassFile();
747                     int length = parameterTypes.length;
748                     char[][] newParameterTypes = new char[length+1][];
749                     declaringTypeName = classFile.getElementName();
750                     declaringTypeName = declaringTypeName.substring(0, declaringTypeName.indexOf('.'));
751                     newParameterTypes[0] = declaringTypeName.toCharArray();
752                     System.arraycopy(parameterTypes, 0, newParameterTypes, 1, length);
753                     this.methodParameterTypes[typeDepth] = newParameterTypes;
754                 } else {
755                     int length = parameterTypes.length;
756                     char[][] newParameterTypes = new char[length+1][];
757                     newParameterTypes[0] = declaringTypeName.toCharArray();
758                     System.arraycopy(parameterTypes, 0, newParameterTypes, 1, length);
759                     this.methodParameterTypes[typeDepth] = newParameterTypes;
760                 }
761             } else {
762                 this.methodParameterTypes[typeDepth] = parameterTypes;
763             }
764             this.methodParameterNames[typeDepth] = methodInfo.parameterNames;
765             
766             IMethod method = currentType.getMethod(
767                     this.memberName[typeDepth],
768                     convertTypeNamesToSigs(this.methodParameterTypes[typeDepth]));
769             
770             // type parameters
771
if (methodInfo.typeParameters != null) {
772                 for (int i = 0, length = methodInfo.typeParameters.length; i < length; i++) {
773                     TypeParameterInfo typeParameterInfo = methodInfo.typeParameters[i];
774                     ITypeParameter typeParameter = method.getTypeParameter(new String JavaDoc(typeParameterInfo.name));
775                     setSourceRange(
776                         typeParameter,
777                         new SourceRange(
778                             typeParameterInfo.declarationStart,
779                             typeParameterInfo.declarationEnd - typeParameterInfo.declarationStart + 1),
780                         new SourceRange(
781                             typeParameterInfo.nameSourceStart,
782                             typeParameterInfo.nameSourceEnd - typeParameterInfo.nameSourceStart + 1));
783                 }
784             }
785             
786             // categories
787
addCategories(method, methodInfo.categories);
788         }
789     }
790     
791     /**
792      * @see ISourceElementRequestor
793      */

794     public void exitType(int declarationEnd) {
795         if (typeDepth >= 0) {
796             IType currentType = this.types[typeDepth];
797             setSourceRange(
798                 currentType,
799                 new SourceRange(
800                     this.typeDeclarationStarts[typeDepth],
801                     declarationEnd - this.typeDeclarationStarts[typeDepth] + 1),
802                 this.typeNameRanges[typeDepth]);
803             this.typeDepth--;
804         }
805     }
806     
807     /**
808      * @see ISourceElementRequestor
809      */

810     public void exitCompilationUnit(int declarationEnd) {
811         //do nothing
812
}
813     
814     /**
815      * @see ISourceElementRequestor
816      */

817     public void exitConstructor(int declarationEnd) {
818         exitAbstractMethod(declarationEnd);
819     }
820     
821     /**
822      * @see ISourceElementRequestor
823      */

824     public void exitField(int initializationStart, int declarationEnd, int declarationSourceEnd) {
825         if (typeDepth >= 0) {
826             IType currentType = this.types[typeDepth];
827             setSourceRange(
828                 currentType.getField(this.memberName[typeDepth]),
829                 new SourceRange(
830                     this.memberDeclarationStart[typeDepth],
831                     declarationEnd - this.memberDeclarationStart[typeDepth] + 1),
832                 this.memberNameRange[typeDepth]);
833         }
834     }
835     
836     /**
837      * @see ISourceElementRequestor
838      */

839     public void exitInitializer(int declarationEnd) {
840         // implements abstract method
841
}
842     
843     /**
844      * @see ISourceElementRequestor
845      */

846     public void exitMethod(int declarationEnd, int defaultValueStart, int defaultValueEnd) {
847         exitAbstractMethod(declarationEnd);
848     }
849     private void exitAbstractMethod(int declarationEnd) {
850         if (typeDepth >= 0) {
851             IType currentType = this.types[typeDepth];
852             SourceRange sourceRange =
853                 new SourceRange(
854                     this.memberDeclarationStart[typeDepth],
855                     declarationEnd - this.memberDeclarationStart[typeDepth] + 1);
856             IMethod method = currentType.getMethod(
857                     this.memberName[typeDepth],
858                     convertTypeNamesToSigs(this.methodParameterTypes[typeDepth]));
859             setSourceRange(
860                 method,
861                 sourceRange,
862                 this.memberNameRange[typeDepth]);
863             setMethodParameterNames(
864                 method,
865                 this.methodParameterNames[typeDepth]);
866         }
867     }
868     
869     /**
870      * Locates and returns source code for the given (binary) type, in this
871      * SourceMapper's ZIP file, or returns <code>null</code> if source
872      * code cannot be found.
873      */

874     public char[] findSource(IType type, IBinaryType info) {
875         if (!type.isBinary()) {
876             return null;
877         }
878         String JavaDoc simpleSourceFileName = ((BinaryType) type).getSourceFileName(info);
879         if (simpleSourceFileName == null) {
880             return null;
881         }
882         return findSource(type, simpleSourceFileName);
883     }
884     
885     /**
886      * Locates and returns source code for the given (binary) type, in this
887      * SourceMapper's ZIP file, or returns <code>null</code> if source
888      * code cannot be found.
889      * The given simpleSourceFileName is the .java file name (without the enclosing
890      * folder) used to create the given type (e.g. "A.java" for x/y/A$Inner.class)
891      */

892     public char[] findSource(IType type, String JavaDoc simpleSourceFileName) {
893         long time = 0;
894         if (VERBOSE) {
895             time = System.currentTimeMillis();
896         }
897         PackageFragment pkgFrag = (PackageFragment) type.getPackageFragment();
898         String JavaDoc name = org.eclipse.jdt.internal.core.util.Util.concatWith(pkgFrag.names, simpleSourceFileName, '/');
899     
900         char[] source = null;
901         
902         if (this.rootPath != null) {
903             source = getSourceForRootPath(this.rootPath, name);
904         }
905
906         if (source == null) {
907             computeAllRootPaths(type);
908             if (this.rootPaths != null) {
909                 loop: for (Iterator JavaDoc iterator = this.rootPaths.iterator(); iterator.hasNext(); ) {
910                     String JavaDoc currentRootPath = (String JavaDoc) iterator.next();
911                     if (!currentRootPath.equals(this.rootPath)) {
912                         source = getSourceForRootPath(currentRootPath, name);
913                         if (source != null) {
914                             // remember right root path
915
this.rootPath = currentRootPath;
916                             break loop;
917                         }
918                     }
919                 }
920             }
921         }
922         if (VERBOSE) {
923             System.out.println("spent " + (System.currentTimeMillis() - time) + "ms for " + type.getElementName()); //$NON-NLS-1$ //$NON-NLS-2$
924
}
925         return source;
926     }
927
928     private char[] getSourceForRootPath(String JavaDoc currentRootPath, String JavaDoc name) {
929         String JavaDoc newFullName;
930         if (!currentRootPath.equals(IPackageFragmentRoot.DEFAULT_PACKAGEROOT_PATH)) {
931             if (currentRootPath.endsWith("/")) { //$NON-NLS-1$
932
newFullName = currentRootPath + name;
933             } else {
934                 newFullName = currentRootPath + '/' + name;
935             }
936         } else {
937             newFullName = name;
938         }
939         return this.findSource(newFullName);
940     }
941     
942     public char[] findSource(String JavaDoc fullName) {
943         char[] source = null;
944         if (Util.isArchiveFileName(this.sourcePath.lastSegment())) {
945             // try to get the entry
946
ZipEntry JavaDoc entry = null;
947             ZipFile JavaDoc zip = null;
948             JavaModelManager manager = JavaModelManager.getJavaModelManager();
949             try {
950                 zip = manager.getZipFile(this.sourcePath);
951                 entry = zip.getEntry(fullName);
952                 if (entry != null) {
953                     // now read the source code
954
source = readSource(entry, zip);
955                 }
956             } catch (CoreException e) {
957                 return null;
958             } finally {
959                 manager.closeZipFile(zip); // handle null case
960
}
961         } else {
962             Object JavaDoc target = JavaModel.getTarget(ResourcesPlugin.getWorkspace().getRoot(), this.sourcePath, true);
963             if (target instanceof IResource) {
964                 if (target instanceof IContainer) {
965                     IResource res = ((IContainer)target).findMember(fullName);
966                     if (res instanceof IFile) {
967                         try {
968                             source = org.eclipse.jdt.internal.core.util.Util.getResourceContentsAsCharArray((IFile)res);
969                         } catch (JavaModelException e) {
970                             // ignore
971
}
972                     }
973                 }
974             } else if (target instanceof File JavaDoc) {
975                 File JavaDoc file = (File JavaDoc)target;
976                 if (file.isDirectory()) {
977                     File JavaDoc sourceFile = new File JavaDoc(file, fullName);
978                     if (sourceFile.isFile()) {
979                         try {
980                             source = Util.getFileCharContent(sourceFile, this.encoding);
981                         } catch (IOException JavaDoc e) {
982                             // ignore
983
}
984                     }
985                 }
986             }
987         }
988         return source;
989     }
990
991
992     
993     /**
994      * Returns the SourceRange for the name of the given element, or
995      * {-1, -1} if no source range is known for the name of the element.
996      */

997     public SourceRange getNameRange(IJavaElement element) {
998         switch(element.getElementType()) {
999             case IJavaElement.METHOD :
1000                if (((IMember) element).isBinary()) {
1001                    IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false);
1002                    if(el[1] != null && this.sourceRanges.get(el[0]) == null) {
1003                        element = getUnqualifiedMethodHandle((IMethod) element, true)[0];
1004                    } else {
1005                        element = el[0];
1006                    }
1007                }
1008                break;
1009            case IJavaElement.TYPE_PARAMETER :
1010                IJavaElement parent = element.getParent();
1011                if (parent.getElementType() == IJavaElement.METHOD) {
1012                    IMethod method = (IMethod) parent;
1013                    if (method.isBinary()) {
1014                        IJavaElement[] el = getUnqualifiedMethodHandle(method, false);
1015                        if(el[1] != null && this.sourceRanges.get(el[0]) == null) {
1016                            method = (IMethod) getUnqualifiedMethodHandle(method, true)[0];
1017                        } else {
1018                            method = (IMethod) el[0];
1019                        }
1020                        element = method.getTypeParameter(element.getElementName());
1021                    }
1022                }
1023        }
1024        SourceRange[] ranges = (SourceRange[]) this.sourceRanges.get(element);
1025        if (ranges == null) {
1026            return UNKNOWN_RANGE;
1027        } else {
1028            return ranges[1];
1029        }
1030    }
1031    
1032    /**
1033     * Returns parameters names for the given method, or
1034     * null if no parameter names are known for the method.
1035     */

1036    public char[][] getMethodParameterNames(IMethod method) {
1037        if (method.isBinary()) {
1038            IJavaElement[] el = getUnqualifiedMethodHandle(method, false);
1039            if(el[1] != null && this.parameterNames.get(el[0]) == null) {
1040                method = (IMethod) getUnqualifiedMethodHandle(method, true)[0];
1041            } else {
1042                method = (IMethod) el[0];
1043            }
1044        }
1045        char[][] parameters = (char[][]) this.parameterNames.get(method);
1046        if (parameters == null) {
1047            return null;
1048        } else {
1049            return parameters;
1050        }
1051    }
1052    
1053    /**
1054     * Returns the <code>SourceRange</code> for the given element, or
1055     * {-1, -1} if no source range is known for the element.
1056     */

1057    public SourceRange getSourceRange(IJavaElement element) {
1058        switch(element.getElementType()) {
1059            case IJavaElement.METHOD :
1060                if (((IMember) element).isBinary()) {
1061                    IJavaElement[] el = getUnqualifiedMethodHandle((IMethod) element, false);
1062                    if(el[1] != null && this.sourceRanges.get(el[0]) == null) {
1063                        element = getUnqualifiedMethodHandle((IMethod) element, true)[0];
1064                    } else {
1065                        element = el[0];
1066                    }
1067                }
1068                break;
1069            case IJavaElement.TYPE_PARAMETER :
1070                IJavaElement parent = element.getParent();
1071                if (parent.getElementType() == IJavaElement.METHOD) {
1072                    IMethod method = (IMethod) parent;
1073                    if (method.isBinary()) {
1074                        IJavaElement[] el = getUnqualifiedMethodHandle(method, false);
1075                        if(el[1] != null && this.sourceRanges.get(el[0]) == null) {
1076                            method = (IMethod) getUnqualifiedMethodHandle(method, true)[0];
1077                        } else {
1078                            method = (IMethod) el[0];
1079                        }
1080                        element = method.getTypeParameter(element.getElementName());
1081                    }
1082                }
1083        }
1084        SourceRange[] ranges = (SourceRange[]) this.sourceRanges.get(element);
1085        if (ranges == null) {
1086            return UNKNOWN_RANGE;
1087        } else {
1088            return ranges[0];
1089        }
1090    }
1091    
1092    /**
1093     * Returns the type with the given <code>typeName</code>. Returns inner classes
1094     * as well.
1095     */

1096    protected IType getType(String JavaDoc typeName) {
1097        if (typeName.length() == 0) {
1098            IJavaElement classFile = this.binaryType.getParent();
1099            String JavaDoc classFileName = classFile.getElementName();
1100            StringBuffer JavaDoc newClassFileName = new StringBuffer JavaDoc();
1101            int lastDollar = classFileName.lastIndexOf('$');
1102            for (int i = 0; i <= lastDollar; i++)
1103                newClassFileName.append(classFileName.charAt(i));
1104            newClassFileName.append(Integer.toString(this.anonymousCounter));
1105            PackageFragment pkg = (PackageFragment) classFile.getParent();
1106            return new BinaryType(new ClassFile(pkg, newClassFileName.toString()), typeName);
1107        } else if (this.binaryType.getElementName().equals(typeName))
1108            return this.binaryType;
1109        else
1110            return this.binaryType.getType(typeName);
1111    }
1112    
1113    /**
1114     * Creates a handle that has parameter types that are not
1115     * fully qualified so that the correct source is found.
1116     */

1117    protected IJavaElement[] getUnqualifiedMethodHandle(IMethod method, boolean noDollar) {
1118        boolean hasDollar = false;
1119        String JavaDoc[] qualifiedParameterTypes = method.getParameterTypes();
1120        String JavaDoc[] unqualifiedParameterTypes = new String JavaDoc[qualifiedParameterTypes.length];
1121        for (int i = 0; i < qualifiedParameterTypes.length; i++) {
1122            StringBuffer JavaDoc unqualifiedTypeSig = new StringBuffer JavaDoc();
1123            getUnqualifiedTypeSignature(qualifiedParameterTypes[i], 0/*start*/, qualifiedParameterTypes[i].length(), unqualifiedTypeSig, noDollar);
1124            unqualifiedParameterTypes[i] = unqualifiedTypeSig.toString();
1125            hasDollar |= unqualifiedParameterTypes[i].lastIndexOf('$') != -1;
1126        }
1127        
1128        IJavaElement[] result = new IJavaElement[2];
1129        result[0] = ((IType) method.getParent()).getMethod(
1130            method.getElementName(),
1131            unqualifiedParameterTypes);
1132        if(hasDollar) {
1133            result[1] = result[0];
1134        }
1135        return result;
1136    }
1137
1138    private int getUnqualifiedTypeSignature(String JavaDoc qualifiedTypeSig, int start, int length, StringBuffer JavaDoc unqualifiedTypeSig, boolean noDollar) {
1139        char firstChar = qualifiedTypeSig.charAt(start);
1140        int end = start + 1;
1141        boolean sigStart = false;
1142        firstPass: for (int i = start; i < length; i++) {
1143            char current = qualifiedTypeSig.charAt(i);
1144            switch (current) {
1145                case Signature.C_ARRAY :
1146                case Signature.C_SUPER:
1147                case Signature.C_EXTENDS:
1148                    unqualifiedTypeSig.append(current);
1149                    start = i + 1;
1150                    end = start + 1;
1151                    firstChar = qualifiedTypeSig.charAt(start);
1152                    break;
1153                case Signature.C_RESOLVED :
1154                case Signature.C_UNRESOLVED :
1155                case Signature.C_TYPE_VARIABLE :
1156                    if (!sigStart) {
1157                        start = ++i;
1158                        sigStart = true;
1159                    }
1160                    break;
1161                case Signature.C_NAME_END:
1162                case Signature.C_GENERIC_START :
1163                    end = i;
1164                    break firstPass;
1165                case Signature.C_STAR :
1166                    unqualifiedTypeSig.append(current);
1167                    start = i + 1;
1168                    end = start + 1;
1169                    firstChar = qualifiedTypeSig.charAt(start);
1170                    break;
1171                case Signature.C_GENERIC_END :
1172                    return i;
1173                case Signature.C_DOT:
1174                    start = ++i;
1175                    break;
1176            }
1177        }
1178        switch (firstChar) {
1179            case Signature.C_RESOLVED :
1180            case Signature.C_UNRESOLVED :
1181            case Signature.C_TYPE_VARIABLE :
1182                unqualifiedTypeSig.append(Signature.C_UNRESOLVED);
1183                if (noDollar) {
1184                    int lastDollar = qualifiedTypeSig.lastIndexOf('$', end);
1185                    if (lastDollar > start)
1186                        start = lastDollar + 1;
1187                }
1188                for (int i = start; i < length; i++) {
1189                    char current = qualifiedTypeSig.charAt(i);
1190                    switch (current) {
1191                        case Signature.C_GENERIC_START:
1192                            unqualifiedTypeSig.append(current);
1193                            i++;
1194                            do {
1195                                i = getUnqualifiedTypeSignature(qualifiedTypeSig, i, length, unqualifiedTypeSig, noDollar);
1196                            } while (qualifiedTypeSig.charAt(i) != Signature.C_GENERIC_END);
1197                            unqualifiedTypeSig.append(Signature.C_GENERIC_END);
1198                            break;
1199                        case Signature.C_NAME_END:
1200                            unqualifiedTypeSig.append(current);
1201                            return i + 1;
1202                        default:
1203                            unqualifiedTypeSig.append(current);
1204                            break;
1205                    }
1206                }
1207                return length;
1208            default :
1209                // primitive type or wildcard
1210
unqualifiedTypeSig.append(qualifiedTypeSig.substring(start, end));
1211                return end;
1212        }
1213    }
1214        
1215    /**
1216     * Maps the given source code to the given binary type and its children.
1217     */

1218    public void mapSource(IType type, char[] contents, IBinaryType info) {
1219        this.mapSource(type, contents, info, null);
1220    }
1221    
1222    /**
1223     * Maps the given source code to the given binary type and its children.
1224     * If a non-null java element is passed, finds the name range for the
1225     * given java element without storing it.
1226     */

1227    public synchronized ISourceRange mapSource(
1228        IType type,
1229        char[] contents,
1230        IBinaryType info,
1231        IJavaElement elementToFind) {
1232            
1233        this.binaryType = (BinaryType) type;
1234        
1235        // check whether it is already mapped
1236
if (this.sourceRanges.get(type) != null) return (elementToFind != null) ? getNameRange(elementToFind) : null;
1237        
1238        this.importsTable.remove(this.binaryType);
1239        this.importsCounterTable.remove(this.binaryType);
1240        this.searchedElement = elementToFind;
1241        this.types = new IType[1];
1242        this.typeDeclarationStarts = new int[1];
1243        this.typeNameRanges = new SourceRange[1];
1244        this.typeModifiers = new int[1];
1245        this.typeDepth = -1;
1246        this.memberDeclarationStart = new int[1];
1247        this.memberName = new String JavaDoc[1];
1248        this.memberNameRange = new SourceRange[1];
1249        this.methodParameterTypes = new char[1][][];
1250        this.methodParameterNames = new char[1][][];
1251        this.anonymousCounter = 0;
1252        
1253        HashMap JavaDoc oldSourceRanges = (HashMap JavaDoc) this.sourceRanges.clone();
1254        try {
1255            IProblemFactory factory = new DefaultProblemFactory();
1256            SourceElementParser parser = null;
1257            this.anonymousClassName = 0;
1258            if (info == null) {
1259                try {
1260                    info = (IBinaryType) this.binaryType.getElementInfo();
1261                } catch(JavaModelException e) {
1262                    return null;
1263                }
1264            }
1265            boolean isAnonymousClass = info.isAnonymous();
1266            char[] fullName = info.getName();
1267            if (isAnonymousClass) {
1268                String JavaDoc eltName = this.binaryType.getParent().getElementName();
1269                eltName = eltName.substring(eltName.lastIndexOf('$') + 1, eltName.length());
1270                try {
1271                    this.anonymousClassName = Integer.parseInt(eltName);
1272                } catch(NumberFormatException JavaDoc e) {
1273                    // ignore
1274
}
1275            }
1276            boolean doFullParse = hasToRetrieveSourceRangesForLocalClass(fullName);
1277            parser = new SourceElementParser(this, factory, new CompilerOptions(this.options), doFullParse, true/*optimize string literals*/);
1278            parser.javadocParser.checkDocComment = false; // disable javadoc parsing
1279
IJavaElement javaElement = this.binaryType.getCompilationUnit();
1280            if (javaElement == null) javaElement = this.binaryType.getParent();
1281            parser.parseCompilationUnit(
1282                new BasicCompilationUnit(contents, null, this.binaryType.sourceFileName(info), javaElement),
1283                doFullParse);
1284            if (elementToFind != null) {
1285                ISourceRange range = this.getNameRange(elementToFind);
1286                return range;
1287            } else {
1288                return null;
1289            }
1290        } finally {
1291            if (elementToFind != null) {
1292                this.sourceRanges = oldSourceRanges;
1293            }
1294            this.binaryType = null;
1295            this.searchedElement = null;
1296            this.types = null;
1297            this.typeDeclarationStarts = null;
1298            this.typeNameRanges = null;
1299            this.typeDepth = -1;
1300        }
1301    }
1302    private char[] readSource(ZipEntry JavaDoc entry, ZipFile JavaDoc zip) {
1303        try {
1304            byte[] bytes = Util.getZipEntryByteContent(entry, zip);
1305            if (bytes != null) {
1306                return Util.bytesToChar(bytes, this.encoding);
1307            }
1308        } catch (IOException JavaDoc e) {
1309            // ignore
1310
}
1311        return null;
1312    }
1313    
1314    /**
1315     * Sets the mapping for this method to its parameter names.
1316     *
1317     * @see #parameterNames
1318     */

1319    protected void setMethodParameterNames(
1320        IMethod method,
1321        char[][] parameterNames) {
1322        if (parameterNames == null) {
1323            parameterNames = CharOperation.NO_CHAR_CHAR;
1324        }
1325        this.parameterNames.put(method, parameterNames);
1326    }
1327    
1328    /**
1329     * Sets the mapping for this element to its source ranges for its source range
1330     * and name range.
1331     *
1332     * @see #sourceRanges
1333     */

1334    protected void setSourceRange(
1335        IJavaElement element,
1336        SourceRange sourceRange,
1337        SourceRange nameRange) {
1338        this.sourceRanges.put(element, new SourceRange[] { sourceRange, nameRange });
1339    }
1340
1341    /**
1342     * Return a char[][] array containing the imports of the attached source for the binary type
1343     */

1344    public char[][] getImports(BinaryType type) {
1345        char[][] imports = (char[][]) this.importsTable.get(type);
1346        if (imports != null) {
1347            int importsCounter = ((Integer JavaDoc) this.importsCounterTable.get(type)).intValue();
1348            if (imports.length != importsCounter) {
1349                System.arraycopy(
1350                    imports,
1351                    0,
1352                    (imports = new char[importsCounter][]),
1353                    0,
1354                    importsCounter);
1355            }
1356            this.importsTable.put(type, imports);
1357        }
1358        return imports;
1359    }
1360    
1361    private boolean hasToRetrieveSourceRangesForLocalClass(char[] eltName) {
1362        /*
1363         * A$1$B$2 : true
1364         * A$B$B$2 : true
1365         * A$C$B$D : false
1366         * A$F$B$D$1$F : true
1367         * A$F$B$D$1F : true
1368         * A$1 : true
1369         * A$B : false
1370         */

1371        if (eltName == null) return false;
1372        int length = eltName.length;
1373        int dollarIndex = CharOperation.indexOf('$', eltName, 0);
1374        while (dollarIndex != -1) {
1375            int nameStart = dollarIndex+1;
1376            if (nameStart == length) return false;
1377            if (Character.isDigit(eltName[nameStart]))
1378                return true;
1379            dollarIndex = CharOperation.indexOf('$', eltName, nameStart);
1380        }
1381        return false;
1382    }
1383    
1384}
1385
Popular Tags