KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > builder > NameEnvironment


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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.builder;
12
13 import org.eclipse.core.resources.*;
14 import org.eclipse.core.runtime.*;
15
16 import org.eclipse.jdt.core.*;
17 import org.eclipse.jdt.core.compiler.CharOperation;
18 import org.eclipse.jdt.internal.compiler.env.*;
19 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
20 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
21 import org.eclipse.jdt.internal.compiler.util.SimpleSet;
22 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
23 import org.eclipse.jdt.internal.core.*;
24
25 import java.io.*;
26 import java.util.*;
27
28 public class NameEnvironment implements INameEnvironment, SuffixConstants {
29
30 boolean isIncrementalBuild;
31 ClasspathMultiDirectory[] sourceLocations;
32 ClasspathLocation[] binaryLocations;
33 BuildNotifier notifier;
34
35 SimpleSet initialTypeNames; // assumed that each name is of the form "a/b/ClassName"
36
SimpleLookupTable additionalUnits;
37
38 NameEnvironment(IWorkspaceRoot root, JavaProject javaProject, SimpleLookupTable binaryLocationsPerProject, BuildNotifier notifier) throws CoreException {
39     this.isIncrementalBuild = false;
40     this.notifier = notifier;
41     computeClasspathLocations(root, javaProject, binaryLocationsPerProject);
42     setNames(null, null);
43 }
44
45 public NameEnvironment(IJavaProject javaProject) {
46     this.isIncrementalBuild = false;
47     try {
48         computeClasspathLocations(javaProject.getProject().getWorkspace().getRoot(), (JavaProject) javaProject, null);
49     } catch(CoreException e) {
50         this.sourceLocations = new ClasspathMultiDirectory[0];
51         this.binaryLocations = new ClasspathLocation[0];
52     }
53     setNames(null, null);
54 }
55
56 /* Some examples of resolved class path entries.
57 * Remember to search class path in the order that it was defined.
58 *
59 * 1a. typical project with no source folders:
60 * /Test[CPE_SOURCE][K_SOURCE] -> D:/eclipse.test/Test
61 * 1b. project with source folders:
62 * /Test/src1[CPE_SOURCE][K_SOURCE] -> D:/eclipse.test/Test/src1
63 * /Test/src2[CPE_SOURCE][K_SOURCE] -> D:/eclipse.test/Test/src2
64 * NOTE: These can be in any order & separated by prereq projects or libraries
65 * 1c. project external to workspace (only detectable using getLocation()):
66 * /Test/src[CPE_SOURCE][K_SOURCE] -> d:/eclipse.zzz/src
67 * Need to search source folder & output folder
68 *
69 * 2. zip files:
70 * D:/j9/lib/jclMax/classes.zip[CPE_LIBRARY][K_BINARY][sourcePath:d:/j9/lib/jclMax/source/source.zip]
71 * -> D:/j9/lib/jclMax/classes.zip
72 * ALWAYS want to take the library path as is
73 *
74 * 3a. prereq project (regardless of whether it has a source or output folder):
75 * /Test[CPE_PROJECT][K_SOURCE] -> D:/eclipse.test/Test
76 * ALWAYS want to append the output folder & ONLY search for .class files
77 */

78 private void computeClasspathLocations(
79     IWorkspaceRoot root,
80     JavaProject javaProject,
81     SimpleLookupTable binaryLocationsPerProject) throws CoreException {
82
83     /* Update cycle marker */
84     IMarker cycleMarker = javaProject.getCycleMarker();
85     if (cycleMarker != null) {
86         int severity = JavaCore.ERROR.equals(javaProject.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true))
87             ? IMarker.SEVERITY_ERROR
88             : IMarker.SEVERITY_WARNING;
89         if (severity != cycleMarker.getAttribute(IMarker.SEVERITY, severity))
90             cycleMarker.setAttribute(IMarker.SEVERITY, severity);
91     }
92
93     IClasspathEntry[] classpathEntries = javaProject.getExpandedClasspath();
94     ArrayList sLocations = new ArrayList(classpathEntries.length);
95     ArrayList bLocations = new ArrayList(classpathEntries.length);
96     nextEntry : for (int i = 0, l = classpathEntries.length; i < l; i++) {
97         ClasspathEntry entry = (ClasspathEntry) classpathEntries[i];
98         IPath path = entry.getPath();
99         Object JavaDoc target = JavaModel.getTarget(root, path, true);
100         if (target == null) continue nextEntry;
101
102         switch(entry.getEntryKind()) {
103             case IClasspathEntry.CPE_SOURCE :
104                 if (!(target instanceof IContainer)) continue nextEntry;
105                 IPath outputPath = entry.getOutputLocation() != null
106                     ? entry.getOutputLocation()
107                     : javaProject.getOutputLocation();
108                 IContainer outputFolder;
109                 if (outputPath.segmentCount() == 1) {
110                     outputFolder = javaProject.getProject();
111                 } else {
112                     outputFolder = root.getFolder(outputPath);
113                     if (!outputFolder.exists())
114                         createOutputFolder(outputFolder);
115                 }
116                 sLocations.add(
117                     ClasspathLocation.forSourceFolder((IContainer) target, outputFolder, entry.fullInclusionPatternChars(), entry.fullExclusionPatternChars()));
118                 continue nextEntry;
119
120             case IClasspathEntry.CPE_PROJECT :
121                 if (!(target instanceof IProject)) continue nextEntry;
122                 IProject prereqProject = (IProject) target;
123                 if (!JavaProject.hasJavaNature(prereqProject)) continue nextEntry; // if project doesn't have java nature or is not accessible
124

125                 JavaProject prereqJavaProject = (JavaProject) JavaCore.create(prereqProject);
126                 IClasspathEntry[] prereqClasspathEntries = prereqJavaProject.getRawClasspath();
127                 ArrayList seen = new ArrayList();
128                 nextPrereqEntry: for (int j = 0, m = prereqClasspathEntries.length; j < m; j++) {
129                     IClasspathEntry prereqEntry = prereqClasspathEntries[j];
130                     if (prereqEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
131                         Object JavaDoc prereqTarget = JavaModel.getTarget(root, prereqEntry.getPath(), true);
132                         if (!(prereqTarget instanceof IContainer)) continue nextPrereqEntry;
133                         IPath prereqOutputPath = prereqEntry.getOutputLocation() != null
134                             ? prereqEntry.getOutputLocation()
135                             : prereqJavaProject.getOutputLocation();
136                         IContainer binaryFolder = prereqOutputPath.segmentCount() == 1
137                             ? (IContainer) prereqProject
138                             : (IContainer) root.getFolder(prereqOutputPath);
139                         if (binaryFolder.exists() && !seen.contains(binaryFolder)) {
140                             seen.add(binaryFolder);
141                             ClasspathLocation bLocation = ClasspathLocation.forBinaryFolder(binaryFolder, true, entry.getAccessRuleSet());
142                             bLocations.add(bLocation);
143                             if (binaryLocationsPerProject != null) { // normal builder mode
144
ClasspathLocation[] existingLocations = (ClasspathLocation[]) binaryLocationsPerProject.get(prereqProject);
145                                 if (existingLocations == null) {
146                                     existingLocations = new ClasspathLocation[] {bLocation};
147                                 } else {
148                                     int size = existingLocations.length;
149                                     System.arraycopy(existingLocations, 0, existingLocations = new ClasspathLocation[size + 1], 0, size);
150                                     existingLocations[size] = bLocation;
151                                 }
152                                 binaryLocationsPerProject.put(prereqProject, existingLocations);
153                             }
154                         }
155                     }
156                 }
157                 continue nextEntry;
158
159             case IClasspathEntry.CPE_LIBRARY :
160                 if (target instanceof IResource) {
161                     IResource resource = (IResource) target;
162                     ClasspathLocation bLocation = null;
163                     if (resource instanceof IFile) {
164                         if (!(org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(path.lastSegment())))
165                             continue nextEntry;
166                         AccessRuleSet accessRuleSet =
167                             (JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, true))
168                             && JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true)))
169                                 ? null
170                                 : entry.getAccessRuleSet();
171                         bLocation = ClasspathLocation.forLibrary((IFile) resource, accessRuleSet);
172                     } else if (resource instanceof IContainer) {
173                         AccessRuleSet accessRuleSet =
174                             (JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, true))
175                             && JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true)))
176                                 ? null
177                                 : entry.getAccessRuleSet();
178                         bLocation = ClasspathLocation.forBinaryFolder((IContainer) target, false, accessRuleSet); // is library folder not output folder
179
}
180                     bLocations.add(bLocation);
181                     if (binaryLocationsPerProject != null) { // normal builder mode
182
IProject p = resource.getProject(); // can be the project being built
183
ClasspathLocation[] existingLocations = (ClasspathLocation[]) binaryLocationsPerProject.get(p);
184                         if (existingLocations == null) {
185                             existingLocations = new ClasspathLocation[] {bLocation};
186                         } else {
187                             int size = existingLocations.length;
188                             System.arraycopy(existingLocations, 0, existingLocations = new ClasspathLocation[size + 1], 0, size);
189                             existingLocations[size] = bLocation;
190                         }
191                         binaryLocationsPerProject.put(p, existingLocations);
192                     }
193                 } else if (target instanceof File) {
194                     if (!(org.eclipse.jdt.internal.compiler.util.Util.isArchiveFileName(path.lastSegment())))
195                         continue nextEntry;
196                     AccessRuleSet accessRuleSet =
197                         (JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE, true))
198                             && JavaCore.IGNORE.equals(javaProject.getOption(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE, true)))
199                                 ? null
200                                 : entry.getAccessRuleSet();
201                     bLocations.add(ClasspathLocation.forLibrary(path.toString(), accessRuleSet));
202                 }
203                 continue nextEntry;
204         }
205     }
206
207     // now split the classpath locations... place the output folders ahead of the other .class file folders & jars
208
ArrayList outputFolders = new ArrayList(1);
209     this.sourceLocations = new ClasspathMultiDirectory[sLocations.size()];
210     if (!sLocations.isEmpty()) {
211         sLocations.toArray(this.sourceLocations);
212
213         // collect the output folders, skipping duplicates
214
next : for (int i = 0, l = sourceLocations.length; i < l; i++) {
215             ClasspathMultiDirectory md = sourceLocations[i];
216             IPath outputPath = md.binaryFolder.getFullPath();
217             for (int j = 0; j < i; j++) { // compare against previously walked source folders
218
if (outputPath.equals(sourceLocations[j].binaryFolder.getFullPath())) {
219                     md.hasIndependentOutputFolder = sourceLocations[j].hasIndependentOutputFolder;
220                     continue next;
221                 }
222             }
223             outputFolders.add(md);
224
225             // also tag each source folder whose output folder is an independent folder & is not also a source folder
226
for (int j = 0, m = sourceLocations.length; j < m; j++)
227                 if (outputPath.equals(sourceLocations[j].sourceFolder.getFullPath()))
228                     continue next;
229             md.hasIndependentOutputFolder = true;
230         }
231     }
232
233     // combine the output folders with the binary folders & jars... place the output folders before other .class file folders & jars
234
this.binaryLocations = new ClasspathLocation[outputFolders.size() + bLocations.size()];
235     int index = 0;
236     for (int i = 0, l = outputFolders.size(); i < l; i++)
237         this.binaryLocations[index++] = (ClasspathLocation) outputFolders.get(i);
238     for (int i = 0, l = bLocations.size(); i < l; i++)
239         this.binaryLocations[index++] = (ClasspathLocation) bLocations.get(i);
240 }
241
242 public void cleanup() {
243     this.initialTypeNames = null;
244     this.additionalUnits = null;
245     for (int i = 0, l = sourceLocations.length; i < l; i++)
246         sourceLocations[i].cleanup();
247     for (int i = 0, l = binaryLocations.length; i < l; i++)
248         binaryLocations[i].cleanup();
249 }
250
251 private void createOutputFolder(IContainer outputFolder) throws CoreException {
252     createParentFolder(outputFolder.getParent());
253     ((IFolder) outputFolder).create(IResource.FORCE | IResource.DERIVED, true, null);
254 }
255
256 private void createParentFolder(IContainer parent) throws CoreException {
257     if (!parent.exists()) {
258         createParentFolder(parent.getParent());
259         ((IFolder) parent).create(true, true, null);
260     }
261 }
262
263 private NameEnvironmentAnswer findClass(String JavaDoc qualifiedTypeName, char[] typeName) {
264     if (this.notifier != null)
265         this.notifier.checkCancelWithinCompiler();
266
267     if (this.initialTypeNames != null && this.initialTypeNames.includes(qualifiedTypeName)) {
268         if (isIncrementalBuild)
269             // catch the case that a type inside a source file has been renamed but other class files are looking for it
270
throw new AbortCompilation(true, new AbortIncrementalBuildException(qualifiedTypeName));
271         return null; // looking for a file which we know was provided at the beginning of the compilation
272
}
273
274     if (this.additionalUnits != null && this.sourceLocations.length > 0) {
275         // if an additional source file is waiting to be compiled, answer it BUT not if this is a secondary type search
276
// if we answer X.java & it no longer defines Y then the binary type looking for Y will think the class path is wrong
277
// let the recompile loop fix up dependents when the secondary type Y has been deleted from X.java
278
SourceFile unit = (SourceFile) this.additionalUnits.get(qualifiedTypeName); // doesn't have file extension
279
if (unit != null)
280             return new NameEnvironmentAnswer(unit, null /*no access restriction*/);
281     }
282
283     String JavaDoc qBinaryFileName = qualifiedTypeName + SUFFIX_STRING_class;
284     String JavaDoc binaryFileName = qBinaryFileName;
285     String JavaDoc qPackageName = ""; //$NON-NLS-1$
286
if (qualifiedTypeName.length() > typeName.length) {
287         int typeNameStart = qBinaryFileName.length() - typeName.length - 6; // size of ".class"
288
qPackageName = qBinaryFileName.substring(0, typeNameStart - 1);
289         binaryFileName = qBinaryFileName.substring(typeNameStart);
290     }
291
292     // NOTE: the output folders are added at the beginning of the binaryLocations
293
NameEnvironmentAnswer suggestedAnswer = null;
294     for (int i = 0, l = binaryLocations.length; i < l; i++) {
295         NameEnvironmentAnswer answer = binaryLocations[i].findClass(binaryFileName, qPackageName, qBinaryFileName);
296         if (answer != null) {
297             if (!answer.ignoreIfBetter()) {
298                 if (answer.isBetter(suggestedAnswer))
299                     return answer;
300             } else if (answer.isBetter(suggestedAnswer))
301                 // remember suggestion and keep looking
302
suggestedAnswer = answer;
303         }
304     }
305     if (suggestedAnswer != null)
306         // no better answer was found
307
return suggestedAnswer;
308     return null;
309 }
310
311 public NameEnvironmentAnswer findType(char[][] compoundName) {
312     if (compoundName != null)
313         return findClass(
314             new String JavaDoc(CharOperation.concatWith(compoundName, '/')),
315             compoundName[compoundName.length - 1]);
316     return null;
317 }
318
319 public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) {
320     if (typeName != null)
321         return findClass(
322             new String JavaDoc(CharOperation.concatWith(packageName, typeName, '/')),
323             typeName);
324     return null;
325 }
326
327 public boolean isPackage(char[][] compoundName, char[] packageName) {
328     return isPackage(new String JavaDoc(CharOperation.concatWith(compoundName, packageName, '/')));
329 }
330
331 public boolean isPackage(String JavaDoc qualifiedPackageName) {
332     // NOTE: the output folders are added at the beginning of the binaryLocations
333
for (int i = 0, l = binaryLocations.length; i < l; i++)
334         if (binaryLocations[i].isPackage(qualifiedPackageName))
335             return true;
336     return false;
337 }
338
339 void setNames(String JavaDoc[] typeNames, SourceFile[] additionalFiles) {
340     // convert the initial typeNames to a set
341
if (typeNames == null) {
342         this.initialTypeNames = null;
343     } else {
344         this.initialTypeNames = new SimpleSet(typeNames.length);
345         for (int i = 0, l = typeNames.length; i < l; i++)
346             this.initialTypeNames.add(typeNames[i]);
347     }
348     // map the additional source files by qualified type name
349
if (additionalFiles == null) {
350         this.additionalUnits = null;
351     } else {
352         this.additionalUnits = new SimpleLookupTable(additionalFiles.length);
353         for (int i = 0, l = additionalFiles.length; i < l; i++) {
354             SourceFile additionalUnit = additionalFiles[i];
355             if (additionalUnit != null)
356                 this.additionalUnits.put(additionalUnit.initialTypeName, additionalFiles[i]);
357         }
358     }
359
360     for (int i = 0, l = sourceLocations.length; i < l; i++)
361         sourceLocations[i].reset();
362     for (int i = 0, l = binaryLocations.length; i < l; i++)
363         binaryLocations[i].reset();
364 }
365 }
366
Popular Tags