aboutsummaryrefslogtreecommitdiffstats
path: root/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java
diff options
context:
space:
mode:
Diffstat (limited to 'lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java')
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java815
1 files changed, 0 insertions, 815 deletions
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java
deleted file mode 100644
index b584020..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java
+++ /dev/null
@@ -1,815 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tools.lint.detector.api;
-
-import static com.android.SdkConstants.ANDROID_LIBRARY;
-import static com.android.SdkConstants.ANDROID_LIBRARY_REFERENCE_FORMAT;
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.ANDROID_URI;
-import static com.android.SdkConstants.ATTR_MIN_SDK_VERSION;
-import static com.android.SdkConstants.ATTR_PACKAGE;
-import static com.android.SdkConstants.ATTR_TARGET_SDK_VERSION;
-import static com.android.SdkConstants.PROGUARD_CONFIG;
-import static com.android.SdkConstants.PROJECT_PROPERTIES;
-import static com.android.SdkConstants.TAG_USES_SDK;
-import static com.android.SdkConstants.VALUE_TRUE;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.Configuration;
-import com.android.tools.lint.client.api.LintClient;
-import com.android.tools.lint.client.api.SdkInfo;
-import com.google.common.annotations.Beta;
-import com.google.common.base.Charsets;
-import com.google.common.io.Closeables;
-import com.google.common.io.Files;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-
-import java.io.BufferedInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Properties;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A project contains information about an Android project being scanned for
- * Lint errors.
- * <p>
- * <b>NOTE: This is not a public or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-@Beta
-public class Project {
- private final LintClient mClient;
- private final File mDir;
- private final File mReferenceDir;
- private Configuration mConfiguration;
- private String mPackage;
- private int mMinSdk = 1;
- private int mTargetSdk = -1;
- private boolean mLibrary;
- private String mName;
- private String mProguardPath;
- private boolean mMergeManifests;
-
- /** The SDK info, if any */
- private SdkInfo mSdkInfo;
-
- /**
- * If non null, specifies a non-empty list of specific files under this
- * project which should be checked.
- */
- private List<File> mFiles;
- private List<File> mJavaSourceFolders;
- private List<File> mJavaClassFolders;
- private List<File> mJavaLibraries;
- private List<Project> mDirectLibraries;
- private List<Project> mAllLibraries;
- private boolean mReportIssues = true;
-
- /**
- * Creates a new {@link Project} for the given directory.
- *
- * @param client the tool running the lint check
- * @param dir the root directory of the project
- * @param referenceDir See {@link #getReferenceDir()}.
- * @return a new {@link Project}
- */
- @NonNull
- public static Project create(
- @NonNull LintClient client,
- @NonNull File dir,
- @NonNull File referenceDir) {
- return new Project(client, dir, referenceDir);
- }
-
- /** Creates a new Project. Use one of the factory methods to create. */
- private Project(
- @NonNull LintClient client,
- @NonNull File dir,
- @NonNull File referenceDir) {
- mClient = client;
- mDir = dir;
- mReferenceDir = referenceDir;
-
- try {
- // Read properties file and initialize library state
- Properties properties = new Properties();
- File propFile = new File(dir, PROJECT_PROPERTIES);
- if (propFile.exists()) {
- @SuppressWarnings("resource") // Eclipse doesn't know about Closeables.closeQuietly
- BufferedInputStream is = new BufferedInputStream(new FileInputStream(propFile));
- try {
- properties.load(is);
- String value = properties.getProperty(ANDROID_LIBRARY);
- mLibrary = VALUE_TRUE.equals(value);
- mProguardPath = properties.getProperty(PROGUARD_CONFIG);
- mMergeManifests = VALUE_TRUE.equals(properties.getProperty(
- "manifestmerger.enabled")); //$NON-NLS-1$
-
- for (int i = 1; i < 1000; i++) {
- String key = String.format(ANDROID_LIBRARY_REFERENCE_FORMAT, i);
- String library = properties.getProperty(key);
- if (library == null || library.length() == 0) {
- // No holes in the numbering sequence is allowed
- break;
- }
-
- File libraryDir = new File(dir, library).getCanonicalFile();
-
- if (mDirectLibraries == null) {
- mDirectLibraries = new ArrayList<Project>();
- }
-
- // Adjust the reference dir to be a proper prefix path of the
- // library dir
- File libraryReferenceDir = referenceDir;
- if (!libraryDir.getPath().startsWith(referenceDir.getPath())) {
- // Symlinks etc might have been resolved, so do those to
- // the reference dir as well
- libraryReferenceDir = libraryReferenceDir.getCanonicalFile();
- if (!libraryDir.getPath().startsWith(referenceDir.getPath())) {
- File f = libraryReferenceDir;
- while (f != null && f.getPath().length() > 0) {
- if (libraryDir.getPath().startsWith(f.getPath())) {
- libraryReferenceDir = f;
- break;
- }
- f = f.getParentFile();
- }
- }
- }
-
- Project libraryPrj = client.getProject(libraryDir, libraryReferenceDir);
- mDirectLibraries.add(libraryPrj);
- // By default, we don't report issues in inferred library projects.
- // The driver will set report = true for those library explicitly
- // requested.
- libraryPrj.setReportIssues(false);
- }
- } finally {
- Closeables.closeQuietly(is);
- }
- }
- } catch (IOException ioe) {
- client.log(ioe, "Initializing project state");
- }
-
- if (mDirectLibraries != null) {
- mDirectLibraries = Collections.unmodifiableList(mDirectLibraries);
- } else {
- mDirectLibraries = Collections.emptyList();
- }
- }
-
- @Override
- public String toString() {
- return "Project [dir=" + mDir + "]";
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mDir == null) ? 0 : mDir.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Project other = (Project) obj;
- if (mDir == null) {
- if (other.mDir != null)
- return false;
- } else if (!mDir.equals(other.mDir))
- return false;
- return true;
- }
-
- /**
- * Adds the given file to the list of files which should be checked in this
- * project. If no files are added, the whole project will be checked.
- *
- * @param file the file to be checked
- */
- public void addFile(@NonNull File file) {
- if (mFiles == null) {
- mFiles = new ArrayList<File>();
- }
- mFiles.add(file);
- }
-
- /**
- * The list of files to be checked in this project. If null, the whole
- * project should be checked.
- *
- * @return the subset of files to be checked, or null for the whole project
- */
- @Nullable
- public List<File> getSubset() {
- return mFiles;
- }
-
- /**
- * Returns the list of source folders for Java source files
- *
- * @return a list of source folders to search for .java files
- */
- @NonNull
- public List<File> getJavaSourceFolders() {
- if (mJavaSourceFolders == null) {
- if (isAospBuildEnvironment()) {
- String top = getAospTop();
- if (mDir.getAbsolutePath().startsWith(top)) {
- mJavaSourceFolders = getAospJavaSourcePath();
- return mJavaSourceFolders;
- }
- }
-
- mJavaSourceFolders = mClient.getJavaSourceFolders(this);
- }
-
- return mJavaSourceFolders;
- }
-
- /**
- * Returns the list of output folders for class files
- * @return a list of output folders to search for .class files
- */
- @NonNull
- public List<File> getJavaClassFolders() {
- if (mJavaClassFolders == null) {
- if (isAospBuildEnvironment()) {
- String top = getAospTop();
- if (mDir.getAbsolutePath().startsWith(top)) {
- mJavaClassFolders = getAospJavaClassPath();
- return mJavaClassFolders;
- }
- }
-
- mJavaClassFolders = mClient.getJavaClassFolders(this);
- }
- return mJavaClassFolders;
- }
-
- /**
- * Returns the list of Java libraries (typically .jar files) that this
- * project depends on. Note that this refers to jar libraries, not Android
- * library projects which are processed in a separate pass with their own
- * source and class folders.
- *
- * @return a list of .jar files (or class folders) that this project depends
- * on.
- */
- @NonNull
- public List<File> getJavaLibraries() {
- if (mJavaLibraries == null) {
- // AOSP builds already merge libraries and class folders into
- // the single classes.jar file, so these have already been processed
- // in getJavaClassFolders.
-
- mJavaLibraries = mClient.getJavaLibraries(this);
- }
-
- return mJavaLibraries;
- }
-
- /**
- * Returns the relative path of a given file relative to the user specified
- * directory (which is often the project directory but sometimes a higher up
- * directory when a directory tree is being scanned
- *
- * @param file the file under this project to check
- * @return the path relative to the reference directory (often the project directory)
- */
- @NonNull
- public String getDisplayPath(@NonNull File file) {
- String path = file.getPath();
- String referencePath = mReferenceDir.getPath();
- if (path.startsWith(referencePath)) {
- int length = referencePath.length();
- if (path.length() > length && path.charAt(length) == File.separatorChar) {
- length++;
- }
-
- return path.substring(length);
- }
-
- return path;
- }
-
- /**
- * Returns the relative path of a given file within the current project.
- *
- * @param file the file under this project to check
- * @return the path relative to the project
- */
- @NonNull
- public String getRelativePath(@NonNull File file) {
- String path = file.getPath();
- String referencePath = mDir.getPath();
- if (path.startsWith(referencePath)) {
- int length = referencePath.length();
- if (path.length() > length && path.charAt(length) == File.separatorChar) {
- length++;
- }
-
- return path.substring(length);
- }
-
- return path;
- }
-
- /**
- * Returns the project root directory
- *
- * @return the dir
- */
- @NonNull
- public File getDir() {
- return mDir;
- }
-
- /**
- * Returns the original user supplied directory where the lint search
- * started. For example, if you run lint against {@code /tmp/foo}, and it
- * finds a project to lint in {@code /tmp/foo/dev/src/project1}, then the
- * {@code dir} is {@code /tmp/foo/dev/src/project1} and the
- * {@code referenceDir} is {@code /tmp/foo/}.
- *
- * @return the reference directory, never null
- */
- @NonNull
- public File getReferenceDir() {
- return mReferenceDir;
- }
-
- /**
- * Gets the configuration associated with this project
- *
- * @return the configuration associated with this project
- */
- @NonNull
- public Configuration getConfiguration() {
- if (mConfiguration == null) {
- mConfiguration = mClient.getConfiguration(this);
- }
- return mConfiguration;
- }
-
- /**
- * Returns the application package specified by the manifest
- *
- * @return the application package, or null if unknown
- */
- @Nullable
- public String getPackage() {
- //assert !mLibrary; // Should call getPackage on the master project, not the library
- // Assertion disabled because you might be running lint on a standalone library project.
-
- return mPackage;
- }
-
- /**
- * Returns the minimum API level requested by the manifest, or -1 if not
- * specified
- *
- * @return the minimum API level or -1 if unknown
- */
- public int getMinSdk() {
- //assert !mLibrary; // Should call getMinSdk on the master project, not the library
- // Assertion disabled because you might be running lint on a standalone library project.
-
- return mMinSdk;
- }
-
- /**
- * Returns the target API level specified by the manifest, or -1 if not
- * specified
- *
- * @return the target API level or -1 if unknown
- */
- public int getTargetSdk() {
- //assert !mLibrary; // Should call getTargetSdk on the master project, not the library
- // Assertion disabled because you might be running lint on a standalone library project.
-
- return mTargetSdk;
- }
-
- /**
- * Initialized the manifest state from the given manifest model
- *
- * @param document the DOM document for the manifest XML document
- */
- public void readManifest(@NonNull Document document) {
- Element root = document.getDocumentElement();
- if (root == null) {
- return;
- }
-
- mPackage = root.getAttribute(ATTR_PACKAGE);
-
- // Initialize minSdk and targetSdk
- NodeList usesSdks = root.getElementsByTagName(TAG_USES_SDK);
- if (usesSdks.getLength() > 0) {
- Element element = (Element) usesSdks.item(0);
-
- String minSdk = null;
- if (element.hasAttributeNS(ANDROID_URI, ATTR_MIN_SDK_VERSION)) {
- minSdk = element.getAttributeNS(ANDROID_URI, ATTR_MIN_SDK_VERSION);
- }
- if (minSdk != null) {
- try {
- mMinSdk = Integer.valueOf(minSdk);
- } catch (NumberFormatException e) {
- mMinSdk = 1;
- }
- }
-
- String targetSdk = null;
- if (element.hasAttributeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION)) {
- targetSdk = element.getAttributeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION);
- } else if (minSdk != null) {
- targetSdk = minSdk;
- }
- if (targetSdk != null) {
- try {
- mTargetSdk = Integer.valueOf(targetSdk);
- } catch (NumberFormatException e) {
- // TODO: Handle codenames?
- mTargetSdk = -1;
- }
- }
- } else if (isAospBuildEnvironment()) {
- extractAospMinSdkVersion();
- }
- }
-
- /**
- * Returns true if this project is an Android library project
- *
- * @return true if this project is an Android library project
- */
- public boolean isLibrary() {
- return mLibrary;
- }
-
- /**
- * Returns the list of library projects referenced by this project
- *
- * @return the list of library projects referenced by this project, never
- * null
- */
- @NonNull
- public List<Project> getDirectLibraries() {
- return mDirectLibraries;
- }
-
- /**
- * Returns the transitive closure of the library projects for this project
- *
- * @return the transitive closure of the library projects for this project
- */
- @NonNull
- public List<Project> getAllLibraries() {
- if (mAllLibraries == null) {
- if (mDirectLibraries.size() == 0) {
- return mDirectLibraries;
- }
-
- List<Project> all = new ArrayList<Project>();
- addLibraryProjects(all);
- mAllLibraries = all;
- }
-
- return mAllLibraries;
- }
-
- /**
- * Adds this project's library project and their library projects
- * recursively into the given collection of projects
- *
- * @param collection the collection to add the projects into
- */
- private void addLibraryProjects(@NonNull Collection<Project> collection) {
- for (Project library : mDirectLibraries) {
- collection.add(library);
- // Recurse
- library.addLibraryProjects(collection);
- }
- }
-
- /**
- * Gets the SDK info for the current project.
- *
- * @return the SDK info for the current project, never null
- */
- @NonNull
- public SdkInfo getSdkInfo() {
- if (mSdkInfo == null) {
- mSdkInfo = mClient.getSdkInfo(this);
- }
-
- return mSdkInfo;
- }
-
- /**
- * Gets the path to the manifest file in this project, if it exists
- *
- * @return the path to the manifest file, or null if it does not exist
- */
- public File getManifestFile() {
- File manifestFile = new File(mDir, ANDROID_MANIFEST_XML);
- if (manifestFile.exists()) {
- return manifestFile;
- }
-
- return null;
- }
-
- /**
- * Returns the proguard path configured for this project, or null if ProGuard is
- * not configured.
- *
- * @return the proguard path, or null
- */
- @Nullable
- public String getProguardPath() {
- return mProguardPath;
- }
-
- /**
- * Returns the name of the project
- *
- * @return the name of the project, never null
- */
- @NonNull
- public String getName() {
- if (mName == null) {
- // TODO: Consider reading the name from .project (if it's an Eclipse project)
- mName = mDir.getName();
- }
-
- return mName;
- }
-
- /**
- * Sets whether lint should report issues in this project. See
- * {@link #getReportIssues()} for a full description of what that means.
- *
- * @param reportIssues whether lint should report issues in this project
- */
- public void setReportIssues(boolean reportIssues) {
- mReportIssues = reportIssues;
- }
-
- /**
- * Returns whether lint should report issues in this project.
- * <p>
- * If a user specifies a project and its library projects for analysis, then
- * those library projects are all "included", and all errors found in all
- * the projects are reported. But if the user is only running lint on the
- * main project, we shouldn't report errors in any of the library projects.
- * We still need to <b>consider</b> them for certain types of checks, such
- * as determining whether resources found in the main project are unused, so
- * the detectors must still get a chance to look at these projects. The
- * {@code #getReportIssues()} attribute is used for this purpose.
- *
- * @return whether lint should report issues in this project
- */
- public boolean getReportIssues() {
- return mReportIssues;
- }
-
- /**
- * Sets whether manifest merging is in effect.
- *
- * @param merging whether manifest merging is in effect
- */
- public void setMergingManifests(boolean merging) {
- mMergeManifests = merging;
- }
-
- /**
- * Returns whether manifest merging is in effect
- *
- * @return true if manifests in library projects should be merged into main projects
- */
- public boolean isMergingManifests() {
- return mMergeManifests;
- }
-
-
- // ---------------------------------------------------------------------------
- // Support for running lint on the AOSP source tree itself
-
- private static Boolean sAospBuild;
-
- /** Is lint running in an AOSP build environment */
- private static boolean isAospBuildEnvironment() {
- if (sAospBuild == null) {
- sAospBuild = getAospTop() != null;
- }
-
- return sAospBuild.booleanValue();
- }
-
- /** Get the root AOSP dir, if any */
- private static String getAospTop() {
- return System.getenv("ANDROID_BUILD_TOP"); //$NON-NLS-1$
- }
-
- /** Get the host out directory in AOSP, if any */
- private static String getAospHostOut() {
- return System.getenv("ANDROID_HOST_OUT"); //$NON-NLS-1$
- }
-
- /** Get the product out directory in AOSP, if any */
- private static String getAospProductOut() {
- return System.getenv("ANDROID_PRODUCT_OUT"); //$NON-NLS-1$
- }
-
- private List<File> getAospJavaSourcePath() {
- List<File> sources = new ArrayList<File>(2);
- // Normal sources
- File src = new File(mDir, "src"); //$NON-NLS-1$
- if (src.exists()) {
- sources.add(src);
- }
-
- // Generates sources
- for (File dir : getIntermediateDirs()) {
- File classes = new File(dir, "src"); //$NON-NLS-1$
- if (classes.exists()) {
- sources.add(classes);
- }
- }
-
- if (sources.size() == 0) {
- mClient.log(null,
- "Warning: Could not find sources or generated sources for project %1$s",
- getName());
- }
-
- return sources;
- }
-
- private List<File> getAospJavaClassPath() {
- List<File> classDirs = new ArrayList<File>(1);
-
- for (File dir : getIntermediateDirs()) {
- File classes = new File(dir, "classes"); //$NON-NLS-1$
- if (classes.exists()) {
- classDirs.add(classes);
- } else {
- classes = new File(dir, "classes.jar"); //$NON-NLS-1$
- if (classes.exists()) {
- classDirs.add(classes);
- }
- }
- }
-
- if (classDirs.size() == 0) {
- mClient.log(null,
- "No bytecode found: Has the project been built? (%1$s)", getName());
- }
-
- return classDirs;
- }
-
- /** Find the _intermediates directories for a given module name */
- private List<File> getIntermediateDirs() {
- // See build/core/definitions.mk and in particular the "intermediates-dir-for" definition
- List<File> intermediates = new ArrayList<File>();
-
- // TODO: Look up the module name, e.g. LOCAL_MODULE. However,
- // some Android.mk files do some complicated things with it - and most
- // projects use the same module name as the directory name.
- String moduleName = mDir.getName();
-
- String top = getAospTop();
- final String[] outFolders = new String[] {
- top + "/out/host/common/obj", //$NON-NLS-1$
- top + "/out/target/common/obj", //$NON-NLS-1$
- getAospHostOut() + "/obj", //$NON-NLS-1$
- getAospProductOut() + "/obj" //$NON-NLS-1$
- };
- final String[] moduleClasses = new String[] {
- "APPS", //$NON-NLS-1$
- "JAVA_LIBRARIES", //$NON-NLS-1$
- };
-
- for (String out : outFolders) {
- assert new File(out.replace('/', File.separatorChar)).exists() : out;
- for (String moduleClass : moduleClasses) {
- String path = out + '/' + moduleClass + '/' + moduleName
- + "_intermediates"; //$NON-NLS-1$
- File file = new File(path.replace('/', File.separatorChar));
- if (file.exists()) {
- intermediates.add(file);
- }
- }
- }
-
- return intermediates;
- }
-
- private void extractAospMinSdkVersion() {
- // Is the SDK level specified by a Makefile?
- boolean found = false;
- File makefile = new File(mDir, "Android.mk"); //$NON-NLS-1$
- if (makefile.exists()) {
- try {
- List<String> lines = Files.readLines(makefile, Charsets.UTF_8);
- Pattern p = Pattern.compile("LOCAL_SDK_VERSION\\s*:=\\s*(.*)"); //$NON-NLS-1$
- for (String line : lines) {
- line = line.trim();
- Matcher matcher = p.matcher(line);
- if (matcher.matches()) {
- found = true;
- String version = matcher.group(1);
- if (version.equals("current")) { //$NON-NLS-1$
- mMinSdk = findCurrentAospVersion();
- } else {
- try {
- mMinSdk = Integer.valueOf(version);
- } catch (NumberFormatException e) {
- // Codename - just use current
- mMinSdk = findCurrentAospVersion();
- }
- }
- break;
- }
- }
- } catch (IOException ioe) {
- mClient.log(ioe, null);
- }
- }
-
- if (!found) {
- mMinSdk = findCurrentAospVersion();
- }
- }
-
- /** Cache for {@link #findCurrentAospVersion()} */
- private static int sCurrentVersion;
-
- /** In an AOSP build environment, identify the currently built image version, if available */
- private int findCurrentAospVersion() {
- if (sCurrentVersion < 1) {
- File apiDir = new File(getAospTop(), "frameworks/base/api" //$NON-NLS-1$
- .replace('/', File.separatorChar));
- File[] apiFiles = apiDir.listFiles();
- int max = 1;
- for (File apiFile : apiFiles) {
- String name = apiFile.getName();
- int index = name.indexOf('.');
- if (index > 0) {
- String base = name.substring(0, index);
- if (Character.isDigit(base.charAt(0))) {
- try {
- int version = Integer.parseInt(base);
- if (version > max) {
- max = version;
- }
- } catch (NumberFormatException nufe) {
- // pass
- }
- }
- }
- }
- sCurrentVersion = max;
- }
-
- return sCurrentVersion;
- }
-}