All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.umd.cs.findbugs.Project Maven / Gradle / Ivy

There is a newer version: 4.8.6
Show newest version
/*
 * FindBugs - Find bugs in Java programs
 * Copyright (C) 2003-2005 University of Maryland
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/*
 * Project.java
 *
 * Created on March 30, 2003, 2:22 PM
 */

package edu.umd.cs.findbugs;

import static edu.umd.cs.findbugs.xml.XMLOutputUtil.writeElementList;
import static edu.umd.cs.findbugs.xml.XMLOutputUtil.writeFileList;
import static java.util.Objects.requireNonNull;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.Manifest;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import edu.umd.cs.findbugs.ba.SourceFinder;
import edu.umd.cs.findbugs.ba.URLClassPath;
import edu.umd.cs.findbugs.charsets.UTF8;
import edu.umd.cs.findbugs.config.UserPreferences;
import edu.umd.cs.findbugs.filter.Filter;
import edu.umd.cs.findbugs.io.IO;
import edu.umd.cs.findbugs.util.Util;
import edu.umd.cs.findbugs.xml.OutputStreamXMLOutput;
import edu.umd.cs.findbugs.xml.XMLAttributeList;
import edu.umd.cs.findbugs.xml.XMLOutput;
import edu.umd.cs.findbugs.xml.XMLWriteable;

/**
 * 

A project in the GUI. This consists of some number of Jar files to analyze * for bugs, and optionally *

*
    *
  • some number of source directories, for locating the program's source code
  • *
  • some number of auxiliary classpath entries, for locating classes * referenced by the program which the user doesn't want to analyze
  • *
  • some number of boolean options
  • *
* * @author David Hovemeyer */ public class Project implements XMLWriteable, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(Project.class); private final List currentWorkingDirectoryList; private String projectName; /** * List of jars/directories to analyze */ private List analysisTargets; /** * The list of source directories. */ private List srcDirList; /** * The list of auxiliary classpath entries. */ private List auxClasspathEntryList; /** * Flag to indicate that this Project has been modified. */ private boolean isModified; private UserPreferences configuration; /** key is plugin id */ private final Map enabledPlugins; @CheckForNull public Boolean getPluginStatus(Plugin plugin) { return enabledPlugins.get(plugin.getPluginId()); } public void setPluginStatusTrinary(String pluginId, Boolean enabled) { enabledPlugins.put(pluginId, enabled); } public UserPreferences getConfiguration() { return configuration; } /** * @param configuration The configuration to set, non null */ public void setConfiguration(@Nonnull UserPreferences configuration) { requireNonNull(configuration); this.configuration = configuration; } /** * StaticConstant used to name anonymous projects. */ public static final String UNNAMED_PROJECT = "<>"; private long timestampForAnalyzedClasses = 0L; private IGuiCallback guiCallback; @Nonnull private Filter suppressionFilter = new Filter(); private SourceFinder sourceFinder; /** * Create an anonymous project. */ public Project() { enabledPlugins = new HashMap<>(); configuration = UserPreferences.createDefaultUserPreferences(); analysisTargets = new LinkedList<>(); srcDirList = new LinkedList<>(); auxClasspathEntryList = new LinkedList<>(); isModified = false; currentWorkingDirectoryList = new ArrayList<>(); } /** * Return an exact copy of this Project. */ public Project duplicate() { Project dup = new Project(); dup.currentWorkingDirectoryList.addAll(this.currentWorkingDirectoryList); dup.projectName = this.projectName; dup.analysisTargets.addAll(this.analysisTargets); dup.srcDirList.addAll(this.srcDirList); dup.auxClasspathEntryList.addAll(this.auxClasspathEntryList); dup.timestampForAnalyzedClasses = timestampForAnalyzedClasses; dup.guiCallback = guiCallback; return dup; } public SourceFinder getSourceFinder() { if (sourceFinder == null) { sourceFinder = new SourceFinder(this); } return sourceFinder; } public boolean isGuiAvaliable() { return guiCallback != null; } /** * add information from project2 to this project */ public void add(Project project2) { analysisTargets = appendWithoutDuplicates(analysisTargets, project2.analysisTargets); srcDirList = appendWithoutDuplicates(srcDirList, project2.srcDirList); auxClasspathEntryList = appendWithoutDuplicates(auxClasspathEntryList, project2.auxClasspathEntryList); } public static List appendWithoutDuplicates(List lst1, List lst2) { LinkedHashSet joined = new LinkedHashSet<>(lst1); joined.addAll(lst2); return new ArrayList<>(joined); } public void setCurrentWorkingDirectory(File f) { if (f != null) { addWorkingDir(f.toString()); } } /** * Return whether or not this Project has unsaved modifications. */ public boolean isModified() { return isModified; } /** * Set whether or not this Project has unsaved modifications. */ public void setModified(boolean isModified) { this.isModified = isModified; } /** * Add a file to the project. * * @param fileName * the file to add * @return true if the file was added, or false if the file was already * present */ public boolean addFile(String fileName) { return addToListInternal(analysisTargets, makeAbsoluteCWD(fileName)); } /** * Add a source directory to the project. * * @param sourceDir * The source directory to add. These can be either an absolute path * or relative to any of the working directories in this project object. * @return true if the source directory was added or false if it was already present * @deprecated Calling this method repeatedly performs poorly because a SourceFinder is created each time, * which checks all files for existence each time. Use {@link #addSourceDirs} instead. */ @Deprecated public boolean addSourceDir(String sourceDir) { return addSourceDirs(Collections.singletonList(sourceDir)); } /** * Add source directories to the project. * * @param sourceDirs * The source directories to add. These can be either absolute paths * or relative to any of the working directories in this project object. * @return true if a source directory was added or false if all source * directories were already present */ public boolean addSourceDirs(Collection sourceDirs) { boolean isNew = false; if (sourceDirs == null || sourceDirs.isEmpty()) { return isNew; } for (String dirName : sourceDirs) { for (String dir : makeAbsoluteCwdCandidates(dirName)) { isNew = addToListInternal(srcDirList, dir) || isNew; } } IO.close(sourceFinder); sourceFinder = new SourceFinder(this); return isNew; } /** * Add a working directory to the project. * * @param dirName * the directory to add * @return true if the working directory was added, or false if the working * directory was already present */ public boolean addWorkingDir(String dirName) { if (dirName == null) { throw new NullPointerException(); } return addToListInternal(currentWorkingDirectoryList, new File(dirName)); } /** * Get the number of files in the project. * * @return the number of files in the project */ public int getFileCount() { return analysisTargets.size(); } /** * Get the given file in the list of project files. * * @param num * the number of the file in the list of project files * @return the name of the file */ public String getFile(int num) { return analysisTargets.get(num); } /** * Remove file at the given index in the list of project files * * @param num * index of the file to remove in the list of project files */ public void removeFile(int num) { analysisTargets.remove(num); isModified = true; } /** * Get the list of files, directories, and zip files in the project. */ public List getFileList() { return analysisTargets; } /** * Get the number of source directories in the project. * * @return the number of source directories in the project */ public int getNumSourceDirs() { return srcDirList.size(); } /** * Get the given source directory. * * @param num * the number of the source directory * @return the source directory */ public String getSourceDir(int num) { return srcDirList.get(num); } /** * Remove source directory at given index. * * @param num * index of the source directory to remove */ public void removeSourceDir(int num) { srcDirList.remove(num); IO.close(sourceFinder); sourceFinder = new SourceFinder(this); isModified = true; } /** * Get project files as an array of Strings. */ public String[] getFileArray() { return analysisTargets.toArray(new String[0]); } /** * Get source dirs as an array of Strings. */ public String[] getSourceDirArray() { return srcDirList.toArray(new String[0]); } /** * Get the source dir list. */ public List getSourceDirList() { return srcDirList; } /** * Add an auxiliary classpath entry * * @param auxClasspathEntry * the entry * @return true if the entry was added successfully, or false if the given * entry is already in the list */ public boolean addAuxClasspathEntry(String auxClasspathEntry) { return addToListInternal(auxClasspathEntryList, makeAbsoluteCWD(auxClasspathEntry)); } /** * Get the number of auxiliary classpath entries. */ public int getNumAuxClasspathEntries() { return auxClasspathEntryList.size(); } /** * Get the n'th auxiliary classpath entry. */ public String getAuxClasspathEntry(int n) { return auxClasspathEntryList.get(n); } /** * Remove the n'th auxiliary classpath entry. */ public void removeAuxClasspathEntry(int n) { auxClasspathEntryList.remove(n); isModified = true; } /** * Return the list of aux classpath entries. */ public List getAuxClasspathEntryList() { return auxClasspathEntryList; } /** * Worklist item for finding implicit classpath entries. */ private static class WorkListItem { private final URL url; /** * Constructor. * * @param url * the URL of the Jar or Zip file */ public WorkListItem(URL url) { this.url = url; } /** * Get URL of Jar/Zip file. */ public URL getURL() { return this.url; } } /** * Worklist for finding implicit classpath entries. */ private static class WorkList { private static final Logger LOG = LoggerFactory.getLogger(WorkList.class); private final LinkedList itemList; private final HashSet addedSet; /** * Constructor. Creates an empty worklist. */ public WorkList() { this.itemList = new LinkedList<>(); this.addedSet = new HashSet<>(); } /** * Create a URL from a filename specified in the project file. */ public URL createURL(String fileName) throws MalformedURLException { String protocol = URLClassPath.getURLProtocol(fileName); if (protocol == null) { fileName = "file:" + fileName; } return new URL(fileName); } /** * Create a URL of a file relative to another URL. */ public URL createRelativeURL(URL base, String fileName) throws MalformedURLException { return new URL(base, fileName); } /** * Add a worklist item. * * @param item * the WorkListItem representing a zip/jar file to be * examined * @return true if the item was added, false if not (because it was * examined already) */ public boolean add(WorkListItem item) { LOG.debug("Adding {}", item.getURL()); if (!addedSet.add(item.getURL().toString())) { LOG.debug("\t==> Already processed"); return false; } itemList.add(item); return true; } /** * Return whether or not the worklist is empty. */ public boolean isEmpty() { return itemList.isEmpty(); } /** * Get the next item in the worklist. */ public WorkListItem getNextItem() { return itemList.removeFirst(); } } /** * Return the list of implicit classpath entries. The implicit classpath is * computed from the closure of the set of jar files that are referenced by * the "Class-Path" attribute of the manifest of the any jar * file that is part of this project or by the "Class-Path" * attribute of any directly or indirectly referenced jar. The referenced * jar files that exist are the list of implicit classpath entries. * * @deprecated FindBugs2 and ClassPathBuilder take care of this * automatically */ @Deprecated public List getImplicitClasspathEntryList() { final LinkedList implicitClasspath = new LinkedList<>(); WorkList workList = new WorkList(); // Prime the worklist by adding the zip/jar files // in the project. for (String fileName : analysisTargets) { try { URL url = workList.createURL(fileName); WorkListItem item = new WorkListItem(url); workList.add(item); } catch (MalformedURLException ignore) { // Ignore } } // Scan recursively. while (!workList.isEmpty()) { WorkListItem item = workList.getNextItem(); processComponentJar(item.getURL(), workList, implicitClasspath); } return implicitClasspath; } /** * Examine the manifest of a single zip/jar file for implicit classapth * entries. * * @param jarFileURL * URL of the zip/jar file * @param workList * worklist of zip/jar files to examine * @param implicitClasspath * list of implicit classpath entries found */ private void processComponentJar(URL jarFileURL, WorkList workList, List implicitClasspath) { LOG.debug("Processing {}", jarFileURL); if (!jarFileURL.toString().endsWith(".zip") && !jarFileURL.toString().endsWith(".jar")) { return; } try { URL manifestURL = new URL("jar:" + jarFileURL.toString() + "!/META-INF/MANIFEST.MF"); try (InputStream in = manifestURL.openStream()) { Manifest manifest = new Manifest(in); Attributes mainAttrs = manifest.getMainAttributes(); String classPath = mainAttrs.getValue("Class-Path"); if (classPath != null) { String[] fileList = classPath.split("\\s+"); for (String jarFile : fileList) { URL referencedURL = workList.createRelativeURL(jarFileURL, jarFile); if (workList.add(new WorkListItem(referencedURL))) { implicitClasspath.add(referencedURL.toString()); LOG.debug("Implicit jar: {}", referencedURL); } } } } } catch (IOException ignore) { // Ignore } } private static final String OPTIONS_KEY = "[Options]"; private static final String JAR_FILES_KEY = "[Jar files]"; private static final String SRC_DIRS_KEY = "[Source dirs]"; private static final String AUX_CLASSPATH_ENTRIES_KEY = "[Aux classpath entries]"; // Option keys public static final String RELATIVE_PATHS = "relative_paths"; /** * Save the project to an output file. * * @param outputFile * name of output file * @param useRelativePaths * true if the project should be written using only relative * paths * @param relativeBase * if useRelativePaths is true, this file is taken as the base * directory in terms of which all files should be made relative * @throws IOException * if an error occurs while writing */ @Deprecated public void write(String outputFile, boolean useRelativePaths, String relativeBase) throws IOException { try (PrintWriter writer = UTF8.printWriter(outputFile)) { writer.println(JAR_FILES_KEY); for (String jarFile : analysisTargets) { if (useRelativePaths) { jarFile = convertToRelative(jarFile, relativeBase); } writer.println(jarFile); } writer.println(SRC_DIRS_KEY); for (String srcDir : srcDirList) { if (useRelativePaths) { srcDir = convertToRelative(srcDir, relativeBase); } writer.println(srcDir); } writer.println(AUX_CLASSPATH_ENTRIES_KEY); for (String auxClasspathEntry : auxClasspathEntryList) { if (useRelativePaths) { auxClasspathEntry = convertToRelative(auxClasspathEntry, relativeBase); } writer.println(auxClasspathEntry); } if (useRelativePaths) { writer.println(OPTIONS_KEY); writer.println(RELATIVE_PATHS + "=true"); } } // Project successfully saved isModified = false; } public static Project readXML(File f) throws IOException, SAXException, ParserConfigurationException { @SuppressWarnings("resource") // will be closed by caller Project project = new Project(); try (InputStream in = new BufferedInputStream(new FileInputStream(f))) { String tag = Util.getXMLType(in); SAXBugCollectionHandler handler; if ("Project".equals(tag)) { handler = new SAXBugCollectionHandler(project, f); } else if ("BugCollection".equals(tag)) { SortedBugCollection bugs = new SortedBugCollection(project); handler = new SAXBugCollectionHandler(bugs, f); } else { throw new IOException("Can't load a project from a " + tag + " file"); } SAXParserFactory parserFactory = SAXParserFactory.newInstance(); parserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE); parserFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", Boolean.TRUE); parserFactory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", Boolean.FALSE); parserFactory.setFeature("http://xml.org/sax/features/external-general-entities", Boolean.FALSE); parserFactory.setFeature("http://xml.org/sax/features/external-parameter-entities", Boolean.FALSE); SAXParser parser = parserFactory.newSAXParser(); XMLReader xr = parser.getXMLReader(); xr.setContentHandler(handler); xr.setErrorHandler(handler); try (Reader reader = Util.getReader(in)) { xr.parse(new InputSource(reader)); } } catch (IOException | SAXException | ParserConfigurationException e) { project.close(); throw e; } // Presumably, project is now up-to-date project.setModified(false); return project; } public void writeXML(File f, @CheckForNull BugCollection bugCollection) throws IOException { OutputStream out = new FileOutputStream(f); XMLOutput xmlOutput = new OutputStreamXMLOutput(out); try { writeXML(xmlOutput, f, bugCollection); } finally { xmlOutput.finish(); } } /** * Read Project from named file. * * @param argument * command line argument containing project file name * @return the Project * @throws IOException */ public static Project readProject(String argument) throws IOException { String projectFileName = argument; File projectFile = new File(projectFileName); if (projectFileName.endsWith(".xml") || projectFileName.endsWith(".fbp")) { try { return Project.readXML(projectFile); } catch (SAXException | ParserConfigurationException e) { IOException ioe = new IOException("Couldn't read saved FindBugs project", e); throw ioe; } } throw new IllegalArgumentException("Can't read project from " + argument); } /** * Read a line from a BufferedReader, ignoring blank lines and comments. * private static String getLine(BufferedReader reader) throws IOException { String line; while ((line = reader.readLine()) != null) { line = line.trim(); if (!line.equals("") && !line.startsWith("#")) { break; } } return line; }*/ /** * Convert to a string in a nice (displayable) format. */ @Override public String toString() { if (projectName != null) { return projectName; } return UNNAMED_PROJECT; } /** * Transform a user-entered filename into a proper filename, by adding the * ".fb" file extension if it isn't already present. */ public static String transformFilename(String fileName) { if (!fileName.endsWith(".fb")) { fileName = fileName + ".fb"; } return fileName; } static final String JAR_ELEMENT_NAME = "Jar"; static final String AUX_CLASSPATH_ENTRY_ELEMENT_NAME = "AuxClasspathEntry"; static final String SRC_DIR_ELEMENT_NAME = "SrcDir"; static final String WRK_DIR_ELEMENT_NAME = "WrkDir"; static final String FILENAME_ATTRIBUTE_NAME = "filename"; static final String PROJECTNAME_ATTRIBUTE_NAME = "projectName"; static final String PLUGIN_ELEMENT_NAME = "Plugin"; static final String PLUGIN_ID_ATTRIBUTE_NAME = "id"; static final String PLUGIN_STATUS_ELEMENT_NAME = "enabled"; @Override public void writeXML(XMLOutput xmlOutput) throws IOException { writeXML(xmlOutput, null, null); } public void writeXML(XMLOutput xmlOutput, @CheckForNull File destination, @CheckForNull BugCollection bugCollection) throws IOException { { XMLAttributeList attributeList = new XMLAttributeList(); if (getProjectName() != null) { attributeList = attributeList.addAttribute(PROJECTNAME_ATTRIBUTE_NAME, getProjectName()); } xmlOutput.openTag(BugCollection.PROJECT_ELEMENT_NAME, attributeList); } if (destination != null) { String base = destination.getParent(); writeElementList(xmlOutput, JAR_ELEMENT_NAME, convertToRelative(analysisTargets, base)); writeElementList(xmlOutput, AUX_CLASSPATH_ENTRY_ELEMENT_NAME, convertToRelative(auxClasspathEntryList, base)); writeElementList(xmlOutput, SRC_DIR_ELEMENT_NAME, convertToRelative(srcDirList, base)); List cwdStrings = new ArrayList<>(); for (File file : currentWorkingDirectoryList) { cwdStrings.add(file.getPath()); } writeElementList(xmlOutput, WRK_DIR_ELEMENT_NAME, convertToRelative(cwdStrings, base)); } else { // TODO to allow relative paths: refactor the code which uses null // file arguments writeElementList(xmlOutput, JAR_ELEMENT_NAME, analysisTargets); writeElementList(xmlOutput, AUX_CLASSPATH_ENTRY_ELEMENT_NAME, auxClasspathEntryList); writeElementList(xmlOutput, SRC_DIR_ELEMENT_NAME, srcDirList); writeFileList(xmlOutput, WRK_DIR_ELEMENT_NAME, currentWorkingDirectoryList); } if (!suppressionFilter.isEmpty()) { xmlOutput.openTag("SuppressionFilter"); suppressionFilter.writeBodyAsXML(xmlOutput); xmlOutput.closeTag("SuppressionFilter"); } for (Map.Entry e : enabledPlugins.entrySet()) { String pluginId = e.getKey(); Boolean enabled = e.getValue(); Plugin plugin = Plugin.getByPluginId(pluginId); if (plugin == null || enabled == null) { continue; } XMLAttributeList pluginAttributeList = new XMLAttributeList(); pluginAttributeList.addAttribute(PLUGIN_ID_ATTRIBUTE_NAME, plugin.getPluginId()); pluginAttributeList.addAttribute(PLUGIN_STATUS_ELEMENT_NAME, enabled.toString()); xmlOutput.openCloseTag(PLUGIN_ELEMENT_NAME, pluginAttributeList); } xmlOutput.closeTag(BugCollection.PROJECT_ELEMENT_NAME); } /** * Hack for whether files are case insensitive. For now, we'll assume that * Windows is the only case insensitive OS. (OpenVMS users, feel free to * submit a patch :-) */ private static final boolean FILE_IGNORE_CASE = SystemProperties.getProperty("os.name", "unknown").startsWith("Windows"); private Iterable convertToRelative(List paths, String base) { List newList = new ArrayList<>(paths.size()); for (String path : paths) { newList.add(convertToRelative(path, base)); } return newList; } /** * Converts a full path to a relative path if possible * * @param srcFile * path to convert * @return the converted filename */ private String convertToRelative(String srcFile, String base) { String slash = SystemProperties.getProperty("file.separator"); if (FILE_IGNORE_CASE) { srcFile = srcFile.toLowerCase(); base = base.toLowerCase(); } if (base.equals(srcFile)) { return "."; } if (!base.endsWith(slash)) { base = base + slash; } if (base.length() <= srcFile.length()) { String root = srcFile.substring(0, base.length()); if (root.equals(base)) { // Strip off the base directory, make relative return "." + SystemProperties.getProperty("file.separator") + srcFile.substring(base.length()); } } // See if we can build a relative path above the base using .. notation int slashPos = srcFile.indexOf(slash); int branchPoint; if (slashPos >= 0) { String subPath = srcFile.substring(0, slashPos); if ((subPath.length() == 0) || base.startsWith(subPath)) { branchPoint = slashPos + 1; slashPos = srcFile.indexOf(slash, branchPoint); while (slashPos >= 0) { subPath = srcFile.substring(0, slashPos); if (base.startsWith(subPath)) { branchPoint = slashPos + 1; } else { break; } slashPos = srcFile.indexOf(slash, branchPoint); } int slashCount = 0; slashPos = base.indexOf(slash, branchPoint); while (slashPos >= 0) { slashCount++; slashPos = base.indexOf(slash, slashPos + 1); } StringBuilder path = new StringBuilder(); String upDir = ".." + slash; for (int i = 0; i < slashCount; i++) { path.append(upDir); } path.append(srcFile.substring(branchPoint)); return path.toString(); } } return srcFile; } /** * Converts a relative path to an absolute path if possible. * * @param fileName * path to convert * @return the converted filename * private String convertToAbsolute(String fileName) { // At present relative paths are only calculated if the fileName is // below the project file. This need not be the case, and we could use // .. // syntax to move up the tree. (To Be Added) File file = new File(fileName); if (!file.isAbsolute()) { for (File cwd : currentWorkingDirectoryList) { File test = new File(cwd, fileName); if (test.canRead()) { return test.getAbsolutePath(); } } return file.getAbsolutePath(); } return fileName; }*/ /** * Make the given filename absolute relative to the current working * directory. */ private String makeAbsoluteCWD(String fileName) { List candidates = makeAbsoluteCwdCandidates(fileName); return candidates.get(0); } /** * Make the given filename absolute relative to the current working * directory candidates. * * If the given filename exists in more than one of the working directories, * a list of these existing absolute paths is returned. * * The returned list is guaranteed to be non-empty. The returned paths might * exist or not exist and might be relative or absolute. * * @return A list of at least one candidate path for the given filename. */ private List makeAbsoluteCwdCandidates(String fileName) { List candidates = new ArrayList<>(); boolean hasProtocol = (URLClassPath.getURLProtocol(fileName) != null); if (hasProtocol) { candidates.add(fileName); return candidates; } if (new File(fileName).isAbsolute()) { candidates.add(fileName); return candidates; } for (File currentWorkingDirectory : currentWorkingDirectoryList) { File relativeToCurrent = new File(currentWorkingDirectory, fileName); if (relativeToCurrent.exists()) { candidates.add(relativeToCurrent.toString()); } } if (candidates.isEmpty()) { candidates.add(fileName); } return candidates; } /** * Add a value to given list, making the Project modified if the value is * not already present in the list. * * @param list * the list * @param value * the value to be added * @return true if the value was not already present in the list, false * otherwise */ private boolean addToListInternal(Collection list, T value) { if (!list.contains(value)) { list.add(value); isModified = true; return true; } else { return false; } } /* * Make the given list of pathnames absolute relative to the absolute path * of the project file. * private void makeListAbsoluteProject(List list) { List replace = new LinkedList(); for (String fileName : list) { fileName = convertToAbsolute(fileName); replace.add(fileName); } list.clear(); list.addAll(replace); }*/ public void setTimestamp(long timestamp) { this.timestampForAnalyzedClasses = timestamp; } public void addTimestamp(long timestamp) { if (this.timestampForAnalyzedClasses < timestamp && FindBugs.validTimestamp(timestamp)) { this.timestampForAnalyzedClasses = timestamp; } } public long getTimestamp() { return timestampForAnalyzedClasses; } public void setProjectName(String projectName) { this.projectName = projectName; } public String getProjectName() { return projectName; } public void setSuppressionFilter(@Nonnull Filter suppressionFilter) { requireNonNull(suppressionFilter); this.suppressionFilter = suppressionFilter; } @Nonnull public Filter getSuppressionFilter() { return suppressionFilter; } public void setGuiCallback(IGuiCallback guiCallback) { this.guiCallback = guiCallback; } public IGuiCallback getGuiCallback() { if (guiCallback == null) { guiCallback = new CommandLineUiCallback(); } return guiCallback; } public Iterable getResolvedSourcePaths() { List result = new ArrayList<>(); for (String s : srcDirList) { boolean hasProtocol = (URLClassPath.getURLProtocol(s) != null); if (hasProtocol) { result.add(s); continue; } File f = new File(s); if (f.isAbsolute() || currentWorkingDirectoryList.isEmpty()) { if (f.canRead()) { result.add(s); } continue; } for (File d : currentWorkingDirectoryList) { if (d.canRead() && d.isDirectory()) { File a = new File(d, s); if (a.canRead()) { result.add(a.getAbsolutePath()); } } } } return result; } @Override public void close() { IO.close(sourceFinder); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy