/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.core.builder; import java.util.ArrayList; import net.sourceforge.phpdt.core.IClasspathEntry; //import net.sourceforge.phpdt.core.IJavaProject; import net.sourceforge.phpdt.core.JavaCore; import net.sourceforge.phpdt.core.compiler.CharOperation; import net.sourceforge.phpdt.internal.compiler.env.INameEnvironment; import net.sourceforge.phpdt.internal.compiler.env.NameEnvironmentAnswer; import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation; import net.sourceforge.phpdt.internal.core.ClasspathEntry; import net.sourceforge.phpdt.internal.core.JavaModel; import net.sourceforge.phpdt.internal.core.JavaProject; import net.sourceforge.phpdt.internal.core.util.SimpleLookupTable; import org.eclipse.core.resources.IContainer; //import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; public class NameEnvironment implements INameEnvironment { boolean isIncrementalBuild; ClasspathMultiDirectory[] sourceLocations; // ClasspathLocation[] binaryLocations; String[] initialTypeNames; // assumed that each name is of the form // "a/b/ClassName" SourceFile[] additionalUnits; NameEnvironment(IWorkspaceRoot root, JavaProject javaProject, SimpleLookupTable binaryLocationsPerProject) throws CoreException { this.isIncrementalBuild = false; // this.sourceLocations = new ClasspathMultiDirectory[0]; computeClasspathLocations(root, javaProject, binaryLocationsPerProject); setNames(null, null); } // public NameEnvironment(IJavaProject javaProject) { // this.isIncrementalBuild = false; // try { // computeClasspathLocations(javaProject.getProject().getWorkspace() // .getRoot(), (JavaProject) javaProject, null); // } catch (CoreException e) { // // this.sourceLocations = new ClasspathMultiDirectory[0]; // // this.binaryLocations = new ClasspathLocation[0]; // } // setNames(null, null); // } /* * Some examples of resolved class path entries. Remember to search class * path in the order that it was defined. * * 1a. typical project with no source folders: /Test[CPE_SOURCE][K_SOURCE] -> * D:/eclipse.test/Test 1b. project with source folders: * /Test/src1[CPE_SOURCE][K_SOURCE] -> D:/eclipse.test/Test/src1 * /Test/src2[CPE_SOURCE][K_SOURCE] -> D:/eclipse.test/Test/src2 NOTE: These * can be in any order & separated by prereq projects or libraries 1c. * project external to workspace (only detectable using getLocation()): * /Test/src[CPE_SOURCE][K_SOURCE] -> d:/eclipse.zzz/src Need to search * source folder & output folder * * 2. zip files: * D:/j9/lib/jclMax/classes.zip[CPE_LIBRARY][K_BINARY][sourcePath:d:/j9/lib/jclMax/source/source.zip] -> * D:/j9/lib/jclMax/classes.zip ALWAYS want to take the library path as is * * 3a. prereq project (regardless of whether it has a source or output * folder): /Test[CPE_PROJECT][K_SOURCE] -> D:/eclipse.test/Test ALWAYS want * to append the output folder & ONLY search for .class files */ private void computeClasspathLocations(IWorkspaceRoot root, JavaProject javaProject, SimpleLookupTable binaryLocationsPerProject) throws CoreException { /* Update cycle marker */ IMarker cycleMarker = javaProject.getCycleMarker(); if (cycleMarker != null) { int severity = JavaCore.ERROR.equals(javaProject.getOption( JavaCore.CORE_CIRCULAR_CLASSPATH, true)) ? IMarker.SEVERITY_ERROR : IMarker.SEVERITY_WARNING; if (severity != ((Integer) cycleMarker .getAttribute(IMarker.SEVERITY)).intValue()) cycleMarker.setAttribute(IMarker.SEVERITY, severity); } /* Update incomplete classpath marker */ // IClasspathEntry[] classpathEntries = // javaProject.getExpandedClasspath(true, true); IClasspathEntry[] classpathEntries = javaProject .getExpandedClasspath(true/* ignore unresolved variable */, false/* don't create markers */, null/* preferred cp */, null/* preferred output */); ArrayList sLocations = new ArrayList(classpathEntries.length); ArrayList bLocations = new ArrayList(classpathEntries.length); nextEntry: for (int i = 0, l = classpathEntries.length; i < l; i++) { ClasspathEntry entry = (ClasspathEntry) classpathEntries[i]; IPath path = entry.getPath(); Object target = JavaModel.getTarget(root, path, true); if (target == null) continue nextEntry; switch (entry.getEntryKind()) { case IClasspathEntry.CPE_SOURCE: if (!(target instanceof IContainer)) continue nextEntry; // IPath outputPath = entry.getOutputLocation() != null // ? entry.getOutputLocation() // : javaProject.getOutputLocation(); IContainer outputFolder = null; // if (outputPath.segmentCount() == 1) { // outputFolder = javaProject.getProject(); // } else { // outputFolder = root.getFolder(outputPath); // if (!outputFolder.exists()) // createFolder(outputFolder); // } sLocations.add(ClasspathLocation.forSourceFolder( (IContainer) target, outputFolder, entry .fullExclusionPatternChars())); continue nextEntry; case IClasspathEntry.CPE_PROJECT: if (!(target instanceof IProject)) continue nextEntry; IProject prereqProject = (IProject) target; if (!JavaProject.hasJavaNature(prereqProject)) continue nextEntry; // if project doesn't have java nature // or is not accessible JavaProject prereqJavaProject = (JavaProject) JavaCore .create(prereqProject); IClasspathEntry[] prereqClasspathEntries = prereqJavaProject .getRawClasspath(); ArrayList seen = new ArrayList(); nextPrereqEntry: for (int j = 0, m = prereqClasspathEntries.length; j < m; j++) { IClasspathEntry prereqEntry = (IClasspathEntry) prereqClasspathEntries[j]; if (prereqEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { Object prereqTarget = JavaModel.getTarget(root, prereqEntry.getPath(), true); if (!(prereqTarget instanceof IContainer)) continue nextPrereqEntry; IPath prereqOutputPath = prereqEntry .getOutputLocation() != null ? prereqEntry .getOutputLocation() : prereqJavaProject .getOutputLocation(); IContainer binaryFolder = prereqOutputPath .segmentCount() == 1 ? (IContainer) prereqProject : (IContainer) root.getFolder(prereqOutputPath); if (binaryFolder.exists() && !seen.contains(binaryFolder)) { seen.add(binaryFolder); ClasspathLocation bLocation = ClasspathLocation .forBinaryFolder(binaryFolder, true); bLocations.add(bLocation); if (binaryLocationsPerProject != null) { // normal // builder // mode ClasspathLocation[] existingLocations = (ClasspathLocation[]) binaryLocationsPerProject .get(prereqProject); if (existingLocations == null) { existingLocations = new ClasspathLocation[] { bLocation }; } else { int size = existingLocations.length; System .arraycopy( existingLocations, 0, existingLocations = new ClasspathLocation[size + 1], 0, size); existingLocations[size] = bLocation; } binaryLocationsPerProject.put(prereqProject, existingLocations); } } } } continue nextEntry; // case IClasspathEntry.CPE_LIBRARY : // if (target instanceof IResource) { // IResource resource = (IResource) target; // ClasspathLocation bLocation = null; // if (resource instanceof IFile) { // if (!(ProjectPrefUtil.isArchiveFileName(path.lastSegment()))) // continue nextEntry; // bLocation = ClasspathLocation.forLibrary((IFile) resource); // } else if (resource instanceof IContainer) { // bLocation = ClasspathLocation.forBinaryFolder((IContainer) // target, false); // is library folder not output folder // } // bLocations.add(bLocation); // if (binaryLocationsPerProject != null) { // normal builder // mode // IProject p = resource.getProject(); // can be the project // being built // ClasspathLocation[] existingLocations = (ClasspathLocation[]) // binaryLocationsPerProject.get(p); // if (existingLocations == null) { // existingLocations = new ClasspathLocation[] {bLocation}; // } else { // int size = existingLocations.length; // System.arraycopy(existingLocations, 0, existingLocations = // new ClasspathLocation[size + 1], 0, size); // existingLocations[size] = bLocation; // } // binaryLocationsPerProject.put(p, existingLocations); // } // } else if (target instanceof File) { // if (!(ProjectPrefUtil.isArchiveFileName(path.lastSegment()))) // continue nextEntry; // bLocations.add(ClasspathLocation.forLibrary(path.toString())); // } // continue nextEntry; } } // now split the classpath locations... place the output folders ahead // of the other .class file folders & jars ArrayList outputFolders = new ArrayList(1); this.sourceLocations = new ClasspathMultiDirectory[sLocations.size()]; if (!sLocations.isEmpty()) { sLocations.toArray(this.sourceLocations); // collect the output folders, skipping duplicates next: for (int i = 0, l = sourceLocations.length; i < l; i++) { ClasspathMultiDirectory md = sourceLocations[i]; // IPath outputPath = md.binaryFolder.getFullPath(); // for (int j = 0; j < i; j++) { // compare against previously // walked source folders // if // (outputPath.equals(sourceLocations[j].binaryFolder.getFullPath())) // { // md.hasIndependentOutputFolder = // sourceLocations[j].hasIndependentOutputFolder; // continue next; // } // } outputFolders.add(md); // also tag each source folder whose output folder is an // independent folder & is not also a source folder // for (int j = 0, m = sourceLocations.length; j < m; j++) // if // (outputPath.equals(sourceLocations[j].sourceFolder.getFullPath())) // continue next; md.hasIndependentOutputFolder = true; } } // combine the output folders with the binary folders & jars... place // the output folders before other .class file folders & jars // this.binaryLocations = new ClasspathLocation[outputFolders.size() + // bLocations.size()]; // int index = 0; // for (int i = 0, l = outputFolders.size(); i < l; i++) // this.binaryLocations[index++] = (ClasspathLocation) // outputFolders.get(i); // for (int i = 0, l = bLocations.size(); i < l; i++) // this.binaryLocations[index++] = (ClasspathLocation) // bLocations.get(i); } public void cleanup() { this.initialTypeNames = null; this.additionalUnits = null; for (int i = 0, l = sourceLocations.length; i < l; i++) sourceLocations[i].cleanup(); // for (int i = 0, l = binaryLocations.length; i < l; i++) // binaryLocations[i].cleanup(); } // private void createFolder(IContainer folder) throws CoreException { // if (!folder.exists()) { // createFolder(folder.getParent()); // ((IFolder) folder).create(true, true, null); // } // } private NameEnvironmentAnswer findClass(String qualifiedTypeName, char[] typeName) { if (initialTypeNames != null) { for (int i = 0, l = initialTypeNames.length; i < l; i++) { if (qualifiedTypeName.equals(initialTypeNames[i])) { if (isIncrementalBuild) // catch the case that a type inside a source file has // been renamed but other class files are looking for it throw new AbortCompilation(true, new AbortIncrementalBuildException( qualifiedTypeName)); return null; // looking for a file which we know was // provided at the beginning of the // compilation } } } if (additionalUnits != null && sourceLocations.length > 0) { // if an additional source file is waiting to be compiled, answer it // BUT not if this is a secondary type search // if we answer X.java & it no longer defines Y then the binary type // looking for Y will think the class path is wrong // let the recompile loop fix up dependents when the secondary type // Y has been deleted from X.java IPath qSourceFilePath = new Path(qualifiedTypeName + ".java"); //$NON-NLS-1$ int qSegmentCount = qSourceFilePath.segmentCount(); next: for (int i = 0, l = additionalUnits.length; i < l; i++) { SourceFile additionalUnit = additionalUnits[i]; IPath fullPath = additionalUnit.resource.getFullPath(); int prefixCount = additionalUnit.sourceLocation.sourceFolder .getFullPath().segmentCount(); if (qSegmentCount == fullPath.segmentCount() - prefixCount) { for (int j = 0; j < qSegmentCount; j++) if (!qSourceFilePath.segment(j).equals( fullPath.segment(j + prefixCount))) continue next; return new NameEnvironmentAnswer(additionalUnit); } } } // String qBinaryFileName = qualifiedTypeName + ".class"; //$NON-NLS-1$ // String binaryFileName = qBinaryFileName; // String qPackageName = ""; //$NON-NLS-1$ // if (qualifiedTypeName.length() > typeName.length) { // int typeNameStart = qBinaryFileName.length() - typeName.length - 6; // // size of ".class" // qPackageName = qBinaryFileName.substring(0, typeNameStart - 1); // binaryFileName = qBinaryFileName.substring(typeNameStart); // } // // // NOTE: the output folders are added at the beginning of the // binaryLocations // for (int i = 0, l = binaryLocations.length; i < l; i++) { // NameEnvironmentAnswer answer = // binaryLocations[i].findClass(binaryFileName, qPackageName, // qBinaryFileName); // if (answer != null) return answer; // } return null; } public NameEnvironmentAnswer findType(char[][] compoundName) { if (compoundName != null) return findClass(new String(CharOperation.concatWith(compoundName, '/')), compoundName[compoundName.length - 1]); return null; } public NameEnvironmentAnswer findType(char[] typeName, char[][] packageName) { if (typeName != null) return findClass(new String(CharOperation.concatWith(packageName, typeName, '/')), typeName); return null; } public boolean isPackage(char[][] compoundName, char[] packageName) { return isPackage(new String(CharOperation.concatWith(compoundName, packageName, '/'))); } public boolean isPackage(String qualifiedPackageName) { // NOTE: the output folders are added at the beginning of the // binaryLocations // for (int i = 0, l = binaryLocations.length; i < l; i++) // if (binaryLocations[i].isPackage(qualifiedPackageName)) // return true; return false; } void setNames(String[] initialTypeNames, SourceFile[] additionalUnits) { this.initialTypeNames = initialTypeNames; this.additionalUnits = additionalUnits; for (int i = 0, l = sourceLocations.length; i < l; i++) sourceLocations[i].reset(); // for (int i = 0, l = binaryLocations.length; i < l; i++) // binaryLocations[i].reset(); } }