aboutsummaryrefslogtreecommitdiffstats
path: root/lint/libs/lint_api/src
diff options
context:
space:
mode:
Diffstat (limited to 'lint/libs/lint_api/src')
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/AsmVisitor.java205
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/Configuration.java130
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultConfiguration.java453
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java233
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/IDomParser.java93
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/IJavaParser.java76
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/IssueRegistry.java253
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/JavaVisitor.java1192
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java602
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java2061
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/LintListener.java70
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/SdkInfo.java80
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/XmlVisitor.java227
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Category.java170
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java663
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Context.java331
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/DefaultPosition.java68
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Detector.java581
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Issue.java552
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/JavaContext.java108
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/LayoutDetector.java70
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java755
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java712
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Position.java50
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Project.java815
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/ResourceXmlDetector.java60
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java137
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Severity.java77
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/Speed.java55
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/XmlContext.java189
30 files changed, 0 insertions, 11068 deletions
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/AsmVisitor.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/AsmVisitor.java
deleted file mode 100644
index 81e2934..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/AsmVisitor.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2012 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.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.ClassScanner;
-import com.google.common.annotations.Beta;
-
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.InsnList;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-/**
- * Specialized visitor for running detectors on a class object model.
- * <p>
- * It operates in two phases:
- * <ol>
- * <li> First, it computes a set of maps where it generates a map from each
- * significant method name to a list of detectors to consult for that method
- * name. The set of method names that a detector is interested in is provided
- * by the detectors themselves.
- * <li> Second, it iterates over the DOM a single time. For each method call it finds,
- * it dispatches to any check that has registered interest in that method name.
- * <li> Finally, it runs a full check on those class scanners that do not register
- * specific method names to be checked. This is intended for those detectors
- * that do custom work, not related specifically to method calls.
- * </ol>
- * It also notifies all the detectors before and after the document is processed
- * such that they can do pre- and post-processing.
- * <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
-class AsmVisitor {
- /**
- * Number of distinct node types specified in {@link AbstractInsnNode}. Sadly
- * there isn't a max-constant there, so update this along with ASM library
- * updates.
- */
- public final static int TYPE_COUNT = AbstractInsnNode.LINE + 1;
- private final Map<String, List<ClassScanner>> mMethodNameToChecks =
- new HashMap<String, List<ClassScanner>>();
- private final Map<String, List<ClassScanner>> mMethodOwnerToChecks =
- new HashMap<String, List<ClassScanner>>();
- private final List<Detector> mFullClassChecks = new ArrayList<Detector>();
-
- private final LintClient mClient;
- private final List<? extends Detector> mAllDetectors;
- private List<ClassScanner>[] mNodeTypeDetectors;
-
- // Really want this:
- //<T extends List<Detector> & Detector.ClassScanner> ClassVisitor(T xmlDetectors) {
- // but it makes client code tricky and ugly.
- @SuppressWarnings("unchecked")
- AsmVisitor(@NonNull LintClient client, @NonNull List<? extends Detector> classDetectors) {
- mClient = client;
- mAllDetectors = classDetectors;
-
- // TODO: Check appliesTo() for files, and find a quick way to enable/disable
- // rules when running through a full project!
- for (Detector detector : classDetectors) {
- Detector.ClassScanner scanner = (Detector.ClassScanner) detector;
-
- boolean checkFullClass = true;
-
- Collection<String> names = scanner.getApplicableCallNames();
- if (names != null) {
- checkFullClass = false;
- for (String element : names) {
- List<Detector.ClassScanner> list = mMethodNameToChecks.get(element);
- if (list == null) {
- list = new ArrayList<Detector.ClassScanner>();
- mMethodNameToChecks.put(element, list);
- }
- list.add(scanner);
- }
- }
-
- Collection<String> owners = scanner.getApplicableCallOwners();
- if (owners != null) {
- checkFullClass = false;
- for (String element : owners) {
- List<Detector.ClassScanner> list = mMethodOwnerToChecks.get(element);
- if (list == null) {
- list = new ArrayList<Detector.ClassScanner>();
- mMethodOwnerToChecks.put(element, list);
- }
- list.add(scanner);
- }
- }
-
- int[] types = scanner.getApplicableAsmNodeTypes();
- if (types != null) {
- checkFullClass = false;
- for (int i = 0, n = types.length; i < n; i++) {
- int type = types[i];
- if (type < 0 || type >= TYPE_COUNT) {
- // Can't support this node type: looks like ASM wasn't updated correctly.
- mClient.log(null, "Out of range node type %1$d from detector %2$s",
- type, scanner);
- continue;
- }
- if (mNodeTypeDetectors == null) {
- mNodeTypeDetectors = new List[TYPE_COUNT];
- }
- List<ClassScanner> checks = mNodeTypeDetectors[type];
- if (checks == null) {
- checks = new ArrayList<ClassScanner>();
- mNodeTypeDetectors[type] = checks;
- }
- checks.add(scanner);
- }
- }
-
- if (checkFullClass) {
- mFullClassChecks.add(detector);
- }
- }
- }
-
- @SuppressWarnings("rawtypes") // ASM API uses raw types
- void runClassDetectors(ClassContext context) {
- ClassNode classNode = context.getClassNode();
-
- for (Detector detector : mAllDetectors) {
- detector.beforeCheckFile(context);
- }
-
- for (Detector detector : mFullClassChecks) {
- Detector.ClassScanner scanner = (Detector.ClassScanner) detector;
- scanner.checkClass(context, classNode);
- detector.afterCheckFile(context);
- }
-
- if (!mMethodNameToChecks.isEmpty() || !mMethodOwnerToChecks.isEmpty() ||
- mNodeTypeDetectors != null && mNodeTypeDetectors.length > 0) {
- List methodList = classNode.methods;
- for (Object m : methodList) {
- MethodNode method = (MethodNode) m;
- InsnList nodes = method.instructions;
- for (int i = 0, n = nodes.size(); i < n; i++) {
- AbstractInsnNode instruction = nodes.get(i);
- int type = instruction.getType();
- if (type == AbstractInsnNode.METHOD_INSN) {
- MethodInsnNode call = (MethodInsnNode) instruction;
-
- String owner = call.owner;
- List<ClassScanner> scanners = mMethodOwnerToChecks.get(owner);
- if (scanners != null) {
- for (ClassScanner scanner : scanners) {
- scanner.checkCall(context, classNode, method, call);
- }
- }
-
- String name = call.name;
- scanners = mMethodNameToChecks.get(name);
- if (scanners != null) {
- for (ClassScanner scanner : scanners) {
- scanner.checkCall(context, classNode, method, call);
- }
- }
- }
-
- if (mNodeTypeDetectors != null && type < mNodeTypeDetectors.length) {
- List<ClassScanner> scanners = mNodeTypeDetectors[type];
- if (scanners != null) {
- for (ClassScanner scanner : scanners) {
- scanner.checkInstruction(context, classNode, method, instruction);
- }
- }
- }
- }
- }
- }
-
- for (Detector detector : mAllDetectors) {
- detector.afterCheckFile(context);
- }
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/Configuration.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/Configuration.java
deleted file mode 100644
index ad1c7e1..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/Configuration.java
+++ /dev/null
@@ -1,130 +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.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Severity;
-import com.google.common.annotations.Beta;
-
-/**
- * Lint configuration for an Android project such as which specific rules to include,
- * which specific rules to exclude, and which specific errors to ignore.
- * <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 abstract class Configuration {
- /**
- * Checks whether this issue should be ignored because the user has already
- * suppressed the error? Note that this refers to individual issues being
- * suppressed/ignored, not a whole detector being disabled via something
- * like {@link #isEnabled(Issue)}.
- *
- * @param context the context used by the detector when the issue was found
- * @param issue the issue that was found
- * @param location the location of the issue
- * @param message the associated user message
- * @param data additional information about an issue (see
- * {@link LintClient#report(Context, Issue, Severity, Location, String, Object)}
- * for more information
- * @return true if this issue should be suppressed
- */
- public boolean isIgnored(
- @NonNull Context context,
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- return false;
- }
-
- /**
- * Returns false if the given issue has been disabled. This is just
- * a convenience method for {@code getSeverity(issue) != Severity.IGNORE}.
- *
- * @param issue the issue to check
- * @return false if the issue has been disabled
- */
- public boolean isEnabled(@NonNull Issue issue) {
- return getSeverity(issue) != Severity.IGNORE;
- }
-
- /**
- * Returns the severity for a given issue. This is the same as the
- * {@link Issue#getDefaultSeverity()} unless the user has selected a custom
- * severity (which is tool context dependent).
- *
- * @param issue the issue to look up the severity from
- * @return the severity use for issues for the given detector
- */
- public Severity getSeverity(@NonNull Issue issue) {
- return issue.getDefaultSeverity();
- }
-
- // Editing configurations
-
- /**
- * Marks the given warning as "ignored".
- *
- * @param context The scanning context
- * @param issue the issue to be ignored
- * @param location The location to ignore the warning at, if any
- * @param message The message for the warning
- * @param data The corresponding data, or null
- */
- public abstract void ignore(
- @NonNull Context context,
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data);
-
- /**
- * Sets the severity to be used for this issue.
- *
- * @param issue the issue to set the severity for
- * @param severity the severity to associate with this issue, or null to
- * reset the severity to the default
- */
- public abstract void setSeverity(@NonNull Issue issue, @Nullable Severity severity);
-
- // Bulk editing support
-
- /**
- * Marks the beginning of a "bulk" editing operation with repeated calls to
- * {@link #setSeverity} or {@link #ignore}. After all the values haver been
- * set, the client <b>must</b> call {@link #finishBulkEditing()}. This
- * allows configurations to avoid doing expensive I/O (such as writing out a
- * config XML file) for each and every editing operation when they are
- * applied in bulk, such as from a configuration dialog's "Apply" action.
- */
- public void startBulkEditing() {
- }
-
- /**
- * Marks the end of a "bulk" editing operation, where values should be
- * committed to persistent storage. See {@link #startBulkEditing()} for
- * details.
- */
- public void finishBulkEditing() {
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultConfiguration.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultConfiguration.java
deleted file mode 100644
index 5a8a973..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultConfiguration.java
+++ /dev/null
@@ -1,453 +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.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.Severity;
-import com.google.common.annotations.Beta;
-import com.google.common.io.Closeables;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXParseException;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-/**
- * Default implementation of a {@link Configuration} which reads and writes
- * configuration data into {@code lint.xml} in the project directory.
- * <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 DefaultConfiguration extends Configuration {
- private final LintClient mClient;
- private static final String CONFIG_FILE_NAME = "lint.xml"; //$NON-NLS-1$
-
- // Lint XML File
- @NonNull
- private static final String TAG_ISSUE = "issue"; //$NON-NLS-1$
- @NonNull
- private static final String ATTR_ID = "id"; //$NON-NLS-1$
- @NonNull
- private static final String ATTR_SEVERITY = "severity"; //$NON-NLS-1$
- @NonNull
- private static final String ATTR_PATH = "path"; //$NON-NLS-1$
- @NonNull
- private static final String TAG_IGNORE = "ignore"; //$NON-NLS-1$
-
- private final Configuration mParent;
- protected final Project mProject;
- private final File mConfigFile;
- private boolean mBulkEditing;
-
- /** Map from id to list of project-relative paths for suppressed warnings */
- private Map<String, List<String>> mSuppressed;
-
- /**
- * Map from id to custom {@link Severity} override
- */
- private Map<String, Severity> mSeverity;
-
- protected DefaultConfiguration(
- @NonNull LintClient client,
- @Nullable Project project,
- @Nullable Configuration parent,
- @NonNull File configFile) {
- mClient = client;
- mProject = project;
- mParent = parent;
- mConfigFile = configFile;
- }
-
- protected DefaultConfiguration(
- @NonNull LintClient client,
- @NonNull Project project,
- @Nullable Configuration parent) {
- this(client, project, parent, new File(project.getDir(), CONFIG_FILE_NAME));
- }
-
- /**
- * Creates a new {@link DefaultConfiguration}
- *
- * @param client the client to report errors to etc
- * @param project the associated project
- * @param parent the parent/fallback configuration or null
- * @return a new configuration
- */
- @NonNull
- public static DefaultConfiguration create(
- @NonNull LintClient client,
- @NonNull Project project,
- @Nullable Configuration parent) {
- return new DefaultConfiguration(client, project, parent);
- }
-
- /**
- * Creates a new {@link DefaultConfiguration} for the given lint config
- * file, not affiliated with a project. This is used for global
- * configurations.
- *
- * @param client the client to report errors to etc
- * @param lintFile the lint file containing the configuration
- * @return a new configuration
- */
- @NonNull
- public static DefaultConfiguration create(@NonNull LintClient client, @NonNull File lintFile) {
- return new DefaultConfiguration(client, null /*project*/, null /*parent*/, lintFile);
- }
-
- @Override
- public boolean isIgnored(
- @NonNull Context context,
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- ensureInitialized();
-
- String id = issue.getId();
- List<String> paths = mSuppressed.get(id);
- if (paths != null && location != null) {
- File file = location.getFile();
- String relativePath = context.getProject().getRelativePath(file);
- for (String suppressedPath : paths) {
- if (suppressedPath.equals(relativePath)) {
- return true;
- }
- }
- }
-
- if (mParent != null) {
- return mParent.isIgnored(context, issue, location, message, data);
- }
-
- return false;
- }
-
- @NonNull
- protected Severity getDefaultSeverity(@NonNull Issue issue) {
- if (!issue.isEnabledByDefault()) {
- return Severity.IGNORE;
- }
-
- return issue.getDefaultSeverity();
- }
-
- @Override
- @NonNull
- public Severity getSeverity(@NonNull Issue issue) {
- ensureInitialized();
-
- Severity severity = mSeverity.get(issue.getId());
- if (severity != null) {
- return severity;
- }
-
- if (mParent != null) {
- return mParent.getSeverity(issue);
- }
-
- return getDefaultSeverity(issue);
- }
-
- private void ensureInitialized() {
- if (mSuppressed == null) {
- readConfig();
- }
- }
-
- private void formatError(String message, Object... args) {
- if (args != null && args.length > 0) {
- message = String.format(message, args);
- }
- message = "Failed to parse lint.xml configuration file: " + message;
- LintDriver driver = new LintDriver(new IssueRegistry() {
- @Override @NonNull public List<Issue> getIssues() {
- return Collections.emptyList();
- }
- }, mClient);
- mClient.report(new Context(driver, mProject, mProject, mConfigFile),
- IssueRegistry.LINT_ERROR,
- mProject.getConfiguration().getSeverity(IssueRegistry.LINT_ERROR),
- Location.create(mConfigFile), message, null);
- }
-
- private void readConfig() {
- mSuppressed = new HashMap<String, List<String>>();
- mSeverity = new HashMap<String, Severity>();
-
- if (!mConfigFile.exists()) {
- return;
- }
-
- @SuppressWarnings("resource") // Eclipse doesn't know about Closeables.closeQuietly
- BufferedInputStream input = null;
- try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- input = new BufferedInputStream(new FileInputStream(mConfigFile));
- InputSource source = new InputSource(input);
- factory.setNamespaceAware(false);
- factory.setValidating(false);
- DocumentBuilder builder = factory.newDocumentBuilder();
- Document document = builder.parse(source);
- NodeList issues = document.getElementsByTagName(TAG_ISSUE);
- for (int i = 0, count = issues.getLength(); i < count; i++) {
- Node node = issues.item(i);
- Element element = (Element) node;
- String id = element.getAttribute(ATTR_ID);
- if (id.length() == 0) {
- formatError("Invalid lint config file: Missing required issue id attribute");
- continue;
- }
-
- NamedNodeMap attributes = node.getAttributes();
- for (int j = 0, n = attributes.getLength(); j < n; j++) {
- Node attribute = attributes.item(j);
- String name = attribute.getNodeName();
- String value = attribute.getNodeValue();
- if (ATTR_ID.equals(name)) {
- // already handled
- } else if (ATTR_SEVERITY.equals(name)) {
- for (Severity severity : Severity.values()) {
- if (value.equalsIgnoreCase(severity.name())) {
- mSeverity.put(id, severity);
- break;
- }
- }
- } else {
- formatError("Unexpected attribute \"%1$s\"", name);
- }
- }
-
- // Look up ignored errors
- NodeList childNodes = element.getChildNodes();
- if (childNodes.getLength() > 0) {
- for (int j = 0, n = childNodes.getLength(); j < n; j++) {
- Node child = childNodes.item(j);
- if (child.getNodeType() == Node.ELEMENT_NODE) {
- Element ignore = (Element) child;
- String path = ignore.getAttribute(ATTR_PATH);
- if (path.length() == 0) {
- formatError("Missing required %1$s attribute under %2$s",
- ATTR_PATH, id);
- } else {
- List<String> paths = mSuppressed.get(id);
- if (paths == null) {
- paths = new ArrayList<String>(n / 2 + 1);
- mSuppressed.put(id, paths);
- }
- paths.add(path);
- }
- }
- }
- }
- }
- } catch (SAXParseException e) {
- formatError(e.getMessage());
- } catch (Exception e) {
- mClient.log(e, null);
- } finally {
- Closeables.closeQuietly(input);
- }
- }
-
- private void writeConfig() {
- try {
- // Write the contents to a new file first such that we don't clobber the
- // existing file if some I/O error occurs.
- File file = new File(mConfigFile.getParentFile(),
- mConfigFile.getName() + ".new"); //$NON-NLS-1$
-
- Writer writer = new BufferedWriter(new FileWriter(file));
- writer.write(
- "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + //$NON-NLS-1$
- "<lint>\n"); //$NON-NLS-1$
-
- if (mSuppressed.size() > 0 || mSeverity.size() > 0) {
- // Process the maps in a stable sorted order such that if the
- // files are checked into version control with the project,
- // there are no random diffs just because hashing algorithms
- // differ:
- Set<String> idSet = new HashSet<String>();
- for (String id : mSuppressed.keySet()) {
- idSet.add(id);
- }
- for (String id : mSeverity.keySet()) {
- idSet.add(id);
- }
- List<String> ids = new ArrayList<String>(idSet);
- Collections.sort(ids);
-
- for (String id : ids) {
- writer.write(" <"); //$NON-NLS-1$
- writer.write(TAG_ISSUE);
- writeAttribute(writer, ATTR_ID, id);
- Severity severity = mSeverity.get(id);
- if (severity != null) {
- writeAttribute(writer, ATTR_SEVERITY,
- severity.name().toLowerCase(Locale.US));
- }
-
- List<String> paths = mSuppressed.get(id);
- if (paths != null && paths.size() > 0) {
- writer.write('>');
- writer.write('\n');
- // The paths are already kept in sorted order when they are modified
- // by ignore(...)
- for (String path : paths) {
- writer.write(" <"); //$NON-NLS-1$
- writer.write(TAG_IGNORE);
- writeAttribute(writer, ATTR_PATH, path);
- writer.write(" />\n"); //$NON-NLS-1$
- }
- writer.write(" </"); //$NON-NLS-1$
- writer.write(TAG_ISSUE);
- writer.write('>');
- writer.write('\n');
- } else {
- writer.write(" />\n"); //$NON-NLS-1$
- }
- }
- }
-
- writer.write("</lint>"); //$NON-NLS-1$
- writer.close();
-
- // Move file into place: move current version to lint.xml~ (removing the old ~ file
- // if it exists), then move the new version to lint.xml.
- File oldFile = new File(mConfigFile.getParentFile(),
- mConfigFile.getName() + "~"); //$NON-NLS-1$
- if (oldFile.exists()) {
- oldFile.delete();
- }
- if (mConfigFile.exists()) {
- mConfigFile.renameTo(oldFile);
- }
- boolean ok = file.renameTo(mConfigFile);
- if (ok && oldFile.exists()) {
- oldFile.delete();
- }
- } catch (Exception e) {
- mClient.log(e, null);
- }
- }
-
- private static void writeAttribute(
- @NonNull Writer writer, @NonNull String name, @NonNull String value)
- throws IOException {
- writer.write(' ');
- writer.write(name);
- writer.write('=');
- writer.write('"');
- writer.write(value);
- writer.write('"');
- }
-
- @Override
- public void ignore(
- @NonNull Context context,
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- // This configuration only supports suppressing warnings on a per-file basis
- if (location != null) {
- ignore(issue, location.getFile());
- }
- }
-
- /**
- * Marks the given issue and file combination as being ignored.
- *
- * @param issue the issue to be ignored in the given file
- * @param file the file to ignore the issue in
- */
- public void ignore(@NonNull Issue issue, @NonNull File file) {
- ensureInitialized();
-
- String path = mProject != null ? mProject.getRelativePath(file) : file.getPath();
-
- List<String> paths = mSuppressed.get(issue.getId());
- if (paths == null) {
- paths = new ArrayList<String>();
- mSuppressed.put(issue.getId(), paths);
- }
- paths.add(path);
-
- // Keep paths sorted alphabetically; makes XML output stable
- Collections.sort(paths);
-
- if (!mBulkEditing) {
- writeConfig();
- }
- }
-
- @Override
- public void setSeverity(@NonNull Issue issue, @Nullable Severity severity) {
- ensureInitialized();
-
- String id = issue.getId();
- if (severity == null) {
- mSeverity.remove(id);
- } else {
- mSeverity.put(id, severity);
- }
-
- if (!mBulkEditing) {
- writeConfig();
- }
- }
-
- @Override
- public void startBulkEditing() {
- mBulkEditing = true;
- }
-
- @Override
- public void finishBulkEditing() {
- mBulkEditing = false;
- writeConfig();
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java
deleted file mode 100644
index b5ae26d..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java
+++ /dev/null
@@ -1,233 +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.client.api;
-
-import static com.android.SdkConstants.ABSOLUTE_LAYOUT;
-import static com.android.SdkConstants.ABS_LIST_VIEW;
-import static com.android.SdkConstants.ABS_SEEK_BAR;
-import static com.android.SdkConstants.ABS_SPINNER;
-import static com.android.SdkConstants.ADAPTER_VIEW;
-import static com.android.SdkConstants.AUTO_COMPLETE_TEXT_VIEW;
-import static com.android.SdkConstants.BUTTON;
-import static com.android.SdkConstants.CHECKED_TEXT_VIEW;
-import static com.android.SdkConstants.CHECK_BOX;
-import static com.android.SdkConstants.COMPOUND_BUTTON;
-import static com.android.SdkConstants.EDIT_TEXT;
-import static com.android.SdkConstants.EXPANDABLE_LIST_VIEW;
-import static com.android.SdkConstants.FRAME_LAYOUT;
-import static com.android.SdkConstants.GALLERY;
-import static com.android.SdkConstants.GRID_VIEW;
-import static com.android.SdkConstants.HORIZONTAL_SCROLL_VIEW;
-import static com.android.SdkConstants.IMAGE_BUTTON;
-import static com.android.SdkConstants.IMAGE_VIEW;
-import static com.android.SdkConstants.LINEAR_LAYOUT;
-import static com.android.SdkConstants.LIST_VIEW;
-import static com.android.SdkConstants.MULTI_AUTO_COMPLETE_TEXT_VIEW;
-import static com.android.SdkConstants.PROGRESS_BAR;
-import static com.android.SdkConstants.RADIO_BUTTON;
-import static com.android.SdkConstants.RADIO_GROUP;
-import static com.android.SdkConstants.RELATIVE_LAYOUT;
-import static com.android.SdkConstants.SCROLL_VIEW;
-import static com.android.SdkConstants.SEEK_BAR;
-import static com.android.SdkConstants.SPINNER;
-import static com.android.SdkConstants.SURFACE_VIEW;
-import static com.android.SdkConstants.SWITCH;
-import static com.android.SdkConstants.TABLE_LAYOUT;
-import static com.android.SdkConstants.TABLE_ROW;
-import static com.android.SdkConstants.TAB_HOST;
-import static com.android.SdkConstants.TAB_WIDGET;
-import static com.android.SdkConstants.TEXT_VIEW;
-import static com.android.SdkConstants.TOGGLE_BUTTON;
-import static com.android.SdkConstants.VIEW;
-import static com.android.SdkConstants.VIEW_ANIMATOR;
-import static com.android.SdkConstants.VIEW_GROUP;
-import static com.android.SdkConstants.VIEW_PKG_PREFIX;
-import static com.android.SdkConstants.VIEW_STUB;
-import static com.android.SdkConstants.VIEW_SWITCHER;
-import static com.android.SdkConstants.WEB_VIEW;
-import static com.android.SdkConstants.WIDGET_PKG_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.annotations.Beta;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Default simple implementation of an {@link SdkInfo}
- * <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
-class DefaultSdkInfo extends SdkInfo {
- @Override
- @Nullable
- public String getParentViewName(@NonNull String name) {
- name = getRawType(name);
-
- return PARENTS.get(name);
- }
-
- @Override
- @Nullable
- public String getParentViewClass(@NonNull String fqcn) {
- int index = fqcn.lastIndexOf('.');
- if (index != -1) {
- fqcn = fqcn.substring(index + 1);
- }
-
- String parent = PARENTS.get(fqcn);
- if (parent == null) {
- return null;
- }
- // The map only stores class names internally; correct for full package paths
- if (parent.equals(VIEW) || parent.equals(VIEW_GROUP) || parent.equals(SURFACE_VIEW)) {
- return VIEW_PKG_PREFIX + parent;
- } else {
- return WIDGET_PKG_PREFIX + parent;
- }
- }
-
- @Override
- public boolean isSubViewOf(@NonNull String parentType, @NonNull String childType) {
- String parent = getRawType(parentType);
- String child = getRawType(childType);
-
- // Do analysis just on non-fqcn paths
- if (parent.indexOf('.') != -1) {
- parent = parent.substring(parent.lastIndexOf('.') + 1);
- }
- if (child.indexOf('.') != -1) {
- child = child.substring(child.lastIndexOf('.') + 1);
- }
-
- if (parent.equals(VIEW)) {
- return true;
- }
-
- while (!child.equals(VIEW)) {
- if (parent.equals(child)) {
- return true;
- }
- child = PARENTS.get(child);
- if (child == null) {
- // Unknown view - err on the side of caution
- return true;
- }
- }
-
- return false;
- }
-
- // Strip off type parameters, e.g. AdapterView<?> => AdapterView
- private static String getRawType(String type) {
- if (type != null) {
- int index = type.indexOf('<');
- if (index != -1) {
- type = type.substring(0, index);
- }
- }
-
- return type;
- }
-
- private static final int CLASS_COUNT = 59;
-
- @NonNull
- private static final Map<String, String> PARENTS = new HashMap<String, String>(CLASS_COUNT);
-
- static {
- PARENTS.put(COMPOUND_BUTTON, BUTTON);
- PARENTS.put(ABS_SPINNER, ADAPTER_VIEW);
- PARENTS.put(ABS_LIST_VIEW, ADAPTER_VIEW);
- PARENTS.put(ABS_SEEK_BAR, ADAPTER_VIEW);
- PARENTS.put(ADAPTER_VIEW, VIEW_GROUP);
- PARENTS.put(VIEW_GROUP, VIEW);
-
- PARENTS.put(TEXT_VIEW, VIEW);
- PARENTS.put(CHECKED_TEXT_VIEW, TEXT_VIEW);
- PARENTS.put(RADIO_BUTTON, COMPOUND_BUTTON);
- PARENTS.put(SPINNER, ABS_SPINNER);
- PARENTS.put(IMAGE_BUTTON, IMAGE_VIEW);
- PARENTS.put(IMAGE_VIEW, VIEW);
- PARENTS.put(EDIT_TEXT, TEXT_VIEW);
- PARENTS.put(PROGRESS_BAR, VIEW);
- PARENTS.put(TOGGLE_BUTTON, COMPOUND_BUTTON);
- PARENTS.put(VIEW_STUB, VIEW);
- PARENTS.put(BUTTON, TEXT_VIEW);
- PARENTS.put(SEEK_BAR, ABS_SEEK_BAR);
- PARENTS.put(CHECK_BOX, COMPOUND_BUTTON);
- PARENTS.put(SWITCH, COMPOUND_BUTTON);
- PARENTS.put(GALLERY, ABS_SPINNER);
- PARENTS.put(SURFACE_VIEW, VIEW);
- PARENTS.put(ABSOLUTE_LAYOUT, VIEW_GROUP);
- PARENTS.put(LINEAR_LAYOUT, VIEW_GROUP);
- PARENTS.put(RELATIVE_LAYOUT, VIEW_GROUP);
- PARENTS.put(LIST_VIEW, ABS_LIST_VIEW);
- PARENTS.put(VIEW_SWITCHER, VIEW_ANIMATOR);
- PARENTS.put(FRAME_LAYOUT, VIEW_GROUP);
- PARENTS.put(HORIZONTAL_SCROLL_VIEW, FRAME_LAYOUT);
- PARENTS.put(VIEW_ANIMATOR, FRAME_LAYOUT);
- PARENTS.put(TAB_HOST, FRAME_LAYOUT);
- PARENTS.put(TABLE_ROW, LINEAR_LAYOUT);
- PARENTS.put(RADIO_GROUP, LINEAR_LAYOUT);
- PARENTS.put(TAB_WIDGET, LINEAR_LAYOUT);
- PARENTS.put(EXPANDABLE_LIST_VIEW, LIST_VIEW);
- PARENTS.put(TABLE_LAYOUT, LINEAR_LAYOUT);
- PARENTS.put(SCROLL_VIEW, FRAME_LAYOUT);
- PARENTS.put(GRID_VIEW, ABS_LIST_VIEW);
- PARENTS.put(WEB_VIEW, ABSOLUTE_LAYOUT);
- PARENTS.put(AUTO_COMPLETE_TEXT_VIEW, EDIT_TEXT);
- PARENTS.put(MULTI_AUTO_COMPLETE_TEXT_VIEW, AUTO_COMPLETE_TEXT_VIEW);
-
- PARENTS.put("CheckedTextView", TEXT_VIEW); //$NON-NLS-1$
- PARENTS.put("MediaController", FRAME_LAYOUT); //$NON-NLS-1$
- PARENTS.put("SlidingDrawer", VIEW_GROUP); //$NON-NLS-1$
- PARENTS.put("DialerFilter", RELATIVE_LAYOUT); //$NON-NLS-1$
- PARENTS.put("DigitalClock", TEXT_VIEW); //$NON-NLS-1$
- PARENTS.put("Chronometer", TEXT_VIEW); //$NON-NLS-1$
- PARENTS.put("ImageSwitcher", VIEW_SWITCHER); //$NON-NLS-1$
- PARENTS.put("TextSwitcher", VIEW_SWITCHER); //$NON-NLS-1$
- PARENTS.put("AnalogClock", VIEW); //$NON-NLS-1$
- PARENTS.put("TwoLineListItem", RELATIVE_LAYOUT); //$NON-NLS-1$
- PARENTS.put("ZoomControls", LINEAR_LAYOUT); //$NON-NLS-1$
- PARENTS.put("DatePicker", FRAME_LAYOUT); //$NON-NLS-1$
- PARENTS.put("TimePicker", FRAME_LAYOUT); //$NON-NLS-1$
- PARENTS.put("VideoView", SURFACE_VIEW); //$NON-NLS-1$
- PARENTS.put("ZoomButton", IMAGE_BUTTON); //$NON-NLS-1$
- PARENTS.put("RatingBar", ABS_SEEK_BAR); //$NON-NLS-1$
- PARENTS.put("ViewFlipper", VIEW_ANIMATOR); //$NON-NLS-1$
- PARENTS.put("NumberPicker", LINEAR_LAYOUT); //$NON-NLS-1$
-
- assert PARENTS.size() <= CLASS_COUNT : PARENTS.size();
-
- /*
- // Check that all widgets lead to the root view
- if (LintUtils.assertionsEnabled()) {
- for (String key : PARENTS.keySet()) {
- String parent = PARENTS.get(key);
- if (!parent.equals(VIEW)) {
- String grandParent = PARENTS.get(parent);
- assert grandParent != null : parent;
- }
- }
- }
- */
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/IDomParser.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/IDomParser.java
deleted file mode 100644
index 1a70fac..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/IDomParser.java
+++ /dev/null
@@ -1,93 +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.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.annotations.Beta;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-/**
- * A wrapper for an XML parser. This allows tools integrating lint to map directly
- * to builtin services, such as already-parsed data structures in XML editors.
- * <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 interface IDomParser {
- /**
- * Parse the file pointed to by the given context and return as a Document
- *
- * @param context the context pointing to the file to be parsed, typically
- * via {@link Context#getContents()} but the file handle (
- * {@link Context#file} can also be used to map to an existing
- * editor buffer in the surrounding tool, etc)
- * @return the parsed DOM document, or null if parsing fails
- */
- @Nullable
- Document parseXml(@NonNull XmlContext context);
-
- /**
- * Returns a {@link Location} for the given DOM node
- *
- * @param context information about the file being parsed
- * @param node the node to create a location for
- * @return a location for the given node
- */
- @NonNull
- Location getLocation(@NonNull XmlContext context, @NonNull Node node);
-
- /**
- * Returns a {@link Location} for the given DOM node. Like
- * {@link #getLocation(XmlContext, Node)}, but allows a position range that
- * is a subset of the node range.
- *
- * @param context information about the file being parsed
- * @param node the node to create a location for
- * @param start the starting position within the node, inclusive
- * @param end the ending position within the node, exclusive
- * @return a location for the given node
- */
- @NonNull
- Location getLocation(@NonNull XmlContext context, @NonNull Node node, int start, int end);
-
- /**
- * Creates a light-weight handle to a location for the given node. It can be
- * turned into a full fledged location by
- * {@link com.android.tools.lint.detector.api.Location.Handle#resolve()}.
- *
- * @param context the context providing the node
- * @param node the node (element or attribute) to create a location handle
- * for
- * @return a location handle
- */
- @NonNull
- Location.Handle createLocationHandle(@NonNull XmlContext context, @NonNull Node node);
-
- /**
- * Dispose any data structures held for the given context.
- * @param context information about the file previously parsed
- * @param document the document that was parsed and is now being disposed
- */
- void dispose(@NonNull XmlContext context, @NonNull Document document);
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/IJavaParser.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/IJavaParser.java
deleted file mode 100644
index 9b74f16..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/IJavaParser.java
+++ /dev/null
@@ -1,76 +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.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.Location;
-
-import lombok.ast.Node;
-
-/**
- * A wrapper for a Java parser. This allows tools integrating lint to map directly
- * to builtin services, such as already-parsed data structures in Java editors.
- * <p/>
- * <b>NOTE: This is not a or final API; if you rely on this be prepared
- * to adjust your code for the next tools release.</b>
- */
-public interface IJavaParser {
- /**
- * Parse the file pointed to by the given context.
- *
- * @param context the context pointing to the file to be parsed, typically
- * via {@link Context#getContents()} but the file handle (
- * {@link Context#file} can also be used to map to an existing
- * editor buffer in the surrounding tool, etc)
- * @return the compilation unit node for the file
- */
- @Nullable
- Node parseJava(@NonNull JavaContext context);
-
- /**
- * Returns a {@link Location} for the given node
- *
- * @param context information about the file being parsed
- * @param node the node to create a location for
- * @return a location for the given node
- */
- @NonNull
- Location getLocation(@NonNull JavaContext context, @NonNull Node node);
-
- /**
- * Creates a light-weight handle to a location for the given node. It can be
- * turned into a full fledged location by
- * {@link com.android.tools.lint.detector.api.Location.Handle#resolve()}.
- *
- * @param context the context providing the node
- * @param node the node (element or attribute) to create a location handle
- * for
- * @return a location handle
- */
- @NonNull
- Location.Handle createLocationHandle(@NonNull JavaContext context, @NonNull Node node);
-
- /**
- * Dispose any data structures held for the given context.
- * @param context information about the file previously parsed
- * @param compilationUnit the compilation unit being disposed
- */
- void dispose(@NonNull JavaContext context, @NonNull Node compilationUnit);
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/IssueRegistry.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/IssueRegistry.java
deleted file mode 100644
index e780d79..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/IssueRegistry.java
+++ /dev/null
@@ -1,253 +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.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.google.common.annotations.Beta;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/** Registry which provides a list of checks to be performed on an Android project
- * <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 abstract class IssueRegistry {
- private static List<Category> sCategories;
- private static Map<String, Issue> sIdToIssue;
-
- /**
- * Issue reported by lint (not a specific detector) when it cannot even
- * parse an XML file prior to analysis
- */
- @NonNull
- public static final Issue PARSER_ERROR = Issue.create(
- "ParserError", //$NON-NLS-1$
- "Finds files that contain fatal parser errors",
- "Lint will ignore any files that contain fatal parsing errors. These may contain " +
- "other errors, or contain code which affects issues in other files.",
- Category.CORRECTNESS,
- 10,
- Severity.ERROR,
- Detector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /**
- * Issue reported by lint for various other issues which prevents lint from
- * running normally when it's not necessarily an error in the user's code base.
- */
- @NonNull
- public static final Issue LINT_ERROR = Issue.create(
- "LintError", //$NON-NLS-1$
- "Isues related to running lint itself, such as failure to read files, etc",
- "This issue type represents a problem running lint itself. Examples include " +
- "failure to find bytecode for source files (which means certain detectors " +
- "could not be run), parsing errors in lint configuration files, etc." +
- "\n" +
- "These errors are not errors in your own code, but they are shown to make " +
- "it clear that some checks were not completed.",
-
- Category.LINT,
- 10,
- Severity.ERROR,
- Detector.class,
- Scope.RESOURCE_FILE_SCOPE);
-
- /**
- * Returns the list of issues that can be found by all known detectors.
- *
- * @return the list of issues to be checked (including those that may be
- * disabled!)
- */
- @NonNull
- public abstract List<Issue> getIssues();
-
- /**
- * Creates a list of detectors applicable to the given cope, and with the
- * given configuration.
- *
- * @param client the client to report errors to
- * @param configuration the configuration to look up which issues are
- * enabled etc from
- * @param scope the scope for the analysis, to filter out detectors that
- * require wider analysis than is currently being performed
- * @param scopeToDetectors an optional map which (if not null) will be
- * filled by this method to contain mappings from each scope to
- * the applicable detectors for that scope
- * @return a list of new detector instances
- */
- @NonNull
- final List<? extends Detector> createDetectors(
- @NonNull LintClient client,
- @NonNull Configuration configuration,
- @NonNull EnumSet<Scope> scope,
- @Nullable Map<Scope, List<Detector>> scopeToDetectors) {
- List<Issue> issues = getIssues();
- Set<Class<? extends Detector>> detectorClasses = new HashSet<Class<? extends Detector>>();
- Map<Class<? extends Detector>, EnumSet<Scope>> detectorToScope =
- new HashMap<Class<? extends Detector>, EnumSet<Scope>>();
- for (Issue issue : issues) {
- Class<? extends Detector> detectorClass = issue.getDetectorClass();
- EnumSet<Scope> issueScope = issue.getScope();
- if (!detectorClasses.contains(detectorClass)) {
- // Determine if the issue is enabled
- if (!configuration.isEnabled(issue)) {
- continue;
- }
-
- // Determine if the scope matches
- if (!issue.isAdequate(scope)) {
- continue;
- }
-
- detectorClass = client.replaceDetector(detectorClass);
-
- assert detectorClass != null : issue.getId();
- detectorClasses.add(detectorClass);
- }
-
- if (scopeToDetectors != null) {
- EnumSet<Scope> s = detectorToScope.get(detectorClass);
- if (s == null) {
- detectorToScope.put(detectorClass, issueScope);
- } else if (!s.containsAll(issueScope)) {
- EnumSet<Scope> union = EnumSet.copyOf(s);
- union.addAll(issueScope);
- detectorToScope.put(detectorClass, union);
- }
- }
- }
-
- List<Detector> detectors = new ArrayList<Detector>(detectorClasses.size());
- for (Class<? extends Detector> clz : detectorClasses) {
- try {
- Detector detector = clz.newInstance();
- detectors.add(detector);
-
- if (scopeToDetectors != null) {
- EnumSet<Scope> union = detectorToScope.get(clz);
- for (Scope s : union) {
- List<Detector> list = scopeToDetectors.get(s);
- if (list == null) {
- list = new ArrayList<Detector>();
- scopeToDetectors.put(s, list);
- }
- list.add(detector);
- }
-
- }
- } catch (Throwable t) {
- client.log(t, "Can't initialize detector %1$s", clz.getName()); //$NON-NLS-1$
- }
- }
-
- return detectors;
- }
-
- /**
- * Returns true if the given id represents a valid issue id
- *
- * @param id the id to be checked
- * @return true if the given id is valid
- */
- public final boolean isIssueId(@NonNull String id) {
- return getIssue(id) != null;
- }
-
- /**
- * Returns true if the given category is a valid category
- *
- * @param name the category name to be checked
- * @return true if the given string is a valid category
- */
- public final boolean isCategoryName(@NonNull String name) {
- for (Category c : getCategories()) {
- if (c.getName().equals(name) || c.getFullName().equals(name)) {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Returns the available categories
- *
- * @return an iterator for all the categories, never null
- */
- @NonNull
- public List<Category> getCategories() {
- if (sCategories == null) {
- final Set<Category> categories = new HashSet<Category>();
- for (Issue issue : getIssues()) {
- categories.add(issue.getCategory());
- }
- List<Category> sorted = new ArrayList<Category>(categories);
- Collections.sort(sorted);
- sCategories = Collections.unmodifiableList(sorted);
- }
-
- return sCategories;
- }
-
- /**
- * Returns the issue for the given id, or null if it's not a valid id
- *
- * @param id the id to be checked
- * @return the corresponding issue, or null
- */
- @Nullable
- public final Issue getIssue(@NonNull String id) {
- if (sIdToIssue == null) {
- List<Issue> issues = getIssues();
- sIdToIssue = new HashMap<String, Issue>(issues.size());
- for (Issue issue : issues) {
- sIdToIssue.put(issue.getId(), issue);
- }
-
- sIdToIssue.put(PARSER_ERROR.getId(), PARSER_ERROR);
- sIdToIssue.put(LINT_ERROR.getId(), LINT_ERROR);
- }
- return sIdToIssue.get(id);
- }
-
- /**
- * Reset the registry such that it recomputes its available issues.
- * <p>
- * NOTE: This is only intended for testing purposes.
- */
- @VisibleForTesting
- protected static void reset() {
- sIdToIssue = null;
- sCategories = null;
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/JavaVisitor.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/JavaVisitor.java
deleted file mode 100644
index b1d8832..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/JavaVisitor.java
+++ /dev/null
@@ -1,1192 +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.client.api;
-
-import static com.android.SdkConstants.ANDROID_PKG;
-import static com.android.SdkConstants.R_CLASS;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.JavaScanner;
-import com.android.tools.lint.detector.api.Detector.XmlScanner;
-import com.android.tools.lint.detector.api.JavaContext;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import lombok.ast.AlternateConstructorInvocation;
-import lombok.ast.Annotation;
-import lombok.ast.AnnotationDeclaration;
-import lombok.ast.AnnotationElement;
-import lombok.ast.AnnotationMethodDeclaration;
-import lombok.ast.AnnotationValueArray;
-import lombok.ast.ArrayAccess;
-import lombok.ast.ArrayCreation;
-import lombok.ast.ArrayDimension;
-import lombok.ast.ArrayInitializer;
-import lombok.ast.Assert;
-import lombok.ast.AstVisitor;
-import lombok.ast.BinaryExpression;
-import lombok.ast.Block;
-import lombok.ast.BooleanLiteral;
-import lombok.ast.Break;
-import lombok.ast.Case;
-import lombok.ast.Cast;
-import lombok.ast.Catch;
-import lombok.ast.CharLiteral;
-import lombok.ast.ClassDeclaration;
-import lombok.ast.ClassLiteral;
-import lombok.ast.Comment;
-import lombok.ast.CompilationUnit;
-import lombok.ast.ConstructorDeclaration;
-import lombok.ast.ConstructorInvocation;
-import lombok.ast.Continue;
-import lombok.ast.Default;
-import lombok.ast.DoWhile;
-import lombok.ast.EmptyDeclaration;
-import lombok.ast.EmptyStatement;
-import lombok.ast.EnumConstant;
-import lombok.ast.EnumDeclaration;
-import lombok.ast.EnumTypeBody;
-import lombok.ast.Expression;
-import lombok.ast.ExpressionStatement;
-import lombok.ast.FloatingPointLiteral;
-import lombok.ast.For;
-import lombok.ast.ForEach;
-import lombok.ast.ForwardingAstVisitor;
-import lombok.ast.Identifier;
-import lombok.ast.If;
-import lombok.ast.ImportDeclaration;
-import lombok.ast.InlineIfExpression;
-import lombok.ast.InstanceInitializer;
-import lombok.ast.InstanceOf;
-import lombok.ast.IntegralLiteral;
-import lombok.ast.InterfaceDeclaration;
-import lombok.ast.KeywordModifier;
-import lombok.ast.LabelledStatement;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.MethodInvocation;
-import lombok.ast.Modifiers;
-import lombok.ast.Node;
-import lombok.ast.NormalTypeBody;
-import lombok.ast.NullLiteral;
-import lombok.ast.PackageDeclaration;
-import lombok.ast.Return;
-import lombok.ast.Select;
-import lombok.ast.StaticInitializer;
-import lombok.ast.StringLiteral;
-import lombok.ast.Super;
-import lombok.ast.SuperConstructorInvocation;
-import lombok.ast.Switch;
-import lombok.ast.Synchronized;
-import lombok.ast.This;
-import lombok.ast.Throw;
-import lombok.ast.Try;
-import lombok.ast.TypeReference;
-import lombok.ast.TypeReferencePart;
-import lombok.ast.TypeVariable;
-import lombok.ast.UnaryExpression;
-import lombok.ast.VariableDeclaration;
-import lombok.ast.VariableDefinition;
-import lombok.ast.VariableDefinitionEntry;
-import lombok.ast.VariableReference;
-import lombok.ast.While;
-
-
-/**
- * Specialized visitor for running detectors on a Java AST.
- * It operates in three phases:
- * <ol>
- * <li> First, it computes a set of maps where it generates a map from each
- * significant AST attribute (such as method call names) to a list
- * of detectors to consult whenever that attribute is encountered.
- * Examples of "attributes" are method names, Android resource identifiers,
- * and general AST node types such as "cast" nodes etc. These are
- * defined on the {@link JavaScanner} interface.
- * <li> Second, it iterates over the document a single time, delegating to
- * the detectors found at each relevant AST attribute.
- * <li> Finally, it calls the remaining visitors (those that need to process a
- * whole document on their own).
- * </ol>
- * It also notifies all the detectors before and after the document is processed
- * such that they can do pre- and post-processing.
- */
-public class JavaVisitor {
- /** Default size of lists holding detectors of the same type for a given node type */
- private static final int SAME_TYPE_COUNT = 8;
-
- private final Map<String, List<VisitingDetector>> mMethodDetectors =
- new HashMap<String, List<VisitingDetector>>();
- private final List<VisitingDetector> mResourceFieldDetectors =
- new ArrayList<VisitingDetector>();
- private final List<VisitingDetector> mAllDetectors;
- private final List<VisitingDetector> mFullTreeDetectors;
- private Map<Class<? extends Node>, List<VisitingDetector>> mNodeTypeDetectors =
- new HashMap<Class<? extends Node>, List<VisitingDetector>>();
- private final IJavaParser mParser;
-
- JavaVisitor(@NonNull IJavaParser parser, @NonNull List<Detector> detectors) {
- mParser = parser;
- mAllDetectors = new ArrayList<VisitingDetector>(detectors.size());
- mFullTreeDetectors = new ArrayList<VisitingDetector>(detectors.size());
-
- for (Detector detector : detectors) {
- VisitingDetector v = new VisitingDetector(detector, (JavaScanner) detector);
- mAllDetectors.add(v);
-
- List<Class<? extends Node>> nodeTypes = detector.getApplicableNodeTypes();
- if (nodeTypes != null) {
- for (Class<? extends Node> type : nodeTypes) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(type);
- if (list == null) {
- list = new ArrayList<VisitingDetector>(SAME_TYPE_COUNT);
- mNodeTypeDetectors.put(type, list);
- }
- list.add(v);
- }
- }
-
- List<String> names = detector.getApplicableMethodNames();
- if (names != null) {
- // not supported in Java visitors; adding a method invocation node is trivial
- // for that case.
- assert names != XmlScanner.ALL;
-
- for (String name : names) {
- List<VisitingDetector> list = mMethodDetectors.get(name);
- if (list == null) {
- list = new ArrayList<VisitingDetector>(SAME_TYPE_COUNT);
- mMethodDetectors.put(name, list);
- }
- list.add(v);
- }
- }
-
- if (detector.appliesToResourceRefs()) {
- mResourceFieldDetectors.add(v);
- } else if ((names == null || names.size() == 0)
- && (nodeTypes == null || nodeTypes.size() ==0)) {
- mFullTreeDetectors.add(v);
- }
- }
- }
-
- void visitFile(@NonNull JavaContext context, @NonNull File file) {
- context.parser = mParser;
-
- Node compilationUnit = null;
- try {
- compilationUnit = mParser.parseJava(context);
- if (compilationUnit == null) {
- // No need to log this; the parser should be reporting
- // a full warning (such as IssueRegistry#PARSER_ERROR)
- // with details, location, etc.
- return;
- }
- context.compilationUnit = compilationUnit;
-
- for (VisitingDetector v : mAllDetectors) {
- v.setContext(context);
- v.getDetector().beforeCheckFile(context);
- }
-
- for (VisitingDetector v : mFullTreeDetectors) {
- AstVisitor visitor = v.getVisitor();
- if (visitor != null) {
- compilationUnit.accept(visitor);
- }
- }
-
- if (mMethodDetectors.size() > 0 || mResourceFieldDetectors.size() > 0) {
- AstVisitor visitor = new DelegatingJavaVisitor(context);
- compilationUnit.accept(visitor);
- } else if (mNodeTypeDetectors.size() > 0) {
- AstVisitor visitor = new DispatchVisitor();
- compilationUnit.accept(visitor);
- }
-
- for (VisitingDetector v : mAllDetectors) {
- v.getDetector().afterCheckFile(context);
- }
- } finally {
- if (compilationUnit != null) {
- mParser.dispose(context, compilationUnit);
- }
- }
- }
-
- private static class VisitingDetector {
- private AstVisitor mVisitor; // construct lazily, and clear out on context switch!
- private JavaContext mContext;
- public final Detector mDetector;
- public final JavaScanner mJavaScanner;
-
- public VisitingDetector(@NonNull Detector detector, @NonNull JavaScanner javaScanner) {
- mDetector = detector;
- mJavaScanner = javaScanner;
- }
-
- @NonNull
- public Detector getDetector() {
- return mDetector;
- }
-
- @NonNull
- public JavaScanner getJavaScanner() {
- return mJavaScanner;
- }
-
- public void setContext(@NonNull JavaContext context) {
- mContext = context;
-
- // The visitors are one-per-context, so clear them out here and construct
- // lazily only if needed
- mVisitor = null;
- }
-
- @NonNull
- AstVisitor getVisitor() {
- if (mVisitor == null) {
- mVisitor = mDetector.createJavaVisitor(mContext);
- if (mVisitor == null) {
- mVisitor = new ForwardingAstVisitor() {
- };
- }
- }
- return mVisitor;
- }
- }
-
- /**
- * Generic dispatcher which visits all nodes (once) and dispatches to
- * specific visitors for each node. Each visitor typically only wants to
- * look at a small part of a tree, such as a method call or a class
- * declaration, so this means we avoid visiting all "uninteresting" nodes in
- * the tree repeatedly.
- */
- private class DispatchVisitor extends AstVisitor {
- @Override
- public void endVisit(Node node) {
- }
-
- @Override
- public boolean visitAlternateConstructorInvocation(AlternateConstructorInvocation node) {
- List<VisitingDetector> list =
- mNodeTypeDetectors.get(AlternateConstructorInvocation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAlternateConstructorInvocation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotation(Annotation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Annotation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotationDeclaration(AnnotationDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(AnnotationDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotationDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotationElement(AnnotationElement node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(AnnotationElement.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotationElement(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotationMethodDeclaration(AnnotationMethodDeclaration node) {
- List<VisitingDetector> list =
- mNodeTypeDetectors.get(AnnotationMethodDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotationMethodDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAnnotationValueArray(AnnotationValueArray node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(AnnotationValueArray.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAnnotationValueArray(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitArrayAccess(ArrayAccess node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayAccess.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitArrayAccess(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitArrayCreation(ArrayCreation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayCreation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitArrayCreation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitArrayDimension(ArrayDimension node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayDimension.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitArrayDimension(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitArrayInitializer(ArrayInitializer node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ArrayInitializer.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitArrayInitializer(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitAssert(Assert node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Assert.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitAssert(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitBinaryExpression(BinaryExpression node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(BinaryExpression.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitBinaryExpression(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitBlock(Block node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Block.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitBlock(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitBooleanLiteral(BooleanLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(BooleanLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitBooleanLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitBreak(Break node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Break.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitBreak(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCase(Case node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Case.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCase(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCast(Cast node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Cast.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCast(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCatch(Catch node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Catch.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCatch(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCharLiteral(CharLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(CharLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCharLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitClassDeclaration(ClassDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ClassDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitClassDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitClassLiteral(ClassLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ClassLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitClassLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitComment(Comment node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Comment.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitComment(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitCompilationUnit(CompilationUnit node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(CompilationUnit.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitCompilationUnit(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitConstructorDeclaration(ConstructorDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ConstructorDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitConstructorDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitConstructorInvocation(ConstructorInvocation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ConstructorInvocation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitConstructorInvocation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitContinue(Continue node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Continue.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitContinue(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitDefault(Default node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Default.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitDefault(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitDoWhile(DoWhile node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(DoWhile.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitDoWhile(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEmptyDeclaration(EmptyDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EmptyDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEmptyDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEmptyStatement(EmptyStatement node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EmptyStatement.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEmptyStatement(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEnumConstant(EnumConstant node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EnumConstant.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEnumConstant(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEnumDeclaration(EnumDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EnumDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEnumDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitEnumTypeBody(EnumTypeBody node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(EnumTypeBody.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitEnumTypeBody(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitExpressionStatement(ExpressionStatement node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ExpressionStatement.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitExpressionStatement(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitFloatingPointLiteral(FloatingPointLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(FloatingPointLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitFloatingPointLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitFor(For node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(For.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitFor(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitForEach(ForEach node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ForEach.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitForEach(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitIdentifier(Identifier node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Identifier.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitIdentifier(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitIf(If node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(If.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitIf(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitImportDeclaration(ImportDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(ImportDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitImportDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitInlineIfExpression(InlineIfExpression node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(InlineIfExpression.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitInlineIfExpression(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitInstanceInitializer(InstanceInitializer node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(InstanceInitializer.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitInstanceInitializer(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitInstanceOf(InstanceOf node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(InstanceOf.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitInstanceOf(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitIntegralLiteral(IntegralLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(IntegralLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitIntegralLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitInterfaceDeclaration(InterfaceDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(InterfaceDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitInterfaceDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitKeywordModifier(KeywordModifier node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(KeywordModifier.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitKeywordModifier(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitLabelledStatement(LabelledStatement node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(LabelledStatement.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitLabelledStatement(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitMethodDeclaration(MethodDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(MethodDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitMethodDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(MethodInvocation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitMethodInvocation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitModifiers(Modifiers node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Modifiers.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitModifiers(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitNormalTypeBody(NormalTypeBody node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(NormalTypeBody.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitNormalTypeBody(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitNullLiteral(NullLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(NullLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitNullLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitPackageDeclaration(PackageDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(PackageDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitPackageDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitParseArtefact(Node node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Node.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitParseArtefact(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitReturn(Return node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Return.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitReturn(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSelect(Select node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Select.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSelect(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitStaticInitializer(StaticInitializer node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(StaticInitializer.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitStaticInitializer(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitStringLiteral(StringLiteral node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(StringLiteral.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitStringLiteral(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSuper(Super node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Super.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSuper(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSuperConstructorInvocation(SuperConstructorInvocation node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(SuperConstructorInvocation.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSuperConstructorInvocation(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSwitch(Switch node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Switch.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSwitch(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitSynchronized(Synchronized node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Synchronized.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitSynchronized(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitThis(This node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(This.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitThis(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitThrow(Throw node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Throw.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitThrow(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitTry(Try node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(Try.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitTry(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitTypeReference(TypeReference node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(TypeReference.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitTypeReference(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitTypeReferencePart(TypeReferencePart node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(TypeReferencePart.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitTypeReferencePart(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitTypeVariable(TypeVariable node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(TypeVariable.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitTypeVariable(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitUnaryExpression(UnaryExpression node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(UnaryExpression.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitUnaryExpression(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitVariableDeclaration(VariableDeclaration node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(VariableDeclaration.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitVariableDeclaration(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitVariableDefinition(VariableDefinition node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(VariableDefinition.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitVariableDefinition(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitVariableDefinitionEntry(VariableDefinitionEntry node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(VariableDefinitionEntry.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitVariableDefinitionEntry(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitVariableReference(VariableReference node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(VariableReference.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitVariableReference(node);
- }
- }
- return false;
- }
-
- @Override
- public boolean visitWhile(While node) {
- List<VisitingDetector> list = mNodeTypeDetectors.get(While.class);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getVisitor().visitWhile(node);
- }
- }
- return false;
- }
- }
-
- /** Performs common AST searches for method calls and R-type-field references.
- * Note that this is a specialized form of the {@link DispatchVisitor}. */
- private class DelegatingJavaVisitor extends DispatchVisitor {
- private final JavaContext mContext;
- private final boolean mVisitResources;
- private final boolean mVisitMethods;
-
- public DelegatingJavaVisitor(JavaContext context) {
- mContext = context;
-
- mVisitMethods = mMethodDetectors.size() > 0;
- mVisitResources = mResourceFieldDetectors.size() > 0;
- }
-
- @Override
- public boolean visitSelect(Select node) {
- if (mVisitResources) {
- // R.type.name
- if (node.astOperand() instanceof Select) {
- Select select = (Select) node.astOperand();
- if (select.astOperand() instanceof VariableReference) {
- VariableReference reference = (VariableReference) select.astOperand();
- if (reference.astIdentifier().astValue().equals(R_CLASS)) {
- String type = select.astIdentifier().astValue();
- String name = node.astIdentifier().astValue();
-
- // R -could- be referenced locally and really have been
- // imported as "import android.R;" in the import statements,
- // but this is not recommended (and in fact there's a specific
- // lint rule warning against it)
- boolean isFramework = false;
-
- for (VisitingDetector v : mResourceFieldDetectors) {
- JavaScanner detector = v.getJavaScanner();
- detector.visitResourceReference(mContext, v.getVisitor(),
- node, type, name, isFramework);
- }
-
- return super.visitSelect(node);
- }
- }
- }
-
- // Arbitrary packages -- android.R.type.name, foo.bar.R.type.name
- if (node.astIdentifier().astValue().equals(R_CLASS)) {
- Node parent = node.getParent();
- if (parent instanceof Select) {
- Node grandParent = parent.getParent();
- if (grandParent instanceof Select) {
- Select select = (Select) grandParent;
- String name = select.astIdentifier().astValue();
- Expression typeOperand = select.astOperand();
- if (typeOperand instanceof Select) {
- Select typeSelect = (Select) typeOperand;
- String type = typeSelect.astIdentifier().astValue();
- boolean isFramework =
- node.astIdentifier().astValue().equals(ANDROID_PKG);
- for (VisitingDetector v : mResourceFieldDetectors) {
- JavaScanner detector = v.getJavaScanner();
- detector.visitResourceReference(mContext, v.getVisitor(),
- node, type, name, isFramework);
- }
- }
- }
- }
- }
- }
-
- return super.visitSelect(node);
- }
-
- @Override
- public boolean visitMethodInvocation(MethodInvocation node) {
- if (mVisitMethods) {
- String methodName = node.astName().getDescription();
- List<VisitingDetector> list = mMethodDetectors.get(methodName);
- if (list != null) {
- for (VisitingDetector v : list) {
- v.getJavaScanner().visitMethod(mContext, v.getVisitor(), node);
- }
- }
- }
-
- return super.visitMethodInvocation(node);
- }
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java
deleted file mode 100644
index c15b284..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java
+++ /dev/null
@@ -1,602 +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.client.api;
-
-import static com.android.SdkConstants.CLASS_FOLDER;
-import static com.android.SdkConstants.DOT_JAR;
-import static com.android.SdkConstants.GEN_FOLDER;
-import static com.android.SdkConstants.LIBS_FOLDER;
-import static com.android.SdkConstants.SRC_FOLDER;
-
-import com.android.SdkConstants;
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.sdklib.IAndroidTarget;
-import com.android.sdklib.SdkManager;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.utils.StdLogger;
-import com.android.utils.StdLogger.Level;
-import com.google.common.annotations.Beta;
-import com.google.common.collect.Maps;
-import com.google.common.io.Files;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringReader;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
-/**
- * Information about the tool embedding the lint analyzer. IDEs and other tools
- * implementing lint support will extend this to integrate logging, displaying errors,
- * etc.
- * <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 abstract class LintClient {
- private static final String PROP_BIN_DIR = "com.android.tools.lint.bindir"; //$NON-NLS-1$
-
- /**
- * Returns a configuration for use by the given project. The configuration
- * provides information about which issues are enabled, any customizations
- * to the severity of an issue, etc.
- * <p>
- * By default this method returns a {@link DefaultConfiguration}.
- *
- * @param project the project to obtain a configuration for
- * @return a configuration, never null.
- */
- public Configuration getConfiguration(@NonNull Project project) {
- return DefaultConfiguration.create(this, project, null);
- }
-
- /**
- * Report the given issue. This method will only be called if the configuration
- * provided by {@link #getConfiguration(Project)} has reported the corresponding
- * issue as enabled and has not filtered out the issue with its
- * {@link Configuration#ignore(Context, Issue, Location, String, Object)} method.
- * <p>
- *
- * @param context the context used by the detector when the issue was found
- * @param issue the issue that was found
- * @param severity the severity of the issue
- * @param location the location of the issue
- * @param message the associated user message
- * @param data optional extra data for a discovered issue, or null. The
- * content depends on the specific issue. Detectors can pass
- * extra info here which automatic fix tools etc can use to
- * extract relevant information instead of relying on parsing the
- * error message text. See each detector for details on which
- * data if any is supplied for a given issue.
- */
- public abstract void report(
- @NonNull Context context,
- @NonNull Issue issue,
- @NonNull Severity severity,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data);
-
- /**
- * Send an exception or error message (with warning severity) to the log
- *
- * @param exception the exception, possibly null
- * @param format the error message using {@link String#format} syntax, possibly null
- * (though in that case the exception should not be null)
- * @param args any arguments for the format string
- */
- public void log(
- @Nullable Throwable exception,
- @Nullable String format,
- @Nullable Object... args) {
- log(Severity.WARNING, exception, format, args);
- }
-
- /**
- * Send an exception or error message to the log
- *
- * @param severity the severity of the warning
- * @param exception the exception, possibly null
- * @param format the error message using {@link String#format} syntax, possibly null
- * (though in that case the exception should not be null)
- * @param args any arguments for the format string
- */
- public abstract void log(
- @NonNull Severity severity,
- @Nullable Throwable exception,
- @Nullable String format,
- @Nullable Object... args);
-
- /**
- * Returns a {@link IDomParser} to use to parse XML
- *
- * @return a new {@link IDomParser}, or null if this client does not support
- * XML analysis
- */
- @Nullable
- public abstract IDomParser getDomParser();
-
- /**
- * Returns a {@link IJavaParser} to use to parse Java
- *
- * @return a new {@link IJavaParser}, or null if this client does not
- * support Java analysis
- */
- @Nullable
- public abstract IJavaParser getJavaParser();
-
- /**
- * Returns an optimal detector, if applicable. By default, just returns the
- * original detector, but tools can replace detectors using this hook with a version
- * that takes advantage of native capabilities of the tool.
- *
- * @param detectorClass the class of the detector to be replaced
- * @return the new detector class, or just the original detector (not null)
- */
- @NonNull
- public Class<? extends Detector> replaceDetector(
- @NonNull Class<? extends Detector> detectorClass) {
- return detectorClass;
- }
-
- /**
- * Reads the given text file and returns the content as a string
- *
- * @param file the file to read
- * @return the string to return, never null (will be empty if there is an
- * I/O error)
- */
- @NonNull
- public abstract String readFile(@NonNull File file);
-
- /**
- * Reads the given binary file and returns the content as a byte array.
- * By default this method will read the bytes from the file directly,
- * but this can be customized by a client if for example I/O could be
- * held in memory and not flushed to disk yet.
- *
- * @param file the file to read
- * @return the bytes in the file, never null
- * @throws IOException if the file does not exist, or if the file cannot be
- * read for some reason
- */
- @NonNull
- public byte[] readBytes(@NonNull File file) throws IOException {
- return Files.toByteArray(file);
- }
-
- /**
- * Returns the list of source folders for Java source files
- *
- * @param project the project to look up Java source file locations for
- * @return a list of source folders to search for .java files
- */
- @NonNull
- public List<File> getJavaSourceFolders(@NonNull Project project) {
- return getClassPath(project).getSourceFolders();
- }
-
- /**
- * Returns the list of output folders for class files
- *
- * @param project the project to look up class file locations for
- * @return a list of output folders to search for .class files
- */
- @NonNull
- public List<File> getJavaClassFolders(@NonNull Project project) {
- return getClassPath(project).getClassFolders();
-
- }
-
- /**
- * Returns the list of Java libraries
- *
- * @param project the project to look up jar dependencies for
- * @return a list of jar dependencies containing .class files
- */
- @NonNull
- public List<File> getJavaLibraries(@NonNull Project project) {
- return getClassPath(project).getLibraries();
- }
-
- /**
- * Returns the {@link SdkInfo} to use for the given project.
- *
- * @param project the project to look up an {@link SdkInfo} for
- * @return an {@link SdkInfo} for the project
- */
- @NonNull
- public SdkInfo getSdkInfo(@NonNull Project project) {
- // By default no per-platform SDK info
- return new DefaultSdkInfo();
- }
-
- /**
- * Returns a suitable location for storing cache files. Note that the
- * directory may not exist.
- *
- * @param create if true, attempt to create the cache dir if it does not
- * exist
- * @return a suitable location for storing cache files, which may be null if
- * the create flag was false, or if for some reason the directory
- * could not be created
- */
- @Nullable
- public File getCacheDir(boolean create) {
- String home = System.getProperty("user.home");
- String relative = ".android" + File.separator + "cache"; //$NON-NLS-1$ //$NON-NLS-2$
- File dir = new File(home, relative);
- if (create && !dir.exists()) {
- if (!dir.mkdirs()) {
- return null;
- }
- }
- return dir;
- }
-
- /**
- * Returns the File corresponding to the system property or the environment variable
- * for {@link #PROP_BIN_DIR}.
- * This property is typically set by the SDK/tools/lint[.bat] wrapper.
- * It denotes the path of the wrapper on disk.
- *
- * @return A new File corresponding to {@link LintClient#PROP_BIN_DIR} or null.
- */
- @Nullable
- private File getLintBinDir() {
- // First check the Java properties (e.g. set using "java -jar ... -Dname=value")
- String path = System.getProperty(PROP_BIN_DIR);
- if (path == null || path.length() == 0) {
- // If not found, check environment variables.
- path = System.getenv(PROP_BIN_DIR);
- }
- if (path != null && path.length() > 0) {
- return new File(path);
- }
- return null;
- }
-
- /**
- * Returns the File pointing to the user's SDK install area. This is generally
- * the root directory containing the lint tool (but also platforms/ etc).
- *
- * @return a file pointing to the user's install area
- */
- @Nullable
- public File getSdkHome() {
- File binDir = getLintBinDir();
- if (binDir != null) {
- assert binDir.getName().equals("tools");
-
- File root = binDir.getParentFile();
- if (root != null && root.isDirectory()) {
- return root;
- }
- }
-
- String home = System.getenv("ANDROID_HOME"); //$NON-NLS-1$
- if (home != null) {
- return new File(home);
- }
-
- return null;
- }
-
- /**
- * Locates an SDK resource (relative to the SDK root directory).
- * <p>
- * TODO: Consider switching to a {@link URL} return type instead.
- *
- * @param relativePath A relative path (using {@link File#separator} to
- * separate path components) to the given resource
- * @return a {@link File} pointing to the resource, or null if it does not
- * exist
- */
- @Nullable
- public File findResource(@NonNull String relativePath) {
- File dir = getLintBinDir();
- if (dir == null) {
- throw new IllegalArgumentException("Lint must be invoked with the System property "
- + PROP_BIN_DIR + " pointing to the ANDROID_SDK tools directory");
- }
-
- File top = dir.getParentFile();
- File file = new File(top, relativePath);
- if (file.exists()) {
- return file;
- } else {
- return null;
- }
- }
-
- private Map<Project, ClassPathInfo> mProjectInfo;
-
- /**
- * Information about class paths (sources, class files and libraries)
- * usually associated with a project.
- */
- protected static class ClassPathInfo {
- private final List<File> mClassFolders;
- private final List<File> mSourceFolders;
- private final List<File> mLibraries;
-
- public ClassPathInfo(
- @NonNull List<File> sourceFolders,
- @NonNull List<File> classFolders,
- @NonNull List<File> libraries) {
- mSourceFolders = sourceFolders;
- mClassFolders = classFolders;
- mLibraries = libraries;
- }
-
- @NonNull
- public List<File> getSourceFolders() {
- return mSourceFolders;
- }
-
- @NonNull
- public List<File> getClassFolders() {
- return mClassFolders;
- }
-
- @NonNull
- public List<File> getLibraries() {
- return mLibraries;
- }
- }
-
- /**
- * Considers the given project as an Eclipse project and returns class path
- * information for the project - the source folder(s), the output folder and
- * any libraries.
- * <p>
- * Callers will not cache calls to this method, so if it's expensive to compute
- * the classpath info, this method should perform its own caching.
- *
- * @param project the project to look up class path info for
- * @return a class path info object, never null
- */
- @NonNull
- protected ClassPathInfo getClassPath(@NonNull Project project) {
- ClassPathInfo info;
- if (mProjectInfo == null) {
- mProjectInfo = Maps.newHashMap();
- info = null;
- } else {
- info = mProjectInfo.get(project);
- }
-
- if (info == null) {
- List<File> sources = new ArrayList<File>(2);
- List<File> classes = new ArrayList<File>(1);
- List<File> libraries = new ArrayList<File>();
-
- File projectDir = project.getDir();
- File classpathFile = new File(projectDir, ".classpath"); //$NON-NLS-1$
- if (classpathFile.exists()) {
- String classpathXml = readFile(classpathFile);
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- InputSource is = new InputSource(new StringReader(classpathXml));
- factory.setNamespaceAware(false);
- factory.setValidating(false);
- try {
- DocumentBuilder builder = factory.newDocumentBuilder();
- Document document = builder.parse(is);
- NodeList tags = document.getElementsByTagName("classpathentry"); //$NON-NLS-1$
- for (int i = 0, n = tags.getLength(); i < n; i++) {
- Element element = (Element) tags.item(i);
- String kind = element.getAttribute("kind"); //$NON-NLS-1$
- List<File> addTo = null;
- if (kind.equals("src")) { //$NON-NLS-1$
- addTo = sources;
- } else if (kind.equals("output")) { //$NON-NLS-1$
- addTo = classes;
- } else if (kind.equals("lib")) { //$NON-NLS-1$
- addTo = libraries;
- }
- if (addTo != null) {
- String path = element.getAttribute("path"); //$NON-NLS-1$
- File folder = new File(projectDir, path);
- if (folder.exists()) {
- addTo.add(folder);
- }
- }
- }
- } catch (Exception e) {
- log(null, null);
- }
- }
-
- // Add in libraries that aren't specified in the .classpath file
- File libs = new File(project.getDir(), LIBS_FOLDER);
- if (libs.isDirectory()) {
- File[] jars = libs.listFiles();
- if (jars != null) {
- for (File jar : jars) {
- if (LintUtils.endsWith(jar.getPath(), DOT_JAR)
- && !libraries.contains(jar)) {
- libraries.add(jar);
- }
- }
- }
- }
-
- if (classes.size() == 0) {
- File folder = new File(projectDir, CLASS_FOLDER);
- if (folder.exists()) {
- classes.add(folder);
- } else {
- // Maven checks
- folder = new File(projectDir,
- "target" + File.separator + "classes"); //$NON-NLS-1$ //$NON-NLS-2$
- if (folder.exists()) {
- classes.add(folder);
-
- // If it's maven, also correct the source path, "src" works but
- // it's in a more specific subfolder
- if (sources.size() == 0) {
- File src = new File(projectDir,
- "src" + File.separator //$NON-NLS-1$
- + "main" + File.separator //$NON-NLS-1$
- + "java"); //$NON-NLS-1$
- if (src.exists()) {
- sources.add(src);
- } else {
- src = new File(projectDir, SRC_FOLDER);
- if (src.exists()) {
- sources.add(src);
- }
- }
-
- File gen = new File(projectDir,
- "target" + File.separator //$NON-NLS-1$
- + "generated-sources" + File.separator //$NON-NLS-1$
- + "r"); //$NON-NLS-1$
- if (gen.exists()) {
- sources.add(gen);
- }
- }
- }
- }
- }
-
- // Fallback, in case there is no Eclipse project metadata here
- if (sources.size() == 0) {
- File src = new File(projectDir, SRC_FOLDER);
- if (src.exists()) {
- sources.add(src);
- }
- File gen = new File(projectDir, GEN_FOLDER);
- if (gen.exists()) {
- sources.add(gen);
- }
- }
-
- info = new ClassPathInfo(sources, classes, libraries);
- mProjectInfo.put(project, info);
- }
-
- return info;
- }
-
- /**
- * A map from directory to existing projects, or null. Used to ensure that
- * projects are unique for a directory (in case we process a library project
- * before its including project for example)
- */
- private Map<File, Project> mDirToProject;
-
- /**
- * Returns a project for the given directory. This should return the same
- * project for the same directory if called repeatedly.
- *
- * @param dir the directory containing the project
- * @param referenceDir See {@link Project#getReferenceDir()}.
- * @return a project, never null
- */
- @NonNull
- public Project getProject(@NonNull File dir, @NonNull File referenceDir) {
- if (mDirToProject == null) {
- mDirToProject = new HashMap<File, Project>();
- }
-
- File canonicalDir = dir;
- try {
- // Attempt to use the canonical handle for the file, in case there
- // are symlinks etc present (since when handling library projects,
- // we also call getCanonicalFile to compute the result of appending
- // relative paths, which can then resolve symlinks and end up with
- // a different prefix)
- canonicalDir = dir.getCanonicalFile();
- } catch (IOException ioe) {
- // pass
- }
-
- Project project = mDirToProject.get(canonicalDir);
- if (project != null) {
- return project;
- }
-
-
- project = Project.create(this, dir, referenceDir);
- mDirToProject.put(canonicalDir, project);
- return project;
- }
-
- private IAndroidTarget[] mTargets;
-
- /**
- * Returns all the {@link IAndroidTarget} versions installed in the user's SDK install
- * area.
- *
- * @return all the installed targets
- */
- @NonNull
- public IAndroidTarget[] getTargets() {
- if (mTargets == null) {
- File sdkHome = getSdkHome();
- if (sdkHome != null) {
- StdLogger log = new StdLogger(Level.WARNING);
- SdkManager manager = SdkManager.createManager(sdkHome.getPath(), log);
- mTargets = manager.getTargets();
- } else {
- mTargets = new IAndroidTarget[0];
- }
- }
-
- return mTargets;
- }
-
- /**
- * Returns the highest known API level.
- *
- * @return the highest known API level
- */
- public int getHighestKnownApiLevel() {
- int max = SdkConstants.HIGHEST_KNOWN_API;
-
- for (IAndroidTarget target : getTargets()) {
- if (target.isPlatform()) {
- int api = target.getVersion().getApiLevel();
- if (api > max && !target.getVersion().isPreview()) {
- max = api;
- }
- }
- }
-
- return max;
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java
deleted file mode 100644
index a833dae..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java
+++ /dev/null
@@ -1,2061 +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.client.api;
-
-import static com.android.SdkConstants.ANDROID_MANIFEST_XML;
-import static com.android.SdkConstants.ATTR_IGNORE;
-import static com.android.SdkConstants.DOT_CLASS;
-import static com.android.SdkConstants.DOT_JAR;
-import static com.android.SdkConstants.DOT_JAVA;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.FN_PROJECT_PROGUARD_FILE;
-import static com.android.SdkConstants.OLD_PROGUARD_FILE;
-import static com.android.SdkConstants.RES_FOLDER;
-import static com.android.SdkConstants.SUPPRESS_ALL;
-import static com.android.SdkConstants.SUPPRESS_LINT;
-import static com.android.SdkConstants.TOOLS_URI;
-import static org.objectweb.asm.Opcodes.ASM4;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.annotations.VisibleForTesting;
-import com.android.resources.ResourceFolderType;
-import com.android.sdklib.IAndroidTarget;
-import com.android.tools.lint.client.api.LintListener.EventType;
-import com.android.tools.lint.detector.api.Category;
-import com.android.tools.lint.detector.api.ClassContext;
-import com.android.tools.lint.detector.api.Context;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Issue;
-import com.android.tools.lint.detector.api.JavaContext;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.Location;
-import com.android.tools.lint.detector.api.Project;
-import com.android.tools.lint.detector.api.ResourceXmlDetector;
-import com.android.tools.lint.detector.api.Scope;
-import com.android.tools.lint.detector.api.Severity;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.annotations.Beta;
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Splitter;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.Multimap;
-import com.google.common.io.ByteStreams;
-import com.google.common.io.Closeables;
-
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.tree.AnnotationNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import lombok.ast.Annotation;
-import lombok.ast.AnnotationElement;
-import lombok.ast.AnnotationValue;
-import lombok.ast.ArrayInitializer;
-import lombok.ast.ClassDeclaration;
-import lombok.ast.ConstructorDeclaration;
-import lombok.ast.Expression;
-import lombok.ast.MethodDeclaration;
-import lombok.ast.Modifiers;
-import lombok.ast.Node;
-import lombok.ast.StrictListAccessor;
-import lombok.ast.StringLiteral;
-import lombok.ast.TypeReference;
-import lombok.ast.VariableDefinition;
-
-/**
- * Analyzes Android projects and files
- * <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 LintDriver {
- /**
- * Max number of passes to run through the lint runner if requested by
- * {@link #requestRepeat}
- */
- private static final int MAX_PHASES = 3;
- private static final String SUPPRESS_LINT_VMSIG = '/' + SUPPRESS_LINT + ';';
-
- private final LintClient mClient;
- private volatile boolean mCanceled;
- private IssueRegistry mRegistry;
- private EnumSet<Scope> mScope;
- private List<? extends Detector> mApplicableDetectors;
- private Map<Scope, List<Detector>> mScopeDetectors;
- private List<LintListener> mListeners;
- private int mPhase;
- private List<Detector> mRepeatingDetectors;
- private EnumSet<Scope> mRepeatScope;
- private Project[] mCurrentProjects;
- private Project mCurrentProject;
- private boolean mAbbreviating = true;
- private boolean mParserErrors;
-
- /**
- * Creates a new {@link LintDriver}
- *
- * @param registry The registry containing issues to be checked
- * @param client the tool wrapping the analyzer, such as an IDE or a CLI
- */
- public LintDriver(@NonNull IssueRegistry registry, @NonNull LintClient client) {
- mRegistry = registry;
- mClient = new LintClientWrapper(client);
- }
-
- /** Cancels the current lint run as soon as possible */
- public void cancel() {
- mCanceled = true;
- }
-
- /**
- * Returns the scope for the lint job
- *
- * @return the scope, never null
- */
- @NonNull
- public EnumSet<Scope> getScope() {
- return mScope;
- }
-
- /**
- * Returns the lint client requesting the lint check
- *
- * @return the client, never null
- */
- @NonNull
- public LintClient getClient() {
- return mClient;
- }
-
- /**
- * Returns the current phase number. The first pass is numbered 1. Only one pass
- * will be performed, unless a {@link Detector} calls {@link #requestRepeat}.
- *
- * @return the current phase, usually 1
- */
- public int getPhase() {
- return mPhase;
- }
-
- /**
- * Returns the current {@link IssueRegistry}.
- *
- * @return the current {@link IssueRegistry}
- */
- @NonNull
- public IssueRegistry getRegistry() {
- return mRegistry;
- }
-
- /**
- * Returns the project containing a given file, or null if not found. This searches
- * only among the currently checked project and its library projects, not among all
- * possible projects being scanned sequentially.
- *
- * @param file the file to be checked
- * @return the corresponding project, or null if not found
- */
- @Nullable
- public Project findProjectFor(@NonNull File file) {
- if (mCurrentProjects != null) {
- if (mCurrentProjects.length == 1) {
- return mCurrentProjects[0];
- }
- String path = file.getPath();
- for (Project project : mCurrentProjects) {
- if (path.startsWith(project.getDir().getPath())) {
- return project;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Sets whether lint should abbreviate output when appropriate.
- *
- * @param abbreviating true to abbreviate output, false to include everything
- */
- public void setAbbreviating(boolean abbreviating) {
- mAbbreviating = abbreviating;
- }
-
- /**
- * Returns whether lint should abbreviate output when appropriate.
- *
- * @return true if lint should abbreviate output, false when including everything
- */
- public boolean isAbbreviating() {
- return mAbbreviating;
- }
-
- /**
- * Returns whether lint has encountered any files with fatal parser errors
- * (e.g. broken source code, or even broken parsers)
- * <p>
- * This is useful for checks that need to make sure they've seen all data in
- * order to be conclusive (such as an unused resource check).
- *
- * @return true if any files were not properly processed because they
- * contained parser errors
- */
- public boolean hasParserErrors() {
- return mParserErrors;
- }
-
- /**
- * Sets whether lint has encountered files with fatal parser errors.
- *
- * @see #hasParserErrors()
- * @param hasErrors whether parser errors have been encountered
- */
- public void setHasParserErrors(boolean hasErrors) {
- mParserErrors = hasErrors;
- }
-
- /**
- * Returns the projects being analyzed
- *
- * @return the projects being analyzed
- */
- @NonNull
- public List<Project> getProjects() {
- if (mCurrentProjects != null) {
- return Arrays.asList(mCurrentProjects);
- }
- return Collections.emptyList();
- }
-
- /**
- * Analyze the given file (which can point to an Android project). Issues found
- * are reported to the associated {@link LintClient}.
- *
- * @param files the files and directories to be analyzed
- * @param scope the scope of the analysis; detectors with a wider scope will
- * not be run. If null, the scope will be inferred from the files.
- */
- public void analyze(@NonNull List<File> files, @Nullable EnumSet<Scope> scope) {
- mCanceled = false;
- mScope = scope;
-
- Collection<Project> projects = computeProjects(files);
- if (projects.size() == 0) {
- mClient.log(null, "No projects found for %1$s", files.toString());
- return;
- }
- if (mCanceled) {
- return;
- }
-
- if (mScope == null) {
- // Infer the scope
- mScope = EnumSet.noneOf(Scope.class);
- for (Project project : projects) {
- List<File> subset = project.getSubset();
- if (subset != null) {
- for (File file : subset) {
- String name = file.getName();
- if (name.equals(ANDROID_MANIFEST_XML)) {
- mScope.add(Scope.MANIFEST);
- } else if (name.endsWith(DOT_XML)) {
- mScope.add(Scope.RESOURCE_FILE);
- } else if (name.equals(RES_FOLDER)
- || file.getParent().equals(RES_FOLDER)) {
- mScope.add(Scope.ALL_RESOURCE_FILES);
- mScope.add(Scope.RESOURCE_FILE);
- } else if (name.endsWith(DOT_JAVA)) {
- mScope.add(Scope.JAVA_FILE);
- } else if (name.endsWith(DOT_CLASS)) {
- mScope.add(Scope.CLASS_FILE);
- } else if (name.equals(OLD_PROGUARD_FILE)
- || name.equals(FN_PROJECT_PROGUARD_FILE)) {
- mScope.add(Scope.PROGUARD_FILE);
- }
- }
- } else {
- // Specified a full project: just use the full project scope
- mScope = Scope.ALL;
- break;
- }
- }
- }
-
- fireEvent(EventType.STARTING, null);
-
- for (Project project : projects) {
- mPhase = 1;
-
- // The set of available detectors varies between projects
- computeDetectors(project);
-
- if (mApplicableDetectors.size() == 0) {
- // No detectors enabled in this project: skip it
- continue;
- }
-
- checkProject(project);
- if (mCanceled) {
- break;
- }
-
- runExtraPhases(project);
- }
-
- fireEvent(mCanceled ? EventType.CANCELED : EventType.COMPLETED, null);
- }
-
- private void runExtraPhases(Project project) {
- // Did any detectors request another phase?
- if (mRepeatingDetectors != null) {
- // Yes. Iterate up to MAX_PHASES times.
-
- // During the extra phases, we might be narrowing the scope, and setting it in the
- // scope field such that detectors asking about the available scope will get the
- // correct result. However, we need to restore it to the original scope when this
- // is done in case there are other projects that will be checked after this, since
- // the repeated phases is done *per project*, not after all projects have been
- // processed.
- EnumSet<Scope> oldScope = mScope;
-
- do {
- mPhase++;
- fireEvent(EventType.NEW_PHASE,
- new Context(this, project, null, project.getDir()));
-
- // Narrow the scope down to the set of scopes requested by
- // the rules.
- if (mRepeatScope == null) {
- mRepeatScope = Scope.ALL;
- }
- mScope = Scope.intersect(mScope, mRepeatScope);
- if (mScope.isEmpty()) {
- break;
- }
-
- // Compute the detectors to use for this pass.
- // Unlike the normal computeDetectors(project) call,
- // this is going to use the existing instances, and include
- // those that apply for the configuration.
- computeRepeatingDetectors(mRepeatingDetectors, project);
-
- if (mApplicableDetectors.size() == 0) {
- // No detectors enabled in this project: skip it
- continue;
- }
-
- checkProject(project);
- if (mCanceled) {
- break;
- }
- } while (mPhase < MAX_PHASES && mRepeatingDetectors != null);
-
- mScope = oldScope;
- }
- }
-
- private void computeRepeatingDetectors(List<Detector> detectors, Project project) {
- // Ensure that the current visitor is recomputed
- mCurrentFolderType = null;
- mCurrentVisitor = null;
-
- // Create map from detector class to issue such that we can
- // compute applicable issues for each detector in the list of detectors
- // to be repeated
- List<Issue> issues = mRegistry.getIssues();
- Multimap<Class<? extends Detector>, Issue> issueMap =
- ArrayListMultimap.create(issues.size(), 3);
- for (Issue issue : issues) {
- issueMap.put(issue.getDetectorClass(), issue);
- }
-
- Map<Class<? extends Detector>, EnumSet<Scope>> detectorToScope =
- new HashMap<Class<? extends Detector>, EnumSet<Scope>>();
- Map<Scope, List<Detector>> scopeToDetectors =
- new HashMap<Scope, List<Detector>>();
-
- List<Detector> detectorList = new ArrayList<Detector>();
- // Compute the list of detectors (narrowed down from mRepeatingDetectors),
- // and simultaneously build up the detectorToScope map which tracks
- // the scopes each detector is affected by (this is used to populate
- // the mScopeDetectors map which is used during iteration).
- Configuration configuration = project.getConfiguration();
- for (Detector detector : detectors) {
- Class<? extends Detector> detectorClass = detector.getClass();
- Collection<Issue> detectorIssues = issueMap.get(detectorClass);
- if (issues != null) {
- boolean add = false;
- for (Issue issue : detectorIssues) {
- // The reason we have to check whether the detector is enabled
- // is that this is a per-project property, so when running lint in multiple
- // projects, a detector enabled only in a different project could have
- // requested another phase, and we end up in this project checking whether
- // the detector is enabled here.
- if (!configuration.isEnabled(issue)) {
- continue;
- }
-
- add = true; // Include detector if any of its issues are enabled
-
- EnumSet<Scope> s = detectorToScope.get(detectorClass);
- EnumSet<Scope> issueScope = issue.getScope();
- if (s == null) {
- detectorToScope.put(detectorClass, issueScope);
- } else if (!s.containsAll(issueScope)) {
- EnumSet<Scope> union = EnumSet.copyOf(s);
- union.addAll(issueScope);
- detectorToScope.put(detectorClass, union);
- }
- }
-
- if (add) {
- detectorList.add(detector);
- EnumSet<Scope> union = detectorToScope.get(detector.getClass());
- for (Scope s : union) {
- List<Detector> list = scopeToDetectors.get(s);
- if (list == null) {
- list = new ArrayList<Detector>();
- scopeToDetectors.put(s, list);
- }
- list.add(detector);
- }
- }
- }
- }
-
- mApplicableDetectors = detectorList;
- mScopeDetectors = scopeToDetectors;
- mRepeatingDetectors = null;
- mRepeatScope = null;
-
- validateScopeList();
- }
-
- private void computeDetectors(@NonNull Project project) {
- // Ensure that the current visitor is recomputed
- mCurrentFolderType = null;
- mCurrentVisitor = null;
-
- Configuration configuration = project.getConfiguration();
- mScopeDetectors = new HashMap<Scope, List<Detector>>();
- mApplicableDetectors = mRegistry.createDetectors(mClient, configuration,
- mScope, mScopeDetectors);
-
- validateScopeList();
- }
-
- /** Development diagnostics only, run with assertions on */
- @SuppressWarnings("all") // Turn off warnings for the intentional assertion side effect below
- private void validateScopeList() {
- boolean assertionsEnabled = false;
- assert assertionsEnabled = true; // Intentional side-effect
- if (assertionsEnabled) {
- List<Detector> resourceFileDetectors = mScopeDetectors.get(Scope.RESOURCE_FILE);
- if (resourceFileDetectors != null) {
- for (Detector detector : resourceFileDetectors) {
- assert detector instanceof ResourceXmlDetector : detector;
- }
- }
-
- List<Detector> manifestDetectors = mScopeDetectors.get(Scope.MANIFEST);
- if (manifestDetectors != null) {
- for (Detector detector : manifestDetectors) {
- assert detector instanceof Detector.XmlScanner : detector;
- }
- }
- List<Detector> javaCodeDetectors = mScopeDetectors.get(Scope.ALL_JAVA_FILES);
- if (javaCodeDetectors != null) {
- for (Detector detector : javaCodeDetectors) {
- assert detector instanceof Detector.JavaScanner : detector;
- }
- }
- List<Detector> javaFileDetectors = mScopeDetectors.get(Scope.JAVA_FILE);
- if (javaFileDetectors != null) {
- for (Detector detector : javaFileDetectors) {
- assert detector instanceof Detector.JavaScanner : detector;
- }
- }
-
- List<Detector> classDetectors = mScopeDetectors.get(Scope.CLASS_FILE);
- if (classDetectors != null) {
- for (Detector detector : classDetectors) {
- assert detector instanceof Detector.ClassScanner : detector;
- }
- }
- }
- }
-
- private void registerProjectFile(
- @NonNull Map<File, Project> fileToProject,
- @NonNull File file,
- @NonNull File projectDir,
- @NonNull File rootDir) {
- fileToProject.put(file, mClient.getProject(projectDir, rootDir));
- }
-
- private Collection<Project> computeProjects(@NonNull List<File> files) {
- // Compute list of projects
- Map<File, Project> fileToProject = new HashMap<File, Project>();
-
- File sharedRoot = null;
-
- // Ensure that we have absolute paths such that if you lint
- // "foo bar" in "baz" we can show baz/ as the root
- if (files.size() > 1) {
- List<File> absolute = new ArrayList<File>(files.size());
- for (File file : files) {
- absolute.add(file.getAbsoluteFile());
- }
- files = absolute;
-
- sharedRoot = LintUtils.getCommonParent(files);
- if (sharedRoot != null && sharedRoot.getParentFile() == null) { // "/" ?
- sharedRoot = null;
- }
- }
-
-
- for (File file : files) {
- if (file.isDirectory()) {
- File rootDir = sharedRoot;
- if (rootDir == null) {
- rootDir = file;
- if (files.size() > 1) {
- rootDir = file.getParentFile();
- if (rootDir == null) {
- rootDir = file;
- }
- }
- }
-
- // Figure out what to do with a directory. Note that the meaning of the
- // directory can be ambiguous:
- // If you pass a directory which is unknown, we don't know if we should
- // search upwards (in case you're pointing at a deep java package folder
- // within the project), or if you're pointing at some top level directory
- // containing lots of projects you want to scan. We attempt to do the
- // right thing, which is to see if you're pointing right at a project or
- // right within it (say at the src/ or res/) folder, and if not, you're
- // hopefully pointing at a project tree that you want to scan recursively.
- if (LintUtils.isProjectDir(file)) {
- registerProjectFile(fileToProject, file, file, rootDir);
- continue;
- } else {
- File parent = file.getParentFile();
- if (parent != null) {
- if (LintUtils.isProjectDir(parent)) {
- registerProjectFile(fileToProject, file, parent, parent);
- continue;
- } else {
- parent = parent.getParentFile();
- if (parent != null && LintUtils.isProjectDir(parent)) {
- registerProjectFile(fileToProject, file, parent, parent);
- continue;
- }
- }
- }
-
- // Search downwards for nested projects
- addProjects(file, fileToProject, rootDir);
- }
- } else {
- // Pointed at a file: Search upwards for the containing project
- File parent = file.getParentFile();
- while (parent != null) {
- if (LintUtils.isProjectDir(parent)) {
- registerProjectFile(fileToProject, file, parent, parent);
- break;
- }
- parent = parent.getParentFile();
- }
- }
-
- if (mCanceled) {
- return Collections.emptySet();
- }
- }
-
- for (Map.Entry<File, Project> entry : fileToProject.entrySet()) {
- File file = entry.getKey();
- Project project = entry.getValue();
- if (!file.equals(project.getDir())) {
- if (file.isDirectory()) {
- try {
- File dir = file.getCanonicalFile();
- if (dir.equals(project.getDir())) {
- continue;
- }
- } catch (IOException ioe) {
- // pass
- }
- }
-
- project.addFile(file);
- }
- }
-
- // Partition the projects up such that we only return projects that aren't
- // included by other projects (e.g. because they are library projects)
-
- Collection<Project> allProjects = fileToProject.values();
- Set<Project> roots = new HashSet<Project>(allProjects);
- for (Project project : allProjects) {
- roots.removeAll(project.getAllLibraries());
- }
-
- // Report issues for all projects that are explicitly referenced. We need to
- // do this here, since the project initialization will mark all library
- // projects as no-report projects by default.
- for (Project project : allProjects) {
- // Report issues for all projects explicitly listed or found via a directory
- // traversal -- including library projects.
- project.setReportIssues(true);
- }
-
- if (LintUtils.assertionsEnabled()) {
- // Make sure that all the project directories are unique. This ensures
- // that we didn't accidentally end up with different project instances
- // for a library project discovered as a directory as well as one
- // initialized from the library project dependency list
- IdentityHashMap<Project, Project> projects =
- new IdentityHashMap<Project, Project>();
- for (Project project : roots) {
- projects.put(project, project);
- for (Project library : project.getAllLibraries()) {
- projects.put(library, library);
- }
- }
- Set<File> dirs = new HashSet<File>();
- for (Project project : projects.keySet()) {
- assert !dirs.contains(project.getDir());
- dirs.add(project.getDir());
- }
- }
-
- return roots;
- }
-
- private void addProjects(
- @NonNull File dir,
- @NonNull Map<File, Project> fileToProject,
- @NonNull File rootDir) {
- if (mCanceled) {
- return;
- }
-
- if (LintUtils.isProjectDir(dir)) {
- registerProjectFile(fileToProject, dir, dir, rootDir);
- } else {
- File[] files = dir.listFiles();
- if (files != null) {
- for (File file : files) {
- if (file.isDirectory()) {
- addProjects(file, fileToProject, rootDir);
- }
- }
- }
- }
- }
-
- private void checkProject(@NonNull Project project) {
- File projectDir = project.getDir();
-
- Context projectContext = new Context(this, project, null, projectDir);
- fireEvent(EventType.SCANNING_PROJECT, projectContext);
-
- List<Project> allLibraries = project.getAllLibraries();
- Set<Project> allProjects = new HashSet<Project>(allLibraries.size() + 1);
- allProjects.add(project);
- allProjects.addAll(allLibraries);
- mCurrentProjects = allProjects.toArray(new Project[allProjects.size()]);
-
- mCurrentProject = project;
-
- for (Detector check : mApplicableDetectors) {
- check.beforeCheckProject(projectContext);
- if (mCanceled) {
- return;
- }
- }
-
- assert mCurrentProject == project;
- runFileDetectors(project, project);
-
- if (!Scope.checkSingleFile(mScope)) {
- List<Project> libraries = project.getDirectLibraries();
- for (Project library : libraries) {
- Context libraryContext = new Context(this, library, project, projectDir);
- fireEvent(EventType.SCANNING_LIBRARY_PROJECT, libraryContext);
- mCurrentProject = library;
-
- for (Detector check : mApplicableDetectors) {
- check.beforeCheckLibraryProject(libraryContext);
- if (mCanceled) {
- return;
- }
- }
- assert mCurrentProject == library;
-
- runFileDetectors(library, project);
- if (mCanceled) {
- return;
- }
-
- assert mCurrentProject == library;
-
- for (Detector check : mApplicableDetectors) {
- check.afterCheckLibraryProject(libraryContext);
- if (mCanceled) {
- return;
- }
- }
- }
- }
-
- mCurrentProject = project;
-
- for (Detector check : mApplicableDetectors) {
- check.afterCheckProject(projectContext);
- if (mCanceled) {
- return;
- }
- }
-
- if (mCanceled) {
- mClient.report(
- projectContext,
- // Must provide an issue since API guarantees that the issue parameter
- // is valid
- Issue.create("Lint", "", "", Category.PERFORMANCE, 0, Severity.INFORMATIONAL, //$NON-NLS-1$
- Detector.class, EnumSet.noneOf(Scope.class)),
- Severity.INFORMATIONAL,
- null /*range*/,
- "Lint canceled by user", null);
- }
-
- mCurrentProjects = null;
- }
-
- private void runFileDetectors(@NonNull Project project, @Nullable Project main) {
- // Look up manifest information (but not for library projects)
- File manifestFile = project.getManifestFile();
- if (manifestFile != null) {
- XmlContext context = new XmlContext(this, project, main, manifestFile, null);
- IDomParser parser = mClient.getDomParser();
- if (parser != null) {
- context.document = parser.parseXml(context);
- if (context.document != null) {
- project.readManifest(context.document);
-
- if ((!project.isLibrary() || (main != null && main.isMergingManifests()))
- && mScope.contains(Scope.MANIFEST)) {
- List<Detector> detectors = mScopeDetectors.get(Scope.MANIFEST);
- if (detectors != null) {
- XmlVisitor v = new XmlVisitor(parser, detectors);
- fireEvent(EventType.SCANNING_FILE, context);
- v.visitFile(context, manifestFile);
- }
- }
- }
- }
- }
-
- // Process both Scope.RESOURCE_FILE and Scope.ALL_RESOURCE_FILES detectors together
- // in a single pass through the resource directories.
- if (mScope.contains(Scope.ALL_RESOURCE_FILES) || mScope.contains(Scope.RESOURCE_FILE)) {
- List<Detector> checks = union(mScopeDetectors.get(Scope.RESOURCE_FILE),
- mScopeDetectors.get(Scope.ALL_RESOURCE_FILES));
- if (checks != null && checks.size() > 0) {
- List<ResourceXmlDetector> xmlDetectors =
- new ArrayList<ResourceXmlDetector>(checks.size());
- for (Detector detector : checks) {
- if (detector instanceof ResourceXmlDetector) {
- xmlDetectors.add((ResourceXmlDetector) detector);
- }
- }
- if (xmlDetectors.size() > 0) {
- List<File> files = project.getSubset();
- if (files != null) {
- checkIndividualResources(project, main, xmlDetectors, files);
- } else {
- File res = new File(project.getDir(), RES_FOLDER);
- if (res.exists() && xmlDetectors.size() > 0) {
- checkResFolder(project, main, res, xmlDetectors);
- }
- }
- }
- }
- }
-
- if (mCanceled) {
- return;
- }
-
- if (mScope.contains(Scope.JAVA_FILE) || mScope.contains(Scope.ALL_JAVA_FILES)) {
- List<Detector> checks = union(mScopeDetectors.get(Scope.JAVA_FILE),
- mScopeDetectors.get(Scope.ALL_JAVA_FILES));
- if (checks != null && checks.size() > 0) {
- List<File> files = project.getSubset();
- if (files != null) {
- checkIndividualJavaFiles(project, main, checks, files);
- } else {
- List<File> sourceFolders = project.getJavaSourceFolders();
- checkJava(project, main, sourceFolders, checks);
- }
- }
- }
-
- if (mCanceled) {
- return;
- }
-
- if (mScope.contains(Scope.CLASS_FILE) || mScope.contains(Scope.JAVA_LIBRARIES)) {
- checkClasses(project, main);
- }
-
- if (mCanceled) {
- return;
- }
-
- if (project == main && mScope.contains(Scope.PROGUARD_FILE)) {
- checkProGuard(project, main);
- }
- }
- private void checkProGuard(Project project, Project main) {
- List<Detector> detectors = mScopeDetectors.get(Scope.PROGUARD_FILE);
- if (detectors != null) {
- Project p = main != null ? main : project;
- List<File> files = new ArrayList<File>();
- String paths = p.getProguardPath();
- if (paths != null) {
- Splitter splitter = Splitter.on(CharMatcher.anyOf(":;")); //$NON-NLS-1$
- for (String path : splitter.split(paths)) {
- if (path.contains("${")) { //$NON-NLS-1$
- // Don't analyze the global/user proguard files
- continue;
- }
- File file = new File(path);
- if (!file.isAbsolute()) {
- file = new File(project.getDir(), path);
- }
- if (file.exists()) {
- files.add(file);
- }
- }
- }
- if (files.isEmpty()) {
- File file = new File(project.getDir(), OLD_PROGUARD_FILE);
- if (file.exists()) {
- files.add(file);
- }
- file = new File(project.getDir(), FN_PROJECT_PROGUARD_FILE);
- if (file.exists()) {
- files.add(file);
- }
- }
- for (File file : files) {
- Context context = new Context(this, project, main, file);
- fireEvent(EventType.SCANNING_FILE, context);
- for (Detector detector : detectors) {
- if (detector.appliesTo(context, file)) {
- detector.beforeCheckFile(context);
- detector.run(context);
- detector.afterCheckFile(context);
- }
- }
- }
- }
- }
-
- /**
- * Map from VM class name to corresponding super class VM name, if available.
- * This map is typically null except <b>during</b> class processing.
- */
- private Map<String, String> mSuperClassMap;
-
- /**
- * Returns the super class for the given class name,
- * which should be in VM format (e.g. java/lang/Integer, not java.lang.Integer).
- * If the super class is not known, returns null. This can happen if
- * the given class is not a known class according to the project or its
- * libraries, for example because it refers to one of the core libraries which
- * are not analyzed by lint.
- *
- * @param name the fully qualified class name
- * @return the corresponding super class name (in VM format), or null if not known
- */
- @Nullable
- public String getSuperClass(@NonNull String name) {
- if (mSuperClassMap == null) {
- throw new IllegalStateException("Only callable during ClassScanner#checkClass");
- }
- assert name.indexOf('.') == -1 : "Use VM signatures, e.g. java/lang/Integer";
- return mSuperClassMap.get(name);
- }
-
- /**
- * Returns true if the given class is a subclass of the given super class.
- *
- * @param classNode the class to check whether it is a subclass of the given
- * super class name
- * @param superClassName the fully qualified super class name (in VM format,
- * e.g. java/lang/Integer, not java.lang.Integer.
- * @return true if the given class is a subclass of the given super class
- */
- public boolean isSubclassOf(@NonNull ClassNode classNode, @NonNull String superClassName) {
- if (superClassName.equals(classNode.superName)) {
- return true;
- }
-
- String className = classNode.name;
- while (className != null) {
- if (className.equals(superClassName)) {
- return true;
- }
- className = getSuperClass(className);
- }
-
- return false;
- }
- @Nullable
- private static List<Detector> union(
- @Nullable List<Detector> list1,
- @Nullable List<Detector> list2) {
- if (list1 == null) {
- return list2;
- } else if (list2 == null) {
- return list1;
- } else {
- // Use set to pick out unique detectors, since it's possible for there to be overlap,
- // e.g. the DuplicateIdDetector registers both a cross-resource issue and a
- // single-file issue, so it shows up on both scope lists:
- Set<Detector> set = new HashSet<Detector>(list1.size() + list2.size());
- if (list1 != null) {
- set.addAll(list1);
- }
- if (list2 != null) {
- set.addAll(list2);
- }
-
- return new ArrayList<Detector>(set);
- }
- }
-
- /** Check the classes in this project (and if applicable, in any library projects */
- private void checkClasses(Project project, Project main) {
- List<File> files = project.getSubset();
- if (files != null) {
- checkIndividualClassFiles(project, main, files);
- return;
- }
-
- // We need to read in all the classes up front such that we can initialize
- // the parent chains (such that for example for a virtual dispatch, we can
- // also check the super classes).
-
- List<File> libraries = project.getJavaLibraries();
- List<ClassEntry> libraryEntries;
- if (libraries.size() > 0) {
- libraryEntries = new ArrayList<ClassEntry>(64);
- findClasses(libraryEntries, libraries);
- Collections.sort(libraryEntries);
- } else {
- libraryEntries = Collections.emptyList();
- }
-
- List<File> classFolders = project.getJavaClassFolders();
- List<ClassEntry> classEntries;
- if (classFolders.size() == 0) {
- String message = String.format("No .class files were found in project \"%1$s\", "
- + "so none of the classfile based checks could be run. "
- + "Does the project need to be built first?", project.getName());
- Location location = Location.create(project.getDir());
- mClient.report(new Context(this, project, main, project.getDir()),
- IssueRegistry.LINT_ERROR,
- project.getConfiguration().getSeverity(IssueRegistry.LINT_ERROR),
- location, message, null);
- classEntries = Collections.emptyList();
- } else {
- classEntries = new ArrayList<ClassEntry>(64);
- findClasses(classEntries, classFolders);
- Collections.sort(classEntries);
- }
-
- if (getPhase() == 1) {
- mSuperClassMap = getSuperMap(libraryEntries, classEntries);
- }
-
- // Actually run the detectors. Libraries should be called before the
- // main classes.
- runClassDetectors(Scope.JAVA_LIBRARIES, libraryEntries, project, main);
-
- if (mCanceled) {
- return;
- }
-
- runClassDetectors(Scope.CLASS_FILE, classEntries, project, main);
- }
-
- private void checkIndividualClassFiles(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull List<File> files) {
- List<ClassEntry> entries = new ArrayList<ClassEntry>(files.size());
-
- List<File> classFolders = project.getJavaClassFolders();
- if (!classFolders.isEmpty()) {
- for (File file : files) {
- String path = file.getPath();
- if (file.isFile() && path.endsWith(DOT_CLASS)) {
- try {
- byte[] bytes = mClient.readBytes(file);
- if (bytes != null) {
- for (File dir : classFolders) {
- if (path.startsWith(dir.getPath())) {
- entries.add(new ClassEntry(file, null /* jarFile*/, dir,
- bytes));
- break;
- }
- }
- }
- } catch (IOException e) {
- mClient.log(e, null);
- continue;
- }
-
- if (mCanceled) {
- return;
- }
- }
- }
-
- if (entries.size() > 0) {
- Collections.sort(entries);
- // No superclass info available on individual lint runs
- mSuperClassMap = Collections.emptyMap();
- runClassDetectors(Scope.CLASS_FILE, entries, project, main);
- }
- }
- }
-
- /**
- * Stack of {@link ClassNode} nodes for outer classes of the currently
- * processed class, including that class itself. Populated by
- * {@link #runClassDetectors(Scope, List, Project, Project)} and used by
- * {@link #getOuterClassNode(ClassNode)}
- */
- private Deque<ClassNode> mOuterClasses;
-
- private void runClassDetectors(Scope scope, List<ClassEntry> entries,
- Project project, Project main) {
- if (mScope.contains(scope)) {
- List<Detector> classDetectors = mScopeDetectors.get(scope);
- if (classDetectors != null && classDetectors.size() > 0 && entries.size() > 0) {
- AsmVisitor visitor = new AsmVisitor(mClient, classDetectors);
-
- String sourceContents = null;
- String sourceName = "";
- mOuterClasses = new ArrayDeque<ClassNode>();
- for (ClassEntry entry : entries) {
- ClassReader reader;
- ClassNode classNode;
- try {
- reader = new ClassReader(entry.bytes);
- classNode = new ClassNode();
- reader.accept(classNode, 0 /* flags */);
- } catch (Throwable t) {
- mClient.log(null, "Error processing %1$s: broken class file?",
- entry.path());
- continue;
- }
-
- ClassNode peek;
- while ((peek = mOuterClasses.peek()) != null) {
- if (classNode.name.startsWith(peek.name)) {
- break;
- } else {
- mOuterClasses.pop();
- }
- }
- mOuterClasses.push(classNode);
-
- if (isSuppressed(null, classNode)) {
- // Class was annotated with suppress all -- no need to look any further
- continue;
- }
-
- if (sourceContents != null) {
- // Attempt to reuse the source buffer if initialized
- // This means making sure that the source files
- // foo/bar/MyClass and foo/bar/MyClass$Bar
- // and foo/bar/MyClass$3 and foo/bar/MyClass$3$1 have the same prefix.
- String newName = classNode.name;
- int newRootLength = newName.indexOf('$');
- if (newRootLength == -1) {
- newRootLength = newName.length();
- }
- int oldRootLength = sourceName.indexOf('$');
- if (oldRootLength == -1) {
- oldRootLength = sourceName.length();
- }
- if (newRootLength != oldRootLength ||
- !sourceName.regionMatches(0, newName, 0, newRootLength)) {
- sourceContents = null;
- }
- }
-
- ClassContext context = new ClassContext(this, project, main,
- entry.file, entry.jarFile, entry.binDir, entry.bytes,
- classNode, scope == Scope.JAVA_LIBRARIES /*fromLibrary*/,
- sourceContents);
-
- try {
- visitor.runClassDetectors(context);
- } catch (Exception e) {
- mClient.log(e, null);
- }
-
- if (mCanceled) {
- return;
- }
-
- sourceContents = context.getSourceContents(false/*read*/);
- sourceName = classNode.name;
- }
-
- mOuterClasses = null;
- }
- }
- }
-
- /** Returns the outer class node of the given class node
- * @param classNode the inner class node
- * @return the outer class node */
- public ClassNode getOuterClassNode(@NonNull ClassNode classNode) {
- String outerName = classNode.outerClass;
-
- Iterator<ClassNode> iterator = mOuterClasses.iterator();
- while (iterator.hasNext()) {
- ClassNode node = iterator.next();
- if (outerName != null) {
- if (node.name.equals(outerName)) {
- return node;
- }
- } else if (node == classNode) {
- return iterator.hasNext() ? iterator.next() : null;
- }
- }
-
- return null;
- }
-
- private Map<String, String> getSuperMap(List<ClassEntry> libraryEntries,
- List<ClassEntry> classEntries) {
- int size = libraryEntries.size() + classEntries.size();
- Map<String, String> map = new HashMap<String, String>(size);
-
- SuperclassVisitor visitor = new SuperclassVisitor(map);
- addSuperClasses(visitor, libraryEntries);
- addSuperClasses(visitor, classEntries);
-
- return map;
- }
-
- private void addSuperClasses(SuperclassVisitor visitor, List<ClassEntry> entries) {
- for (ClassEntry entry : entries) {
- try {
- ClassReader reader = new ClassReader(entry.bytes);
- int flags = ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG
- | ClassReader.SKIP_FRAMES;
- reader.accept(visitor, flags);
- } catch (Throwable t) {
- mClient.log(null, "Error processing %1$s: broken class file?", entry.path());
- }
- }
- }
-
- /** Visitor skimming classes and initializing a map of super classes */
- private static class SuperclassVisitor extends ClassVisitor {
- private final Map<String, String> mMap;
-
- public SuperclassVisitor(Map<String, String> map) {
- super(ASM4);
- mMap = map;
- }
-
- @Override
- public void visit(int version, int access, String name, String signature, String superName,
- String[] interfaces) {
- if (superName != null) {
- mMap.put(name, superName);
- }
- }
- }
-
- private void findClasses(
- @NonNull List<ClassEntry> entries,
- @NonNull List<File> classPath) {
- for (File classPathEntry : classPath) {
- if (classPathEntry.getName().endsWith(DOT_JAR)) {
- File jarFile = classPathEntry;
- if (!jarFile.exists()) {
- continue;
- }
- ZipInputStream zis = null;
- try {
- FileInputStream fis = new FileInputStream(jarFile);
- zis = new ZipInputStream(fis);
- ZipEntry entry = zis.getNextEntry();
- while (entry != null) {
- String name = entry.getName();
- if (name.endsWith(DOT_CLASS)) {
- try {
- byte[] bytes = ByteStreams.toByteArray(zis);
- if (bytes != null) {
- File file = new File(entry.getName());
- entries.add(new ClassEntry(file, jarFile, jarFile, bytes));
- }
- } catch (Exception e) {
- mClient.log(e, null);
- continue;
- }
- }
-
- if (mCanceled) {
- return;
- }
-
- entry = zis.getNextEntry();
- }
- } catch (IOException e) {
- mClient.log(e, "Could not read jar file contents from %1$s", jarFile);
- } finally {
- Closeables.closeQuietly(zis);
- }
-
- continue;
- } else if (classPathEntry.isDirectory()) {
- File binDir = classPathEntry;
- List<File> classFiles = new ArrayList<File>();
- addClassFiles(binDir, classFiles);
-
- for (File file : classFiles) {
- try {
- byte[] bytes = mClient.readBytes(file);
- if (bytes != null) {
- entries.add(new ClassEntry(file, null /* jarFile*/, binDir, bytes));
- }
- } catch (IOException e) {
- mClient.log(e, null);
- continue;
- }
-
- if (mCanceled) {
- return;
- }
- }
- } else {
- mClient.log(null, "Ignoring class path entry %1$s", classPathEntry);
- }
- }
- }
-
- private void addClassFiles(@NonNull File dir, @NonNull List<File> classFiles) {
- // Process the resource folder
- File[] files = dir.listFiles();
- if (files != null && files.length > 0) {
- for (File file : files) {
- if (file.isFile() && file.getName().endsWith(DOT_CLASS)) {
- classFiles.add(file);
- } else if (file.isDirectory()) {
- // Recurse
- addClassFiles(file, classFiles);
- }
- }
- }
- }
-
- private void checkJava(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull List<File> sourceFolders,
- @NonNull List<Detector> checks) {
- IJavaParser javaParser = mClient.getJavaParser();
- if (javaParser == null) {
- mClient.log(null, "No java parser provided to lint: not running Java checks");
- return;
- }
-
- assert checks.size() > 0;
-
- // Gather all Java source files in a single pass; more efficient.
- List<File> sources = new ArrayList<File>(100);
- for (File folder : sourceFolders) {
- gatherJavaFiles(folder, sources);
- }
- if (sources.size() > 0) {
- JavaVisitor visitor = new JavaVisitor(javaParser, checks);
- for (File file : sources) {
- JavaContext context = new JavaContext(this, project, main, file);
- fireEvent(EventType.SCANNING_FILE, context);
- visitor.visitFile(context, file);
- if (mCanceled) {
- return;
- }
- }
- }
- }
-
- private void checkIndividualJavaFiles(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull List<Detector> checks,
- @NonNull List<File> files) {
-
- IJavaParser javaParser = mClient.getJavaParser();
- if (javaParser == null) {
- mClient.log(null, "No java parser provided to lint: not running Java checks");
- return;
- }
-
- JavaVisitor visitor = new JavaVisitor(javaParser, checks);
-
- for (File file : files) {
- if (file.isFile() && file.getPath().endsWith(DOT_JAVA)) {
- JavaContext context = new JavaContext(this, project, main, file);
- fireEvent(EventType.SCANNING_FILE, context);
- visitor.visitFile(context, file);
- if (mCanceled) {
- return;
- }
- }
- }
- }
-
- private void gatherJavaFiles(@NonNull File dir, @NonNull List<File> result) {
- File[] files = dir.listFiles();
- if (files != null) {
- for (File file : files) {
- if (file.isFile() && file.getName().endsWith(".java")) { //$NON-NLS-1$
- result.add(file);
- } else if (file.isDirectory()) {
- gatherJavaFiles(file, result);
- }
- }
- }
- }
-
- private ResourceFolderType mCurrentFolderType;
- private List<ResourceXmlDetector> mCurrentXmlDetectors;
- private XmlVisitor mCurrentVisitor;
-
- @Nullable
- private XmlVisitor getVisitor(
- @NonNull ResourceFolderType type,
- @NonNull List<ResourceXmlDetector> checks) {
- if (type != mCurrentFolderType) {
- mCurrentFolderType = type;
-
- // Determine which XML resource detectors apply to the given folder type
- List<ResourceXmlDetector> applicableChecks =
- new ArrayList<ResourceXmlDetector>(checks.size());
- for (ResourceXmlDetector check : checks) {
- if (check.appliesTo(type)) {
- applicableChecks.add(check);
- }
- }
-
- // If the list of detectors hasn't changed, then just use the current visitor!
- if (mCurrentXmlDetectors != null && mCurrentXmlDetectors.equals(applicableChecks)) {
- return mCurrentVisitor;
- }
-
- if (applicableChecks.size() == 0) {
- mCurrentVisitor = null;
- return null;
- }
-
- IDomParser parser = mClient.getDomParser();
- if (parser != null) {
- mCurrentVisitor = new XmlVisitor(parser, applicableChecks);
- }
- }
-
- return mCurrentVisitor;
- }
-
- private void checkResFolder(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File res,
- @NonNull List<ResourceXmlDetector> checks) {
- assert res.isDirectory();
- File[] resourceDirs = res.listFiles();
- if (resourceDirs == null) {
- return;
- }
-
- // Sort alphabetically such that we can process related folder types at the
- // same time
-
- Arrays.sort(resourceDirs);
- ResourceFolderType type = null;
- for (File dir : resourceDirs) {
- type = ResourceFolderType.getFolderType(dir.getName());
- if (type != null) {
- checkResourceFolder(project, main, dir, type, checks);
- }
-
- if (mCanceled) {
- return;
- }
- }
- }
-
- private void checkResourceFolder(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File dir,
- @NonNull ResourceFolderType type,
- @NonNull List<ResourceXmlDetector> checks) {
- // Process the resource folder
- File[] xmlFiles = dir.listFiles();
- if (xmlFiles != null && xmlFiles.length > 0) {
- XmlVisitor visitor = getVisitor(type, checks);
- if (visitor != null) { // if not, there are no applicable rules in this folder
- for (File file : xmlFiles) {
- if (LintUtils.isXmlFile(file)) {
- XmlContext context = new XmlContext(this, project, main, file, type);
- fireEvent(EventType.SCANNING_FILE, context);
- visitor.visitFile(context, file);
- if (mCanceled) {
- return;
- }
- }
- }
- }
- }
- }
-
- /** Checks individual resources */
- private void checkIndividualResources(
- @NonNull Project project,
- @Nullable Project main,
- @NonNull List<ResourceXmlDetector> xmlDetectors,
- @NonNull List<File> files) {
- for (File file : files) {
- if (file.isDirectory()) {
- // Is it a resource folder?
- ResourceFolderType type = ResourceFolderType.getFolderType(file.getName());
- if (type != null && new File(file.getParentFile(), RES_FOLDER).exists()) {
- // Yes.
- checkResourceFolder(project, main, file, type, xmlDetectors);
- } else if (file.getName().equals(RES_FOLDER)) { // Is it the res folder?
- // Yes
- checkResFolder(project, main, file, xmlDetectors);
- } else {
- mClient.log(null, "Unexpected folder %1$s; should be project, " +
- "\"res\" folder or resource folder", file.getPath());
- continue;
- }
- } else if (file.isFile() && LintUtils.isXmlFile(file)) {
- // Yes, find out its resource type
- String folderName = file.getParentFile().getName();
- ResourceFolderType type = ResourceFolderType.getFolderType(folderName);
- if (type != null) {
- XmlVisitor visitor = getVisitor(type, xmlDetectors);
- if (visitor != null) {
- XmlContext context = new XmlContext(this, project, main, file, type);
- fireEvent(EventType.SCANNING_FILE, context);
- visitor.visitFile(context, file);
- }
- }
- }
- }
- }
-
- /**
- * Adds a listener to be notified of lint progress
- *
- * @param listener the listener to be added
- */
- public void addLintListener(@NonNull LintListener listener) {
- if (mListeners == null) {
- mListeners = new ArrayList<LintListener>(1);
- }
- mListeners.add(listener);
- }
-
- /**
- * Removes a listener such that it is no longer notified of progress
- *
- * @param listener the listener to be removed
- */
- public void removeLintListener(@NonNull LintListener listener) {
- mListeners.remove(listener);
- if (mListeners.size() == 0) {
- mListeners = null;
- }
- }
-
- /** Notifies listeners, if any, that the given event has occurred */
- private void fireEvent(@NonNull LintListener.EventType type, @Nullable Context context) {
- if (mListeners != null) {
- for (int i = 0, n = mListeners.size(); i < n; i++) {
- LintListener listener = mListeners.get(i);
- listener.update(this, type, context);
- }
- }
- }
-
- /**
- * Wrapper around the lint client. This sits in the middle between a
- * detector calling for example
- * {@link LintClient#report(Context, Issue, Location, String, Object)} and
- * the actual embedding tool, and performs filtering etc such that detectors
- * and lint clients don't have to make sure they check for ignored issues or
- * filtered out warnings.
- */
- private class LintClientWrapper extends LintClient {
- @NonNull
- private final LintClient mDelegate;
-
- public LintClientWrapper(@NonNull LintClient delegate) {
- mDelegate = delegate;
- }
-
- @Override
- public void report(
- @NonNull Context context,
- @NonNull Issue issue,
- @NonNull Severity severity,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- assert mCurrentProject != null;
- if (!mCurrentProject.getReportIssues()) {
- return;
- }
-
- Configuration configuration = context.getConfiguration();
- if (!configuration.isEnabled(issue)) {
- if (issue != IssueRegistry.PARSER_ERROR && issue != IssueRegistry.LINT_ERROR) {
- mDelegate.log(null, "Incorrect detector reported disabled issue %1$s",
- issue.toString());
- }
- return;
- }
-
- if (configuration.isIgnored(context, issue, location, message, data)) {
- return;
- }
-
- if (severity == Severity.IGNORE) {
- return;
- }
-
- mDelegate.report(context, issue, severity, location, message, data);
- }
-
- // Everything else just delegates to the embedding lint client
-
- @Override
- @NonNull
- public Configuration getConfiguration(@NonNull Project project) {
- return mDelegate.getConfiguration(project);
- }
-
-
- @Override
- public void log(@NonNull Severity severity, @Nullable Throwable exception,
- @Nullable String format, @Nullable Object... args) {
- mDelegate.log(exception, format, args);
- }
-
- @Override
- @NonNull
- public String readFile(@NonNull File file) {
- return mDelegate.readFile(file);
- }
-
- @Override
- @NonNull
- public byte[] readBytes(@NonNull File file) throws IOException {
- return mDelegate.readBytes(file);
- }
-
- @Override
- @NonNull
- public List<File> getJavaSourceFolders(@NonNull Project project) {
- return mDelegate.getJavaSourceFolders(project);
- }
-
- @Override
- @NonNull
- public List<File> getJavaClassFolders(@NonNull Project project) {
- return mDelegate.getJavaClassFolders(project);
- }
-
- @Override
- public @NonNull List<File> getJavaLibraries(@NonNull Project project) {
- return mDelegate.getJavaLibraries(project);
- }
-
- @Override
- @Nullable
- public IDomParser getDomParser() {
- return mDelegate.getDomParser();
- }
-
- @Override
- @NonNull
- public Class<? extends Detector> replaceDetector(
- @NonNull Class<? extends Detector> detectorClass) {
- return mDelegate.replaceDetector(detectorClass);
- }
-
- @Override
- @NonNull
- public SdkInfo getSdkInfo(@NonNull Project project) {
- return mDelegate.getSdkInfo(project);
- }
-
- @Override
- @NonNull
- public Project getProject(@NonNull File dir, @NonNull File referenceDir) {
- return mDelegate.getProject(dir, referenceDir);
- }
-
- @Override
- @Nullable
- public IJavaParser getJavaParser() {
- return mDelegate.getJavaParser();
- }
-
- @Override
- public File findResource(@NonNull String relativePath) {
- return mDelegate.findResource(relativePath);
- }
-
- @Override
- @Nullable
- public File getCacheDir(boolean create) {
- return mDelegate.getCacheDir(create);
- }
-
- @Override
- @NonNull
- protected ClassPathInfo getClassPath(@NonNull Project project) {
- return mDelegate.getClassPath(project);
- }
-
- @Override
- public void log(@Nullable Throwable exception, @Nullable String format,
- @Nullable Object... args) {
- mDelegate.log(exception, format, args);
- }
-
- @Override
- @Nullable
- public File getSdkHome() {
- return mDelegate.getSdkHome();
- }
-
- @Override
- @NonNull
- public IAndroidTarget[] getTargets() {
- return mDelegate.getTargets();
- }
-
- @Override
- public int getHighestKnownApiLevel() {
- return mDelegate.getHighestKnownApiLevel();
- }
- }
-
- /**
- * Requests another pass through the data for the given detector. This is
- * typically done when a detector needs to do more expensive computation,
- * but it only wants to do this once it <b>knows</b> that an error is
- * present, or once it knows more specifically what to check for.
- *
- * @param detector the detector that should be included in the next pass.
- * Note that the lint runner may refuse to run more than a couple
- * of runs.
- * @param scope the scope to be revisited. This must be a subset of the
- * current scope ({@link #getScope()}, and it is just a performance hint;
- * in particular, the detector should be prepared to be called on other
- * scopes as well (since they may have been requested by other detectors).
- * You can pall null to indicate "all".
- */
- public void requestRepeat(@NonNull Detector detector, @Nullable EnumSet<Scope> scope) {
- if (mRepeatingDetectors == null) {
- mRepeatingDetectors = new ArrayList<Detector>();
- }
- mRepeatingDetectors.add(detector);
-
- if (scope != null) {
- if (mRepeatScope == null) {
- mRepeatScope = scope;
- } else {
- mRepeatScope = EnumSet.copyOf(mRepeatScope);
- mRepeatScope.addAll(scope);
- }
- } else {
- mRepeatScope = Scope.ALL;
- }
- }
-
- // Unfortunately, ASMs nodes do not extend a common DOM node type with parent
- // pointers, so we have to have multiple methods which pass in each type
- // of node (class, method, field) to be checked.
-
- // TODO: The Quickfix should look for lint warnings placed *inside* warnings
- // and warn that they won't apply to checks that are bytecode oriented!
-
- /**
- * Returns whether the given issue is suppressed in the given method.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param method the method containing the issue
- * @return true if there is a suppress annotation covering the specific
- * issue on this method
- */
- public boolean isSuppressed(@Nullable Issue issue, @NonNull MethodNode method) {
- if (method.invisibleAnnotations != null) {
- @SuppressWarnings("unchecked")
- List<AnnotationNode> annotations = method.invisibleAnnotations;
- return isSuppressed(issue, annotations);
- }
-
- return false;
- }
-
- /**
- * Returns whether the given issue is suppressed for the given field.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param field the field potentially annotated with a suppress annotation
- * @return true if there is a suppress annotation covering the specific
- * issue on this field
- */
- public boolean isSuppressed(@Nullable Issue issue, @NonNull FieldNode field) {
- if (field.invisibleAnnotations != null) {
- @SuppressWarnings("unchecked")
- List<AnnotationNode> annotations = field.invisibleAnnotations;
- return isSuppressed(issue, annotations);
- }
-
- return false;
- }
-
- /**
- * Returns whether the given issue is suppressed in the given class.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param classNode the class containing the issue
- * @return true if there is a suppress annotation covering the specific
- * issue in this class
- */
- public boolean isSuppressed(@Nullable Issue issue, @NonNull ClassNode classNode) {
- if (classNode.invisibleAnnotations != null) {
- @SuppressWarnings("unchecked")
- List<AnnotationNode> annotations = classNode.invisibleAnnotations;
- return isSuppressed(issue, annotations);
- }
-
- return false;
- }
-
- private boolean isSuppressed(@Nullable Issue issue, List<AnnotationNode> annotations) {
- for (AnnotationNode annotation : annotations) {
- String desc = annotation.desc;
-
- // We could obey @SuppressWarnings("all") too, but no need to look for it
- // because that annotation only has source retention.
-
- if (desc.endsWith(SUPPRESS_LINT_VMSIG)) {
- if (annotation.values != null) {
- for (int i = 0, n = annotation.values.size(); i < n; i += 2) {
- String key = (String) annotation.values.get(i);
- if (key.equals("value")) { //$NON-NLS-1$
- Object value = annotation.values.get(i + 1);
- if (value instanceof String) {
- String id = (String) value;
- if (id.equalsIgnoreCase(SUPPRESS_ALL) ||
- issue != null && id.equalsIgnoreCase(issue.getId())) {
- return true;
- }
- } else if (value instanceof List) {
- @SuppressWarnings("rawtypes")
- List list = (List) value;
- for (Object v : list) {
- if (v instanceof String) {
- String id = (String) v;
- if (id.equalsIgnoreCase(SUPPRESS_ALL) || (issue != null
- && id.equalsIgnoreCase(issue.getId()))) {
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns whether the given issue is suppressed in the given parse tree node.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param scope the AST node containing the issue
- * @return true if there is a suppress annotation covering the specific
- * issue in this class
- */
- public boolean isSuppressed(@NonNull Issue issue, @Nullable Node scope) {
- while (scope != null) {
- Class<? extends Node> type = scope.getClass();
- // The Lombok AST uses a flat hierarchy of node type implementation classes
- // so no need to do instanceof stuff here.
- if (type == VariableDefinition.class) {
- // Variable
- VariableDefinition declaration = (VariableDefinition) scope;
- if (isSuppressed(issue, declaration.astModifiers())) {
- return true;
- }
- } else if (type == MethodDeclaration.class) {
- // Method
- // Look for annotations on the method
- MethodDeclaration declaration = (MethodDeclaration) scope;
- if (isSuppressed(issue, declaration.astModifiers())) {
- return true;
- }
- } else if (type == ConstructorDeclaration.class) {
- // Constructor
- // Look for annotations on the method
- ConstructorDeclaration declaration = (ConstructorDeclaration) scope;
- if (isSuppressed(issue, declaration.astModifiers())) {
- return true;
- }
- } else if (type == ClassDeclaration.class) {
- // Class
- ClassDeclaration declaration = (ClassDeclaration) scope;
- if (isSuppressed(issue, declaration.astModifiers())) {
- return true;
- }
- }
-
- scope = scope.getParent();
- }
-
- return false;
- }
-
- /**
- * Returns true if the given AST modifier has a suppress annotation for the
- * given issue (which can be null to check for the "all" annotation)
- *
- * @param issue the issue to be checked
- * @param modifiers the modifier to check
- * @return true if the issue or all issues should be suppressed for this
- * modifier
- */
- private static boolean isSuppressed(@Nullable Issue issue, @Nullable Modifiers modifiers) {
- if (modifiers == null) {
- return false;
- }
- StrictListAccessor<Annotation, Modifiers> annotations = modifiers.astAnnotations();
- if (annotations == null) {
- return false;
- }
-
- Iterator<Annotation> iterator = annotations.iterator();
- while (iterator.hasNext()) {
- Annotation annotation = iterator.next();
- TypeReference t = annotation.astAnnotationTypeReference();
- String typeName = t.getTypeName();
- if (typeName.endsWith(SUPPRESS_LINT)
- || typeName.endsWith("SuppressWarnings")) { //$NON-NLS-1$
- StrictListAccessor<AnnotationElement, Annotation> values =
- annotation.astElements();
- if (values != null) {
- Iterator<AnnotationElement> valueIterator = values.iterator();
- while (valueIterator.hasNext()) {
- AnnotationElement element = valueIterator.next();
- AnnotationValue valueNode = element.astValue();
- if (valueNode == null) {
- continue;
- }
- if (valueNode instanceof StringLiteral) {
- StringLiteral literal = (StringLiteral) valueNode;
- String value = literal.astValue();
- if (value.equalsIgnoreCase(SUPPRESS_ALL) ||
- issue != null && issue.getId().equalsIgnoreCase(value)) {
- return true;
- }
- } else if (valueNode instanceof ArrayInitializer) {
- ArrayInitializer array = (ArrayInitializer) valueNode;
- StrictListAccessor<Expression, ArrayInitializer> expressions =
- array.astExpressions();
- if (expressions == null) {
- continue;
- }
- Iterator<Expression> arrayIterator = expressions.iterator();
- while (arrayIterator.hasNext()) {
- Expression arrayElement = arrayIterator.next();
- if (arrayElement instanceof StringLiteral) {
- String value = ((StringLiteral) arrayElement).astValue();
- if (value.equalsIgnoreCase(SUPPRESS_ALL) || (issue != null
- && issue.getId().equalsIgnoreCase(value))) {
- return true;
- }
- }
- }
- }
- }
- }
- }
- }
-
- return false;
- }
-
- /**
- * Returns whether the given issue is suppressed in the given XML DOM node.
- *
- * @param issue the issue to be checked, or null to just check for "all"
- * @param node the DOM node containing the issue
- * @return true if there is a suppress annotation covering the specific
- * issue in this class
- */
- public boolean isSuppressed(@NonNull Issue issue, @Nullable org.w3c.dom.Node node) {
- if (node instanceof Attr) {
- node = ((Attr) node).getOwnerElement();
- }
- while (node != null) {
- if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) {
- Element element = (Element) node;
- if (element.hasAttributeNS(TOOLS_URI, ATTR_IGNORE)) {
- String ignore = element.getAttributeNS(TOOLS_URI, ATTR_IGNORE);
- if (ignore.indexOf(',') == -1) {
- if (ignore.equalsIgnoreCase(SUPPRESS_ALL) || (issue != null
- && issue.getId().equalsIgnoreCase(ignore))) {
- return true;
- }
- } else {
- for (String id : ignore.split(",")) { //$NON-NLS-1$
- if (id.equalsIgnoreCase(SUPPRESS_ALL) || (issue != null
- && issue.getId().equalsIgnoreCase(id))) {
- return true;
- }
- }
- }
- }
- }
-
- node = node.getParentNode();
- }
-
- return false;
- }
-
- /** A pending class to be analyzed by {@link #checkClasses} */
- @VisibleForTesting
- static class ClassEntry implements Comparable<ClassEntry> {
- public final File file;
- public final File jarFile;
- public final File binDir;
- public final byte[] bytes;
-
- public ClassEntry(File file, File jarFile, File binDir, byte[] bytes) {
- super();
- this.file = file;
- this.jarFile = jarFile;
- this.binDir = binDir;
- this.bytes = bytes;
- }
-
- public String path() {
- if (jarFile != null) {
- return jarFile.getPath() + ':' + file.getPath();
- } else {
- return file.getPath();
- }
- }
-
- @Override
- public int compareTo(ClassEntry other) {
- String p1 = file.getPath();
- String p2 = other.file.getPath();
- int m1 = p1.length();
- int m2 = p2.length();
- int m = Math.min(m1, m2);
-
- for (int i = 0; i < m; i++) {
- char c1 = p1.charAt(i);
- char c2 = p2.charAt(i);
- if (c1 != c2) {
- // Sort Foo$Bar.class *after* Foo.class, even though $ < .
- if (c1 == '.' && c2 == '$') {
- return -1;
- }
- if (c1 == '$' && c2 == '.') {
- return 1;
- }
- return c1 - c2;
- }
- }
-
- return (m == m1) ? -1 : 1;
- }
-
- @Override
- public String toString() {
- return file.getPath();
- }
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintListener.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintListener.java
deleted file mode 100644
index 2247a6d..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintListener.java
+++ /dev/null
@@ -1,70 +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.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.detector.api.Context;
-import com.google.common.annotations.Beta;
-
-/**
- * Interface implemented by listeners to be notified of lint events
- * <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 interface LintListener {
- /** The various types of events provided to lint listeners */
- public enum EventType {
- /** A lint check is about to begin */
- STARTING,
-
- /** Lint is about to check the given project, see {@link Context#getProject()} */
- SCANNING_PROJECT,
-
- /** Lint is about to check the given library project, see {@link Context#getProject()} */
- SCANNING_LIBRARY_PROJECT,
-
- /** Lint is about to check the given file, see {@link Context#file} */
- SCANNING_FILE,
-
- /** A new pass was initiated */
- NEW_PHASE,
-
- /** The lint check was canceled */
- CANCELED,
-
- /** The lint check is done */
- COMPLETED,
- };
-
- /**
- * Notifies listeners that the event of the given type has occurred.
- * Additional information, such as the file being scanned, or the project
- * being scanned, is available in the {@link Context} object (except for the
- * {@link EventType#STARTING}, {@link EventType#CANCELED} or
- * {@link EventType#COMPLETED} events which are fired outside of project
- * contexts.)
- *
- * @param driver the driver running through the checks
- * @param type the type of event that occurred
- * @param context the context providing additional information
- */
- public void update(@NonNull LintDriver driver, @NonNull EventType type,
- @Nullable Context context);
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/SdkInfo.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/SdkInfo.java
deleted file mode 100644
index 5ff7f90..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/SdkInfo.java
+++ /dev/null
@@ -1,80 +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.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.annotations.Beta;
-
-/**
- * Information about SDKs
- * <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 abstract class SdkInfo {
- /**
- * Returns true if the given child view is the same class or a sub class of
- * the given parent view class
- *
- * @param parentViewFqcn the fully qualified class name of the parent view
- * @param childViewFqcn the fully qualified class name of the child view
- * @return true if the child view is a sub view of (or the same class as)
- * the parent view
- */
- public boolean isSubViewOf(@NonNull String parentViewFqcn, @NonNull String childViewFqcn) {
- while (!childViewFqcn.equals("android.view.View")) { //$NON-NLS-1$
- if (parentViewFqcn.equals(childViewFqcn)) {
- return true;
- }
- String parent = getParentViewClass(childViewFqcn);
- if (parent == null) {
- // Unknown view - err on the side of caution
- return true;
- }
- childViewFqcn = parent;
- }
-
- return false;
- }
-
-
- /**
- * Returns the fully qualified name of the parent view, or null if the view
- * is the root android.view.View class.
- *
- * @param fqcn the fully qualified class name of the view
- * @return the fully qualified class name of the parent view, or null
- */
- @Nullable
- public abstract String getParentViewClass(@NonNull String fqcn);
-
- /**
- * Returns the class name of the parent view, or null if the view is the
- * root android.view.View class. This is the same as the
- * {@link #getParentViewClass(String)} but without the package.
- *
- * @param name the view class name to look up the parent for (not including
- * package)
- * @return the view name of the parent
- */
- @Nullable
- public abstract String getParentViewName(@NonNull String name);
-
- // TODO: Add access to resource resolution here.
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/XmlVisitor.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/XmlVisitor.java
deleted file mode 100644
index 816c028..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/XmlVisitor.java
+++ /dev/null
@@ -1,227 +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.client.api;
-
-import com.android.annotations.NonNull;
-import com.android.tools.lint.detector.api.Detector;
-import com.android.tools.lint.detector.api.Detector.XmlScanner;
-import com.android.tools.lint.detector.api.LintUtils;
-import com.android.tools.lint.detector.api.XmlContext;
-import com.google.common.annotations.Beta;
-
-import org.w3c.dom.Attr;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.RandomAccess;
-
-/**
- * Specialized visitor for running detectors on an XML document.
- * It operates in two phases:
- * <ol>
- * <li> First, it computes a set of maps where it generates a map from each
- * significant element name, and each significant attribute name, to a list
- * of detectors to consult for that element or attribute name.
- * The set of element names or attribute names (or both) that a detector
- * is interested in is provided by the detectors themselves.
- * <li> Second, it iterates over the document a single time. For each element and
- * attribute it looks up the list of interested detectors, and runs them.
- * </ol>
- * It also notifies all the detectors before and after the document is processed
- * such that they can do pre- and post-processing.
- * <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
-class XmlVisitor {
- private final Map<String, List<Detector.XmlScanner>> mElementToCheck =
- new HashMap<String, List<Detector.XmlScanner>>();
- private final Map<String, List<Detector.XmlScanner>> mAttributeToCheck =
- new HashMap<String, List<Detector.XmlScanner>>();
- private final List<Detector.XmlScanner> mDocumentDetectors =
- new ArrayList<Detector.XmlScanner>();
- private final List<Detector.XmlScanner> mAllElementDetectors =
- new ArrayList<Detector.XmlScanner>();
- private final List<Detector.XmlScanner> mAllAttributeDetectors =
- new ArrayList<Detector.XmlScanner>();
- private final List<? extends Detector> mAllDetectors;
- private final IDomParser mParser;
-
- // Really want this:
- //<T extends List<Detector> & Detector.XmlScanner> XmlVisitor(IDomParser parser,
- // T xmlDetectors) {
- // but it makes client code tricky and ugly.
- XmlVisitor(@NonNull IDomParser parser, @NonNull List<? extends Detector> xmlDetectors) {
- mParser = parser;
- mAllDetectors = xmlDetectors;
-
- // TODO: Check appliesTo() for files, and find a quick way to enable/disable
- // rules when running through a full project!
- for (Detector detector : xmlDetectors) {
- Detector.XmlScanner xmlDetector = (XmlScanner) detector;
- Collection<String> attributes = xmlDetector.getApplicableAttributes();
- if (attributes == XmlScanner.ALL) {
- mAllAttributeDetectors.add(xmlDetector);
- } else if (attributes != null) {
- for (String attribute : attributes) {
- List<Detector.XmlScanner> list = mAttributeToCheck.get(attribute);
- if (list == null) {
- list = new ArrayList<Detector.XmlScanner>();
- mAttributeToCheck.put(attribute, list);
- }
- list.add(xmlDetector);
- }
- }
- Collection<String> elements = xmlDetector.getApplicableElements();
- if (elements == XmlScanner.ALL) {
- mAllElementDetectors.add(xmlDetector);
- } else if (elements != null) {
- for (String element : elements) {
- List<Detector.XmlScanner> list = mElementToCheck.get(element);
- if (list == null) {
- list = new ArrayList<Detector.XmlScanner>();
- mElementToCheck.put(element, list);
- }
- list.add(xmlDetector);
- }
- }
-
- if ((attributes == null || (attributes.size() == 0
- && attributes != XmlScanner.ALL))
- && (elements == null || (elements.size() == 0
- && elements != XmlScanner.ALL))) {
- mDocumentDetectors.add(xmlDetector);
- }
- }
- }
-
- void visitFile(@NonNull XmlContext context, @NonNull File file) {
- assert LintUtils.isXmlFile(file);
- context.parser = mParser;
-
- try {
- if (context.document == null) {
- context.document = mParser.parseXml(context);
- if (context.document == null) {
- // No need to log this; the parser should be reporting
- // a full warning (such as IssueRegistry#PARSER_ERROR)
- // with details, location, etc.
- return;
- }
- if (context.document.getDocumentElement() == null) {
- // Ignore empty documents
- return;
- }
- }
-
- for (Detector check : mAllDetectors) {
- check.beforeCheckFile(context);
- }
-
- for (Detector.XmlScanner check : mDocumentDetectors) {
- check.visitDocument(context, context.document);
- }
-
- if (mElementToCheck.size() > 0 || mAttributeToCheck.size() > 0
- || mAllAttributeDetectors.size() > 0 || mAllElementDetectors.size() > 0) {
- visitElement(context, context.document.getDocumentElement());
- }
-
- for (Detector check : mAllDetectors) {
- check.afterCheckFile(context);
- }
- } finally {
- if (context.document != null) {
- mParser.dispose(context, context.document);
- context.document = null;
- }
- }
- }
-
- private void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- List<Detector.XmlScanner> elementChecks = mElementToCheck.get(element.getTagName());
- if (elementChecks != null) {
- assert elementChecks instanceof RandomAccess;
- for (int i = 0, n = elementChecks.size(); i < n; i++) {
- Detector.XmlScanner check = elementChecks.get(i);
- check.visitElement(context, element);
- }
- }
- if (mAllElementDetectors.size() > 0) {
- for (int i = 0, n = mAllElementDetectors.size(); i < n; i++) {
- Detector.XmlScanner check = mAllElementDetectors.get(i);
- check.visitElement(context, element);
- }
- }
-
- if (mAttributeToCheck.size() > 0 || mAllAttributeDetectors.size() > 0) {
- NamedNodeMap attributes = element.getAttributes();
- for (int i = 0, n = attributes.getLength(); i < n; i++) {
- Attr attribute = (Attr) attributes.item(i);
- String name = attribute.getLocalName();
- if (name == null) {
- name = attribute.getName();
- }
- List<Detector.XmlScanner> list = mAttributeToCheck.get(name);
- if (list != null) {
- for (int j = 0, max = list.size(); j < max; j++) {
- Detector.XmlScanner check = list.get(j);
- check.visitAttribute(context, attribute);
- }
- }
- if (mAllAttributeDetectors.size() > 0) {
- for (int j = 0, max = mAllAttributeDetectors.size(); j < max; j++) {
- Detector.XmlScanner check = mAllAttributeDetectors.get(j);
- check.visitAttribute(context, attribute);
- }
- }
- }
- }
-
- // Visit children
- NodeList childNodes = element.getChildNodes();
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.ELEMENT_NODE) {
- visitElement(context, (Element) child);
- }
- }
-
- // Post hooks
- if (elementChecks != null) {
- for (int i = 0, n = elementChecks.size(); i < n; i++) {
- Detector.XmlScanner check = elementChecks.get(i);
- check.visitElementAfter(context, element);
- }
- }
- if (mAllElementDetectors.size() > 0) {
- for (int i = 0, n = mAllElementDetectors.size(); i < n; i++) {
- Detector.XmlScanner check = mAllElementDetectors.get(i);
- check.visitElementAfter(context, element);
- }
- }
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Category.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Category.java
deleted file mode 100644
index ba8e5b5..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Category.java
+++ /dev/null
@@ -1,170 +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 com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.annotations.Beta;
-
-/**
- * A category is a container for related issues.
- * <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 final class Category implements Comparable<Category> {
- private final String mName;
- private final String mExplanation;
- private final int mPriority;
- private final Category mParent;
-
- /**
- * Creates a new {@link Category}.
- *
- * @param parent the name of a parent category, or null
- * @param name the name of the category
- * @param explanation an optional explanation of the category
- * @param priority a sorting priority, with higher being more important
- */
- private Category(
- @Nullable Category parent,
- @NonNull String name,
- @Nullable String explanation,
- int priority) {
- mParent = parent;
- mName = name;
- mExplanation = explanation;
- mPriority = priority;
- }
-
- /**
- * Creates a new top level {@link Category} with the given sorting priority.
- *
- * @param name the name of the category
- * @param priority a sorting priority, with higher being more important
- * @return a new category
- */
- @NonNull
- public static Category create(@NonNull String name, int priority) {
- return new Category(null, name, null, priority);
- }
-
- /**
- * Creates a new top level {@link Category} with the given sorting priority.
- *
- * @param parent the name of a parent category, or null
- * @param name the name of the category
- * @param explanation an optional explanation of the category
- * @param priority a sorting priority, with higher being more important
- * @return a new category
- */
- @NonNull
- public static Category create(
- @Nullable Category parent,
- @NonNull String name,
- @Nullable String explanation,
- int priority) {
- return new Category(parent, name, null, priority);
- }
-
- /**
- * Returns the parent category, or null if this is a top level category
- *
- * @return the parent category, or null if this is a top level category
- */
- public Category getParent() {
- return mParent;
- }
-
- /**
- * Returns the name of this category
- *
- * @return the name of this category
- */
- public String getName() {
- return mName;
- }
-
- /**
- * Returns an explanation for this category, or null
- *
- * @return an explanation for this category, or null
- */
- public String getExplanation() {
- return mExplanation;
- }
-
- /**
- * Returns a full name for this category. For a top level category, this is just
- * the {@link #getName()} value, but for nested categories it will include the parent
- * names as well.
- *
- * @return a full name for this category
- */
- public String getFullName() {
- if (mParent != null) {
- return mParent.getFullName() + ':' + mName;
- } else {
- return mName;
- }
- }
-
- @Override
- public int compareTo(Category other) {
- if (other.mPriority == mPriority) {
- if (mParent == other) {
- return 1;
- } else if (other.mParent == this) {
- return -1;
- }
- }
- return other.mPriority - mPriority;
- }
-
- /** Issues related to running lint itself */
- public static final Category LINT = Category.create("Lint", 110);
-
- /** Issues related to correctness */
- public static final Category CORRECTNESS = Category.create("Correctness", 100);
-
- /** Issues related to security */
- public static final Category SECURITY = Category.create("Security", 90);
-
- /** Issues related to performance */
- public static final Category PERFORMANCE = Category.create("Performance", 80);
-
- /** Issues related to usability */
- public static final Category USABILITY = Category.create("Usability", 70);
-
- /** Issues related to accessibility */
- public static final Category A11Y = Category.create("Accessibility", 60);
-
- /** Issues related to internationalization */
- public static final Category I18N = Category.create("Internationalization", 50);
-
- // Sub categories
-
- /** Issues related to icons */
- public static final Category ICONS = Category.create(USABILITY, "Icons", null, 73);
-
- /** Issues related to typography */
- public static final Category TYPOGRAPHY = Category.create(USABILITY, "Typography", null, 76);
-
- /** Issues related to messages/strings */
- public static final Category MESSAGES = Category.create(CORRECTNESS, "Messages", null, 95);
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java
deleted file mode 100644
index 68c25d9..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java
+++ /dev/null
@@ -1,663 +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.CONSTRUCTOR_NAME;
-import static com.android.SdkConstants.DOT_CLASS;
-import static com.android.SdkConstants.DOT_JAVA;
-import static com.android.tools.lint.detector.api.Location.SearchDirection.BACKWARD;
-import static com.android.tools.lint.detector.api.Location.SearchDirection.EOL_BACKWARD;
-import static com.android.tools.lint.detector.api.Location.SearchDirection.FORWARD;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.LintDriver;
-import com.android.tools.lint.detector.api.Location.SearchHints;
-import com.google.common.annotations.Beta;
-
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldNode;
-import org.objectweb.asm.tree.LineNumberNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import java.io.File;
-import java.util.List;
-
-/**
- * A {@link Context} used when checking .class files.
- * <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 ClassContext extends Context {
- private final File mBinDir;
- /** The class file DOM root node */
- private ClassNode mClassNode;
- /** The class file byte data */
- private byte[] mBytes;
- /** The source file, if known/found */
- private File mSourceFile;
- /** The contents of the source file, if source file is known/found */
- private String mSourceContents;
- /** Whether we've searched for the source file (used to avoid repeated failed searches) */
- private boolean mSearchedForSource;
- /** If the file is a relative path within a jar file, this is the jar file, otherwise null */
- private final File mJarFile;
- /** Whether this class is part of a library (rather than corresponding to one of the
- * source files in this project */
- private final boolean mFromLibrary;
-
- /**
- * Construct a new {@link ClassContext}
- *
- * @param driver the driver running through the checks
- * @param project the project containing the file being checked
- * @param main the main project if this project is a library project, or
- * null if this is not a library project. The main project is the
- * root project of all library projects, not necessarily the
- * directly including project.
- * @param file the file being checked
- * @param jarFile If the file is a relative path within a jar file, this is
- * the jar file, otherwise null
- * @param binDir the root binary directory containing this .class file.
- * @param bytes the bytecode raw data
- * @param classNode the bytecode object model
- * @param fromLibrary whether this class is from a library rather than part
- * of this project
- * @param sourceContents initial contents of the Java source, if known, or
- * null
- */
- public ClassContext(
- @NonNull LintDriver driver,
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File file,
- @Nullable File jarFile,
- @NonNull File binDir,
- @NonNull byte[] bytes,
- @NonNull ClassNode classNode,
- boolean fromLibrary,
- @Nullable String sourceContents) {
- super(driver, project, main, file);
- mJarFile = jarFile;
- mBinDir = binDir;
- mBytes = bytes;
- mClassNode = classNode;
- mFromLibrary = fromLibrary;
- mSourceContents = sourceContents;
- }
-
- /**
- * Returns the raw bytecode data for this class file
- *
- * @return the byte array containing the bytecode data
- */
- @NonNull
- public byte[] getBytecode() {
- return mBytes;
- }
-
- /**
- * Returns the bytecode object model
- *
- * @return the bytecode object model, never null
- */
- @NonNull
- public ClassNode getClassNode() {
- return mClassNode;
- }
-
- /**
- * Returns the jar file, if any. If this is null, the .class file is a real file
- * on disk, otherwise it represents a relative path within the jar file.
- *
- * @return the jar file, or null
- */
- @Nullable
- public File getJarFile() {
- return mJarFile;
- }
-
- /**
- * Returns whether this class is part of a library (not this project).
- *
- * @return true if this class is part of a library
- */
- public boolean isFromClassLibrary() {
- return mFromLibrary;
- }
-
- /**
- * Returns the source file for this class file, if possible.
- *
- * @return the source file, or null
- */
- @Nullable
- public File getSourceFile() {
- if (mSourceFile == null && !mSearchedForSource) {
- mSearchedForSource = true;
-
- String source = mClassNode.sourceFile;
- if (source == null) {
- source = file.getName();
- if (source.endsWith(DOT_CLASS)) {
- source = source.substring(0, source.length() - DOT_CLASS.length()) + DOT_JAVA;
- }
- int index = source.indexOf('$');
- if (index != -1) {
- source = source.substring(0, index) + DOT_JAVA;
- }
- }
- if (source != null) {
- if (mJarFile != null) {
- String relative = file.getParent() + File.separator + source;
- List<File> sources = getProject().getJavaSourceFolders();
- for (File dir : sources) {
- File sourceFile = new File(dir, relative);
- if (sourceFile.exists()) {
- mSourceFile = sourceFile;
- break;
- }
- }
- } else {
- // Determine package
- String topPath = mBinDir.getPath();
- String parentPath = file.getParentFile().getPath();
- if (parentPath.startsWith(topPath)) {
- int start = topPath.length() + 1;
- String relative = start > parentPath.length() ? // default package?
- "" : parentPath.substring(start);
- List<File> sources = getProject().getJavaSourceFolders();
- for (File dir : sources) {
- File sourceFile = new File(dir, relative + File.separator + source);
- if (sourceFile.exists()) {
- mSourceFile = sourceFile;
- break;
- }
- }
- }
- }
- }
- }
-
- return mSourceFile;
- }
-
- /**
- * Returns the contents of the source file for this class file, if found.
- *
- * @return the source contents, or ""
- */
- @NonNull
- public String getSourceContents() {
- if (mSourceContents == null) {
- File sourceFile = getSourceFile();
- if (sourceFile != null) {
- mSourceContents = getClient().readFile(mSourceFile);
- }
-
- if (mSourceContents == null) {
- mSourceContents = "";
- }
- }
-
- return mSourceContents;
- }
-
- /**
- * Returns the contents of the source file for this class file, if found. If
- * {@code read} is false, do not read the source contents if it has not
- * already been read. (This is primarily intended for the lint
- * infrastructure; most client code would call {@link #getSourceContents()}
- * .)
- *
- * @param read whether to read the source contents if it has not already
- * been initialized
- * @return the source contents, which will never be null if {@code read} is
- * true, or null if {@code read} is false and the source contents
- * hasn't already been read.
- */
- @Nullable
- public String getSourceContents(boolean read) {
- if (read) {
- return getSourceContents();
- } else {
- return mSourceContents;
- }
- }
-
- /**
- * Returns a location for the given source line number in this class file's
- * source file, if available.
- *
- * @param line the line number (1-based, which is what ASM uses)
- * @param patternStart optional pattern to search for in the source for
- * range start
- * @param patternEnd optional pattern to search for in the source for range
- * end
- * @param hints additional hints about the pattern search (provided
- * {@code patternStart} is non null)
- * @return a location, never null
- */
- @NonNull
- public Location getLocationForLine(int line, @Nullable String patternStart,
- @Nullable String patternEnd, @Nullable SearchHints hints) {
- File sourceFile = getSourceFile();
- if (sourceFile != null) {
- // ASM line numbers are 1-based, and lint line numbers are 0-based
- if (line != -1) {
- return Location.create(sourceFile, getSourceContents(), line - 1,
- patternStart, patternEnd, hints);
- } else {
- return Location.create(sourceFile);
- }
- }
-
- return Location.create(file);
- }
-
- /**
- * Reports an issue.
- * <p>
- * Detectors should only call this method if an error applies to the whole class
- * scope and there is no specific method or field that applies to the error.
- * If so, use
- * {@link #report(Issue, MethodNode, Location, String, Object)} or
- * {@link #report(Issue, FieldNode, Location, String, Object)}, such that
- * suppress annotations are checked.
- *
- * @param issue the issue to report
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- @Override
- public void report(
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (mDriver.isSuppressed(issue, mClassNode)) {
- return;
- }
- ClassNode curr = mClassNode;
- while (curr != null) {
- ClassNode prev = curr;
- curr = mDriver.getOuterClassNode(curr);
- if (curr != null) {
- if (prev.outerMethod != null) {
- @SuppressWarnings("rawtypes") // ASM API
- List methods = curr.methods;
- for (Object m : methods) {
- MethodNode method = (MethodNode) m;
- if (method.name.equals(prev.outerMethod)
- && method.desc.equals(prev.outerMethodDesc)) {
- // Found the outer method for this anonymous class; continue
- // reporting on it (which will also work its way up the parent
- // class hierarchy)
- if (method != null && mDriver.isSuppressed(issue, method)) {
- return;
- }
- break;
- }
- }
- }
- if (mDriver.isSuppressed(issue, curr)) {
- return;
- }
- }
- }
-
- super.report(issue, location, message, data);
- }
-
- // Unfortunately, ASMs nodes do not extend a common DOM node type with parent
- // pointers, so we have to have multiple methods which pass in each type
- // of node (class, method, field) to be checked.
-
- /**
- * Reports an issue applicable to a given method node.
- *
- * @param issue the issue to report
- * @param method the method scope the error applies to. The lint infrastructure
- * will check whether there are suppress annotations on this method (or its enclosing
- * class) and if so suppress the warning without involving the client.
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable MethodNode method,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (method != null && mDriver.isSuppressed(issue, method)) {
- return;
- }
- report(issue, location, message, data); // also checks the class node
- }
-
- /**
- * Reports an issue applicable to a given method node.
- *
- * @param issue the issue to report
- * @param field the scope the error applies to. The lint infrastructure
- * will check whether there are suppress annotations on this field (or its enclosing
- * class) and if so suppress the warning without involving the client.
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable FieldNode field,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (field != null && mDriver.isSuppressed(issue, field)) {
- return;
- }
- report(issue, location, message, data); // also checks the class node
- }
-
- /**
- * Finds the line number closest to the given node
- *
- * @param node the instruction node to get a line number for
- * @return the closest line number, or -1 if not known
- */
- public static int findLineNumber(@NonNull AbstractInsnNode node) {
- AbstractInsnNode curr = node;
-
- // First search backwards
- while (curr != null) {
- if (curr.getType() == AbstractInsnNode.LINE) {
- return ((LineNumberNode) curr).line;
- }
- curr = curr.getPrevious();
- }
-
- // Then search forwards
- curr = node;
- while (curr != null) {
- if (curr.getType() == AbstractInsnNode.LINE) {
- return ((LineNumberNode) curr).line;
- }
- curr = curr.getNext();
- }
-
- return -1;
- }
-
- /**
- * Finds the line number closest to the given method declaration
- *
- * @param node the method node to get a line number for
- * @return the closest line number, or -1 if not known
- */
- public static int findLineNumber(@NonNull MethodNode node) {
- if (node.instructions != null && node.instructions.size() > 0) {
- return findLineNumber(node.instructions.get(0));
- }
-
- return -1;
- }
-
- /**
- * Finds the line number closest to the given class declaration
- *
- * @param node the method node to get a line number for
- * @return the closest line number, or -1 if not known
- */
- public static int findLineNumber(@NonNull ClassNode node) {
- if (node.methods != null && !node.methods.isEmpty()) {
- MethodNode firstMethod = getFirstRealMethod(node);
- if (firstMethod != null) {
- return ClassContext.findLineNumber(firstMethod);
- }
- }
-
- return -1;
- }
-
- /**
- * Returns a location for the given {@link ClassNode}, where class node is
- * either the top level class, or an inner class, in the current context.
- *
- * @param classNode the class in the current context
- * @return a location pointing to the class declaration, or as close to it
- * as possible
- */
- @NonNull
- public Location getLocation(@NonNull ClassNode classNode) {
- // Attempt to find a proper location for this class. This is tricky
- // since classes do not have line number entries in the class file; we need
- // to find a method, look up the corresponding line number then search
- // around it for a suitable tag, such as the class name.
- String pattern;
- if (isAnonymousClass(classNode.name)) {
- pattern = classNode.superName;
- } else {
- pattern = classNode.name;
- }
- int index = pattern.lastIndexOf('$');
- if (index != -1) {
- pattern = pattern.substring(index + 1);
- }
- index = pattern.lastIndexOf('/');
- if (index != -1) {
- pattern = pattern.substring(index + 1);
- }
-
- return getLocationForLine(findLineNumber(classNode), pattern, null,
- SearchHints.create(BACKWARD).matchJavaSymbol());
- }
-
- @Nullable
- private static MethodNode getFirstRealMethod(@NonNull ClassNode classNode) {
- // Return the first method in the class for line number purposes. Skip <init>,
- // since it's typically not located near the real source of the method.
- if (classNode.methods != null) {
- @SuppressWarnings("rawtypes") // ASM API
- List methods = classNode.methods;
- for (Object m : methods) {
- MethodNode method = (MethodNode) m;
- if (method.name.charAt(0) != '<') {
- return method;
- }
- }
-
- if (classNode.methods.size() > 0) {
- return (MethodNode) classNode.methods.get(0);
- }
- }
-
- return null;
- }
-
- /**
- * Returns a location for the given {@link MethodNode}.
- *
- * @param methodNode the class in the current context
- * @param classNode the class containing the method
- * @return a location pointing to the class declaration, or as close to it
- * as possible
- */
- @NonNull
- public Location getLocation(@NonNull MethodNode methodNode,
- @NonNull ClassNode classNode) {
- // Attempt to find a proper location for this class. This is tricky
- // since classes do not have line number entries in the class file; we need
- // to find a method, look up the corresponding line number then search
- // around it for a suitable tag, such as the class name.
- String pattern;
- if (methodNode.name.equals(CONSTRUCTOR_NAME)) {
- if (isAnonymousClass(classNode.name)) {
- pattern = classNode.superName.substring(classNode.superName.lastIndexOf('/') + 1);
- } else {
- pattern = classNode.name.substring(classNode.name.lastIndexOf('$') + 1);
- }
- } else {
- pattern = methodNode.name;
- }
-
- return getLocationForLine(findLineNumber(methodNode), pattern, null,
- SearchHints.create(EOL_BACKWARD).matchJavaSymbol());
- }
-
- /**
- * Returns a location for the given {@link AbstractInsnNode}.
- *
- * @param instruction the instruction to look up the location for
- * @return a location pointing to the instruction, or as close to it
- * as possible
- */
- @NonNull
- public Location getLocation(@NonNull AbstractInsnNode instruction) {
- SearchHints hints = SearchHints.create(FORWARD).matchJavaSymbol();
- String pattern = null;
- if (instruction instanceof MethodInsnNode) {
- MethodInsnNode call = (MethodInsnNode) instruction;
- if (call.name.equals(CONSTRUCTOR_NAME)) {
- pattern = call.owner;
- hints = hints.matchConstructor();
- } else {
- pattern = call.name;
- }
- int index = pattern.lastIndexOf('$');
- if (index != -1) {
- pattern = pattern.substring(index + 1);
- }
- index = pattern.lastIndexOf('/');
- if (index != -1) {
- pattern = pattern.substring(index + 1);
- }
- }
-
- int line = findLineNumber(instruction);
- return getLocationForLine(line, pattern, null, hints);
- }
-
- private static boolean isAnonymousClass(@NonNull String fqcn) {
- int lastIndex = fqcn.lastIndexOf('$');
- if (lastIndex != -1 && lastIndex < fqcn.length() - 1) {
- if (Character.isDigit(fqcn.charAt(lastIndex + 1))) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Converts from a VM owner name (such as foo/bar/Foo$Baz) to a
- * fully qualified class name (such as foo.bar.Foo.Baz).
- *
- * @param owner the owner name to convert
- * @return the corresponding fully qualified class name
- */
- @NonNull
- public static String getFqcn(@NonNull String owner) {
- return owner.replace('/', '.').replace('$','.');
- }
-
- /**
- * Computes a user-readable type signature from the given class owner, name
- * and description. For example, for owner="foo/bar/Foo$Baz", name="foo",
- * description="(I)V", it returns "void foo.bar.Foo.Bar#foo(int)".
- *
- * @param owner the class name
- * @param name the method name
- * @param desc the method description
- * @return a user-readable string
- */
- public static String createSignature(String owner, String name, String desc) {
- StringBuilder sb = new StringBuilder();
-
- if (desc != null) {
- Type returnType = Type.getReturnType(desc);
- sb.append(getTypeString(returnType));
- sb.append(' ');
- }
-
- if (owner != null) {
- sb.append(getFqcn(owner));
- }
- if (name != null) {
- sb.append('#');
- sb.append(name);
- if (desc != null) {
- Type[] argumentTypes = Type.getArgumentTypes(desc);
- if (argumentTypes != null && argumentTypes.length > 0) {
- sb.append('(');
- boolean first = true;
- for (Type type : argumentTypes) {
- if (first) {
- first = false;
- } else {
- sb.append(", ");
- }
- sb.append(getTypeString(type));
- }
- sb.append(')');
- }
- }
- }
-
- return sb.toString();
- }
-
- private static String getTypeString(Type type) {
- String s = type.getClassName();
- if (s.startsWith("java.lang.")) { //$NON-NLS-1$
- s = s.substring("java.lang.".length()); //$NON-NLS-1$
- }
-
- return s;
- }
-
- /**
- * Computes the internal class name of the given fully qualified class name.
- * For example, it converts foo.bar.Foo.Bar into foo/bar/Foo$Bar
- *
- * @param fqcn the fully qualified class name
- * @return the internal class name
- */
- @NonNull
- public static String getInternalName(@NonNull String fqcn) {
- String[] parts = fqcn.split("\\."); //$NON-NLS-1$
- StringBuilder sb = new StringBuilder();
- String prev = null;
- for (String part : parts) {
- if (prev != null) {
- if (Character.isUpperCase(prev.charAt(0))) {
- sb.append('$');
- } else {
- sb.append('/');
- }
- }
- sb.append(part);
- prev = part;
- }
-
- return sb.toString();
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Context.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Context.java
deleted file mode 100644
index 9ddd10a..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Context.java
+++ /dev/null
@@ -1,331 +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 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.LintDriver;
-import com.android.tools.lint.client.api.SdkInfo;
-import com.google.common.annotations.Beta;
-
-import java.io.File;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-/**
- * Context passed to the detectors during an analysis run. It provides
- * information about the file being analyzed, it allows shared properties (so
- * the detectors can share results), etc.
- * <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 Context {
- /**
- * The file being checked. Note that this may not always be to a concrete
- * file. For example, in the {@link Detector#beforeCheckProject(Context)}
- * method, the context file is the directory of the project.
- */
- public final File file;
-
- /** The driver running through the checks */
- protected final LintDriver mDriver;
-
- /** The project containing the file being checked */
- @NonNull
- private final Project mProject;
-
- /**
- * The "main" project. For normal projects, this is the same as {@link #mProject},
- * but for library projects, it's the root project that includes (possibly indirectly)
- * the various library projects and their library projects.
- * <p>
- * Note that this is a property on the {@link Context}, not the
- * {@link Project}, since a library project can be included from multiple
- * different top level projects, so there isn't <b>one</b> main project,
- * just one per main project being analyzed with its library projects.
- */
- private final Project mMainProject;
-
- /** The current configuration controlling which checks are enabled etc */
- private final Configuration mConfiguration;
-
- /** The contents of the file */
- private String mContents;
-
- /**
- * Whether the lint job has been canceled.
- * <p>
- * Slow-running detectors should check this flag via
- * {@link AtomicBoolean#get()} and abort if canceled
- */
- @NonNull
- public final AtomicBoolean canceled = new AtomicBoolean();
-
- /** Map of properties to share results between detectors */
- private Map<String, Object> mProperties;
-
- /**
- * Construct a new {@link Context}
- *
- * @param driver the driver running through the checks
- * @param project the project containing the file being checked
- * @param main the main project if this project is a library project, or
- * null if this is not a library project. The main project is
- * the root project of all library projects, not necessarily the
- * directly including project.
- * @param file the file being checked
- */
- public Context(
- @NonNull LintDriver driver,
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File file) {
- this.file = file;
-
- mDriver = driver;
- mProject = project;
- mMainProject = main;
- mConfiguration = project.getConfiguration();
- }
-
- /**
- * Returns the scope for the lint job
- *
- * @return the scope, never null
- */
- @NonNull
- public EnumSet<Scope> getScope() {
- return mDriver.getScope();
- }
-
- /**
- * Returns the configuration for this project.
- *
- * @return the configuration, never null
- */
- @NonNull
- public Configuration getConfiguration() {
- return mConfiguration;
- }
-
- /**
- * Returns the project containing the file being checked
- *
- * @return the project, never null
- */
- @NonNull
- public Project getProject() {
- return mProject;
- }
-
- /**
- * Returns the main project if this project is a library project, or self
- * if this is not a library project. The main project is the root project
- * of all library projects, not necessarily the directly including project.
- *
- * @return the main project, never null
- */
- @NonNull
- public Project getMainProject() {
- return mMainProject != null ? mMainProject : mProject;
- }
-
- /**
- * Returns the lint client requesting the lint check
- *
- * @return the client, never null
- */
- @NonNull
- public LintClient getClient() {
- return mDriver.getClient();
- }
-
- /**
- * Returns the driver running through the lint checks
- *
- * @return the driver
- */
- @NonNull
- public LintDriver getDriver() {
- return mDriver;
- }
-
- /**
- * Returns the contents of the file. This may not be the contents of the
- * file on disk, since it delegates to the {@link LintClient}, which in turn
- * may decide to return the current edited contents of the file open in an
- * editor.
- *
- * @return the contents of the given file, or null if an error occurs.
- */
- @Nullable
- public String getContents() {
- if (mContents == null) {
- mContents = mDriver.getClient().readFile(file);
- }
-
- return mContents;
- }
-
- /**
- * Returns the value of the given named property, or null.
- *
- * @param name the name of the property
- * @return the corresponding value, or null
- */
- @Nullable
- public Object getProperty(String name) {
- if (mProperties == null) {
- return null;
- }
-
- return mProperties.get(name);
- }
-
- /**
- * Sets the value of the given named property.
- *
- * @param name the name of the property
- * @param value the corresponding value
- */
- public void setProperty(@NonNull String name, @Nullable Object value) {
- if (value == null) {
- if (mProperties != null) {
- mProperties.remove(name);
- }
- } else {
- if (mProperties == null) {
- mProperties = new HashMap<String, Object>();
- }
- mProperties.put(name, value);
- }
- }
-
- /**
- * Gets the SDK info for the current project.
- *
- * @return the SDK info for the current project, never null
- */
- @NonNull
- public SdkInfo getSdkInfo() {
- return mProject.getSdkInfo();
- }
-
- // ---- Convenience wrappers ---- (makes the detector code a bit leaner)
-
- /**
- * Returns false if the given issue has been disabled. Convenience wrapper
- * around {@link Configuration#getSeverity(Issue)}.
- *
- * @param issue the issue to check
- * @return false if the issue has been disabled
- */
- public boolean isEnabled(@NonNull Issue issue) {
- return mConfiguration.isEnabled(issue);
- }
-
- /**
- * Reports an issue. Convenience wrapper around {@link LintClient#report}
- *
- * @param issue the issue to report
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- Configuration configuration = mConfiguration;
-
- // If this error was computed for a context where the context corresponds to
- // a project instead of a file, the actual error may be in a different project (e.g.
- // a library project), so adjust the configuration as necessary.
- if (location != null && location.getFile() != null) {
- Project project = mDriver.findProjectFor(location.getFile());
- if (project != null) {
- configuration = project.getConfiguration();
- }
- }
-
- // If an error occurs in a library project, but you've disabled that check in the
- // main project, disable it in the library project too. (In some cases you don't
- // control the lint.xml of a library project, and besides, if you're not interested in
- // a check for your main project you probably don't care about it in the library either.)
- if (configuration != mConfiguration
- && mConfiguration.getSeverity(issue) == Severity.IGNORE) {
- return;
- }
-
- Severity severity = configuration.getSeverity(issue);
- if (severity == Severity.IGNORE) {
- return;
- }
-
- mDriver.getClient().report(this, issue, severity, location, message, data);
- }
-
- /**
- * Send an exception to the log. Convenience wrapper around {@link LintClient#log}.
- *
- * @param exception the exception, possibly null
- * @param format the error message using {@link String#format} syntax, possibly null
- * @param args any arguments for the format string
- */
- public void log(
- @Nullable Throwable exception,
- @Nullable String format,
- @Nullable Object... args) {
- mDriver.getClient().log(exception, format, args);
- }
-
- /**
- * Returns the current phase number. The first pass is numbered 1. Only one pass
- * will be performed, unless a {@link Detector} calls {@link #requestRepeat}.
- *
- * @return the current phase, usually 1
- */
- public int getPhase() {
- return mDriver.getPhase();
- }
-
- /**
- * Requests another pass through the data for the given detector. This is
- * typically done when a detector needs to do more expensive computation,
- * but it only wants to do this once it <b>knows</b> that an error is
- * present, or once it knows more specifically what to check for.
- *
- * @param detector the detector that should be included in the next pass.
- * Note that the lint runner may refuse to run more than a couple
- * of runs.
- * @param scope the scope to be revisited. This must be a subset of the
- * current scope ({@link #getScope()}, and it is just a performance hint;
- * in particular, the detector should be prepared to be called on other
- * scopes as well (since they may have been requested by other detectors).
- * You can pall null to indicate "all".
- */
- public void requestRepeat(@NonNull Detector detector, @Nullable EnumSet<Scope> scope) {
- mDriver.requestRepeat(detector, scope);
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/DefaultPosition.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/DefaultPosition.java
deleted file mode 100644
index 72c8ee7..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/DefaultPosition.java
+++ /dev/null
@@ -1,68 +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 com.google.common.annotations.Beta;
-
-/**
- * A simple offset-based position *
- * <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 DefaultPosition extends Position {
- /** The line number (0-based where the first line is line 0) */
- private final int mLine;
-
- /**
- * The column number (where the first character on the line is 0), or -1 if
- * unknown
- */
- private final int mColumn;
-
- /** The character offset */
- private final int mOffset;
-
- /**
- * Creates a new {@link DefaultPosition}
- *
- * @param line the 0-based line number, or -1 if unknown
- * @param column the 0-based column number, or -1 if unknown
- * @param offset the offset, or -1 if unknown
- */
- public DefaultPosition(int line, int column, int offset) {
- mLine = line;
- mColumn = column;
- mOffset = offset;
- }
-
- @Override
- public int getLine() {
- return mLine;
- }
-
- @Override
- public int getOffset() {
- return mOffset;
- }
-
- @Override
- public int getColumn() {
- return mColumn;
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Detector.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Detector.java
deleted file mode 100644
index e2c5907..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Detector.java
+++ /dev/null
@@ -1,581 +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 com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.LintDriver;
-import com.google.common.annotations.Beta;
-
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodInsnNode;
-import org.objectweb.asm.tree.MethodNode;
-import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import lombok.ast.AstVisitor;
-import lombok.ast.MethodInvocation;
-
-/**
- * A detector is able to find a particular problem. It might also be thought of as enforcing
- * a rule, but "rule" is a bit overloaded in ADT terminology since ViewRules are used in
- * the Rules API to allow views to specify designtime behavior in the graphical layout editor.
- * <p>
- * Each detector provides information about the issues it can find, such as an explanation
- * of how to fix the issue, the priority, the category, etc. It also has an id which is
- * used to persistently identify a particular type of error.
- * <p>
- * Detectors will be called in a predefined order:
- * <ol>
- * <li> Manifest file
- * <li> Resource files, in alphabetical order by resource type
- * (therefore, "layout" is checked before "values", "values-de" is checked before
- * "values-en" but after "values", and so on.
- * <li> Java sources
- * <li> Java classes
- * <li> Proguard files
- * </ol>
- * If a detector needs information when processing a file type that comes from a type of
- * file later in the order above, they can request a second phase; see
- * {@link LintDriver#requestRepeat}.
- * <p>
- * NOTE: Detectors might be constructed just once and shared between lint runs, so
- * any per-detector state should be initialized and reset via the before/after
- * methods.
- * <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 abstract class Detector {
- /** Specialized interface for detectors that scan Java source file parse trees */
- public interface JavaScanner {
- /**
- * Create a parse tree visitor to process the parse tree. All
- * {@link JavaScanner} detectors must provide a visitor, unless they
- * either return true from {@link #appliesToResourceRefs()} or return
- * non null from {@link #getApplicableMethodNames()}.
- * <p>
- * If you return specific AST node types from
- * {@link #getApplicableNodeTypes()}, then the visitor will <b>only</b>
- * be called for the specific requested node types. This is more
- * efficient, since it allows many detectors that apply to only a small
- * part of the AST (such as method call nodes) to share iteration of the
- * majority of the parse tree.
- * <p>
- * If you return null from {@link #getApplicableNodeTypes()}, then your
- * visitor will be called from the top and all node types visited.
- * <p>
- * Note that a new visitor is created for each separate compilation
- * unit, so you can store per file state in the visitor.
- *
- * @param context the {@link Context} for the file being analyzed
- * @return a visitor, or null.
- */
- @Nullable
- AstVisitor createJavaVisitor(@NonNull JavaContext context);
-
- /**
- * Return the types of AST nodes that the visitor returned from
- * {@link #createJavaVisitor(JavaContext)} should visit. See the
- * documentation for {@link #createJavaVisitor(JavaContext)} for details
- * on how the shared visitor is used.
- * <p>
- * If you return null from this method, then the visitor will process
- * the full tree instead.
- * <p>
- * Note that for the shared visitor, the return codes from the visit
- * methods are ignored: returning true will <b>not</b> prune iteration
- * of the subtree, since there may be other node types interested in the
- * children. If you need to ensure that your visitor only processes a
- * part of the tree, use a full visitor instead. See the
- * OverdrawDetector implementation for an example of this.
- *
- * @return the list of applicable node types (AST node classes), or null
- */
- @Nullable
- List<Class<? extends lombok.ast.Node>> getApplicableNodeTypes();
-
- /**
- * Return the list of method names this detector is interested in, or
- * null. If this method returns non-null, then any AST nodes that match
- * a method call in the list will be passed to the
- * {@link #visitMethod(JavaContext, AstVisitor, MethodInvocation)}
- * method for processing. The visitor created by
- * {@link #createJavaVisitor(JavaContext)} is also passed to that
- * method, although it can be null.
- * <p>
- * This makes it easy to write detectors that focus on some fixed calls.
- * For example, the StringFormatDetector uses this mechanism to look for
- * "format" calls, and when found it looks around (using the AST's
- * {@link lombok.ast.Node#getParent()} method) to see if it's called on
- * a String class instance, and if so do its normal processing. Note
- * that since it doesn't need to do any other AST processing, that
- * detector does not actually supply a visitor.
- *
- * @return a set of applicable method names, or null.
- */
- @Nullable
- List<String> getApplicableMethodNames();
-
- /**
- * Method invoked for any method calls found that matches any names
- * returned by {@link #getApplicableMethodNames()}. This also passes
- * back the visitor that was created by
- * {@link #createJavaVisitor(JavaContext)}, but a visitor is not
- * required. It is intended for detectors that need to do additional AST
- * processing, but also want the convenience of not having to look for
- * method names on their own.
- *
- * @param context the context of the lint request
- * @param visitor the visitor created from
- * {@link #createJavaVisitor(JavaContext)}, or null
- * @param node the {@link MethodInvocation} node for the invoked method
- */
- void visitMethod(
- @NonNull JavaContext context,
- @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node);
-
- /**
- * Returns whether this detector cares about Android resource references
- * (such as {@code R.layout.main} or {@code R.string.app_name}). If it
- * does, then the visitor will look for these patterns, and if found, it
- * will invoke {@link #visitResourceReference} passing the resource type
- * and resource name. It also passes the visitor, if any, that was
- * created by {@link #createJavaVisitor(JavaContext)}, such that a
- * detector can do more than just look for resources.
- *
- * @return true if this detector wants to be notified of R resource
- * identifiers found in the code.
- */
- boolean appliesToResourceRefs();
-
- /**
- * Called for any resource references (such as {@code R.layout.main}
- * found in Java code, provided this detector returned {@code true} from
- * {@link #appliesToResourceRefs()}.
- *
- * @param context the lint scanning context
- * @param visitor the visitor created from
- * {@link #createJavaVisitor(JavaContext)}, or null
- * @param node the variable reference for the resource
- * @param type the resource type, such as "layout" or "string"
- * @param name the resource name, such as "main" from
- * {@code R.layout.main}
- * @param isFramework whether the resource is a framework resource
- * (android.R) or a local project resource (R)
- */
- void visitResourceReference(
- @NonNull JavaContext context,
- @Nullable AstVisitor visitor,
- @NonNull lombok.ast.Node node,
- @NonNull String type,
- @NonNull String name,
- boolean isFramework);
- }
-
- /** Specialized interface for detectors that scan Java class files */
- public interface ClassScanner {
- /**
- * Checks the given class' bytecode for issues.
- *
- * @param context the context of the lint check, pointing to for example
- * the file
- * @param classNode the root class node
- */
- void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode);
-
- /**
- * Returns the list of node types (corresponding to the constants in the
- * {@link AbstractInsnNode} class) that this scanner applies to. The
- * {@link #checkInstruction(ClassContext, ClassNode, MethodNode, AbstractInsnNode)}
- * method will be called for each match.
- *
- * @return an array containing all the node types this detector should be
- * called for, or null if none.
- */
- @Nullable
- int[] getApplicableAsmNodeTypes();
-
- /**
- * Process a given instruction node, and register lint issues if
- * applicable.
- *
- * @param context the context of the lint check, pointing to for example
- * the file
- * @param classNode the root class node
- * @param method the method node containing the call
- * @param instruction the actual instruction
- */
- void checkInstruction(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull AbstractInsnNode instruction);
-
- /**
- * Return the list of method call names (in VM format, e.g. "<init>" for
- * constructors, etc) for method calls this detector is interested in,
- * or null. T his will be used to dispatch calls to
- * {@link #checkCall(ClassContext, ClassNode, MethodNode, MethodInsnNode)}
- * for only the method calls in owners that the detector is interested
- * in.
- * <p>
- * <b>NOTE</b>: If you return non null from this method, then <b>only</b>
- * {@link #checkCall(ClassContext, ClassNode, MethodNode, MethodInsnNode)}
- * will be called if a suitable method is found;
- * {@link #checkClass(ClassContext, ClassNode)} will not be called under
- * any circumstances.
- * <p>
- * This makes it easy to write detectors that focus on some fixed calls,
- * and allows lint to make a single pass over the bytecode over a class,
- * and efficiently dispatch method calls to any detectors that are
- * interested in it. Without this, each new lint check interested in a
- * single method, would be doing a complete pass through all the
- * bytecode instructions of the class via the
- * {@link #checkClass(ClassContext, ClassNode)} method, which would make
- * each newly added lint check make lint slower. Now a single dispatch
- * map is used instead, and for each encountered call in the single
- * dispatch, it looks up in the map which if any detectors are
- * interested in the given call name, and dispatches to each one in
- * turn.
- *
- * @return a list of applicable method names, or null.
- */
- @Nullable
- List<String> getApplicableCallNames();
-
- /**
- * Just like {@link Detector#getApplicableCallNames()}, but for the owner
- * field instead. The
- * {@link #checkCall(ClassContext, ClassNode, MethodNode, MethodInsnNode)}
- * method will be called for all {@link MethodInsnNode} instances where the
- * owner field matches any of the members returned in this node.
- * <p>
- * Note that if your detector provides both a name and an owner, the
- * method will be called for any nodes matching either the name <b>or</b>
- * the owner, not only where they match <b>both</b>. Note also that it will
- * be called twice - once for the name match, and (at least once) for the owner
- * match.
- *
- * @return a list of applicable owner names, or null.
- */
- @Nullable
- List<String> getApplicableCallOwners();
-
- /**
- * Process a given method call node, and register lint issues if
- * applicable. This is similar to the
- * {@link #checkInstruction(ClassContext, ClassNode, MethodNode, AbstractInsnNode)}
- * method, but has the additional advantage that it is only called for known
- * method names or method owners, according to
- * {@link #getApplicableCallNames()} and {@link #getApplicableCallOwners()}.
- *
- * @param context the context of the lint check, pointing to for example
- * the file
- * @param classNode the root class node
- * @param method the method node containing the call
- * @param call the actual method call node
- */
- void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call);
- }
-
- /** Specialized interface for detectors that scan XML files */
- public interface XmlScanner {
- /**
- * Visit the given document. The detector is responsible for its own iteration
- * through the document.
- * @param context information about the document being analyzed
- * @param document the document to examine
- */
- void visitDocument(@NonNull XmlContext context, @NonNull Document document);
-
- /**
- * Visit the given element.
- * @param context information about the document being analyzed
- * @param element the element to examine
- */
- void visitElement(@NonNull XmlContext context, @NonNull Element element);
-
- /**
- * Visit the given element after its children have been analyzed.
- * @param context information about the document being analyzed
- * @param element the element to examine
- */
- void visitElementAfter(@NonNull XmlContext context, @NonNull Element element);
-
- /**
- * Visit the given attribute.
- * @param context information about the document being analyzed
- * @param attribute the attribute node to examine
- */
- void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute);
-
- /**
- * Returns the list of elements that this detector wants to analyze. If non
- * null, this detector will be called (specifically, the
- * {@link #visitElement} method) for each matching element in the document.
- * <p>
- * If this method returns null, and {@link #getApplicableAttributes()} also returns
- * null, then the {@link #visitDocument} method will be called instead.
- *
- * @return a collection of elements, or null, or the special
- * {@link XmlScanner#ALL} marker to indicate that every single
- * element should be analyzed.
- */
- @Nullable
- Collection<String> getApplicableElements();
-
- /**
- * Returns the list of attributes that this detector wants to analyze. If non
- * null, this detector will be called (specifically, the
- * {@link #visitAttribute} method) for each matching attribute in the document.
- * <p>
- * If this method returns null, and {@link #getApplicableElements()} also returns
- * null, then the {@link #visitDocument} method will be called instead.
- *
- * @return a collection of attributes, or null, or the special
- * {@link XmlScanner#ALL} marker to indicate that every single
- * attribute should be analyzed.
- */
- @Nullable
- Collection<String> getApplicableAttributes();
-
- /**
- * Special marker collection returned by {@link #getApplicableElements()} or
- * {@link #getApplicableAttributes()} to indicate that the check should be
- * invoked on all elements or all attributes
- */
- @NonNull
- public static final List<String> ALL = new ArrayList<String>(0); // NOT Collections.EMPTY!
- // We want to distinguish this from just an *empty* list returned by the caller!
- }
-
- /**
- * Runs the detector. This method will not be called for certain specialized
- * detectors, such as {@link XmlScanner} and {@link JavaScanner}, where
- * there are specialized analysis methods instead such as
- * {@link XmlScanner#visitElement(XmlContext, Element)}.
- *
- * @param context the context describing the work to be done
- */
- public void run(@NonNull Context context) {
- }
-
- /**
- * Returns true if this detector applies to the given file
- *
- * @param context the context to check
- * @param file the file in the context to check
- * @return true if this detector applies to the given context and file
- */
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return false;
- }
-
- /**
- * Analysis is about to begin, perform any setup steps.
- *
- * @param context the context for the check referencing the project, lint
- * client, etc
- */
- public void beforeCheckProject(@NonNull Context context) {
- }
-
- /**
- * Analysis has just been finished for the whole project, perform any
- * cleanup or report issues that require project-wide analysis.
- *
- * @param context the context for the check referencing the project, lint
- * client, etc
- */
- public void afterCheckProject(@NonNull Context context) {
- }
-
- /**
- * Analysis is about to begin for the given library project, perform any setup steps.
- *
- * @param context the context for the check referencing the project, lint
- * client, etc
- */
- public void beforeCheckLibraryProject(@NonNull Context context) {
- }
-
- /**
- * Analysis has just been finished for the given library project, perform any
- * cleanup or report issues that require library-project-wide analysis.
- *
- * @param context the context for the check referencing the project, lint
- * client, etc
- */
- public void afterCheckLibraryProject(@NonNull Context context) {
- }
-
- /**
- * Analysis is about to be performed on a specific file, perform any setup
- * steps.
- * <p>
- * Note: When this method is called at the beginning of checking an XML
- * file, the context is guaranteed to be an instance of {@link XmlContext},
- * and similarly for a Java source file, the context will be a
- * {@link JavaContext} and so on.
- *
- * @param context the context for the check referencing the file to be
- * checked, the project, etc.
- */
- public void beforeCheckFile(@NonNull Context context) {
- }
-
- /**
- * Analysis has just been finished for a specific file, perform any cleanup
- * or report issues found
- * <p>
- * Note: When this method is called at the end of checking an XML
- * file, the context is guaranteed to be an instance of {@link XmlContext},
- * and similarly for a Java source file, the context will be a
- * {@link JavaContext} and so on.
- *
- * @param context the context for the check referencing the file to be
- * checked, the project, etc.
- */
- public void afterCheckFile(@NonNull Context context) {
- }
-
- /**
- * Returns the expected speed of this detector
- *
- * @return the expected speed of this detector
- */
- @NonNull
- public Speed getSpeed() {
- return Speed.NORMAL;
- }
-
- // ---- Dummy implementations to make implementing XmlScanner easier: ----
-
- @SuppressWarnings("javadoc")
- public void visitDocument(@NonNull XmlContext context, @NonNull Document document) {
- // This method must be overridden if your detector does
- // not return something from getApplicableElements or
- // getApplicableATtributes
- assert false;
- }
-
- @SuppressWarnings("javadoc")
- public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
- // This method must be overridden if your detector returns
- // tag names from getApplicableElements
- assert false;
- }
-
- @SuppressWarnings("javadoc")
- public void visitElementAfter(@NonNull XmlContext context, @NonNull Element element) {
- }
-
- @SuppressWarnings("javadoc")
- public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
- // This method must be overridden if your detector returns
- // attribute names from getApplicableAttributes
- assert false;
- }
-
- @SuppressWarnings("javadoc")
- @Nullable
- public Collection<String> getApplicableElements() {
- return null;
- }
-
- @Nullable
- @SuppressWarnings("javadoc")
- public Collection<String> getApplicableAttributes() {
- return null;
- }
-
- // ---- Dummy implementations to make implementing JavaScanner easier: ----
-
- @Nullable @SuppressWarnings("javadoc")
- public List<String> getApplicableMethodNames() {
- return null;
- }
-
- @Nullable @SuppressWarnings("javadoc")
- public AstVisitor createJavaVisitor(@NonNull JavaContext context) {
- return null;
- }
-
- @Nullable @SuppressWarnings("javadoc")
- public List<Class<? extends lombok.ast.Node>> getApplicableNodeTypes() {
- return null;
- }
-
- @SuppressWarnings("javadoc")
- public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull MethodInvocation node) {
- }
-
- @SuppressWarnings("javadoc")
- public boolean appliesToResourceRefs() {
- return false;
- }
-
- @SuppressWarnings("javadoc")
- public void visitResourceReference(@NonNull JavaContext context, @Nullable AstVisitor visitor,
- @NonNull lombok.ast.Node node, @NonNull String type, @NonNull String name,
- boolean isFramework) {
- }
-
- // ---- Dummy implementations to make implementing a ClassScanner easier: ----
-
- @SuppressWarnings("javadoc")
- public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
- }
-
- @SuppressWarnings("javadoc")
- @Nullable
- public List<String> getApplicableCallNames() {
- return null;
- }
-
- @SuppressWarnings("javadoc")
- @Nullable
- public List<String> getApplicableCallOwners() {
- return null;
- }
-
- @SuppressWarnings("javadoc")
- public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull MethodInsnNode call) {
- }
-
- @SuppressWarnings("javadoc")
- @Nullable
- public int[] getApplicableAsmNodeTypes() {
- return null;
- }
-
- @SuppressWarnings("javadoc")
- public void checkInstruction(@NonNull ClassContext context, @NonNull ClassNode classNode,
- @NonNull MethodNode method, @NonNull AbstractInsnNode instruction) {
- }
-
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Issue.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Issue.java
deleted file mode 100644
index 70d3cf7..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Issue.java
+++ /dev/null
@@ -1,552 +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 com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.Configuration;
-import com.android.tools.lint.client.api.IssueRegistry;
-import com.google.common.annotations.Beta;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.EnumSet;
-import java.util.List;
-
-
-/**
- * An issue is a potential bug in an Android application. An issue is discovered
- * by a {@link Detector}, and has an associated {@link Severity}.
- * <p>
- * Issues and detectors are separate classes because a detector can discover
- * multiple different issues as it's analyzing code, and we want to be able to
- * different severities for different issues, the ability to suppress one but
- * not other issues from the same detector, and so on.
- * <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 final class Issue implements Comparable<Issue> {
- private static final String HTTP_PREFIX = "http://"; //$NON-NLS-1$
-
- private final String mId;
- private final String mDescription;
- private final String mExplanation;
- private final Category mCategory;
- private final int mPriority;
- private final Severity mSeverity;
- private String mMoreInfoUrl;
- private boolean mEnabledByDefault = true;
- private final EnumSet<Scope> mScope;
- private List<EnumSet<Scope>> mAnalysisScopes;
- private final Class<? extends Detector> mClass;
-
- // Use factory methods
- private Issue(
- @NonNull String id,
- @NonNull String description,
- @NonNull String explanation,
- @NonNull Category category,
- int priority,
- @NonNull Severity severity,
- @NonNull Class<? extends Detector> detectorClass,
- @NonNull EnumSet<Scope> scope) {
- super();
- mId = id;
- mDescription = description;
- mExplanation = explanation;
- mCategory = category;
- mPriority = priority;
- mSeverity = severity;
- mClass = detectorClass;
- mScope = scope;
- }
-
- /**
- * Creates a new issue
- *
- * @param id the fixed id of the issue
- * @param description the quick summary of the issue (one line)
- * @param explanation a full explanation of the issue, with suggestions for
- * how to fix it
- * @param category the associated category, if any
- * @param priority the priority, a number from 1 to 10 with 10 being most
- * important/severe
- * @param severity the default severity of the issue
- * @param detectorClass the class of the detector to find this issue
- * @param scope the scope of files required to analyze this issue
- * @return a new {@link Issue}
- */
- @NonNull
- public static Issue create(
- @NonNull String id,
- @NonNull String description,
- @NonNull String explanation,
- @NonNull Category category,
- int priority,
- @NonNull Severity severity,
- @NonNull Class<? extends Detector> detectorClass,
- @NonNull EnumSet<Scope> scope) {
- return new Issue(id, description, explanation, category, priority, severity,
- detectorClass, scope);
- }
-
- /**
- * Returns the unique id of this issue. These should not change over time
- * since they are used to persist the names of issues suppressed by the user
- * etc. It is typically a single camel-cased word.
- *
- * @return the associated fixed id, never null and always unique
- */
- @NonNull
- public String getId() {
- return mId;
- }
-
- /**
- * Briefly (one line) describes the kinds of checks performed by this rule
- *
- * @return a quick summary of the issue, never null
- */
- @NonNull
- public String getDescription() {
- return mDescription;
- }
-
- /**
- * Describes the error found by this rule, e.g.
- * "Buttons must define contentDescriptions". Preferably the explanation
- * should also contain a description of how the problem should be solved.
- * Additional info can be provided via {@link #getMoreInfo()}.
- * <p>
- * Note that the text may contain some simple markup, such as *'s around sentences
- * for bold text, and back quotes (`) for code fragments. You can obtain
- * the text without this markup by calling {@link #getExplanationAsSimpleText()},
- * and you can obtain the text as annotated HTML by calling
- * {@link #getExplanationAsHtml()}.
- *
- * @return an explanation of the issue, never null.
- */
- @NonNull
- public String getExplanation() {
- return mExplanation;
- }
-
- /**
- * Like {@link #getExplanation()}, but returns the text as properly escaped
- * and marked up HTML, where http URLs are linked, where words with asterisks
- * such as *this* are shown in bold, etc.
- *
- * @return the explanation of the issue, never null
- */
- @NonNull
- public String getExplanationAsHtml() {
- return convertMarkup(mExplanation, true /* html */);
- }
-
- /**
- * Like {@link #getExplanation()}, but returns the text as properly escaped
- * and marked up HTML, where http URLs are linked, where words with asterisks
- * such as *this* are shown in bold, etc.
- *
- * @return the explanation of the issue, never null
- */
- @NonNull
- public String getExplanationAsSimpleText() {
- return convertMarkup(mExplanation, false /* not html = text */);
- }
-
- /**
- * The primary category of the issue
- *
- * @return the primary category of the issue, never null
- */
- @NonNull
- public Category getCategory() {
- return mCategory;
- }
-
- /**
- * Returns a priority, in the range 1-10, with 10 being the most severe and
- * 1 the least
- *
- * @return a priority from 1 to 10
- */
- public int getPriority() {
- return mPriority;
- }
-
- /**
- * Returns the default severity of the issues found by this detector (some
- * tools may allow the user to specify custom severities for detectors).
- * <p>
- * Note that even though the normal way for an issue to be disabled is for
- * the {@link Configuration} to return {@link Severity#IGNORE}, there is a
- * {@link #isEnabledByDefault()} method which can be used to turn off issues
- * by default. This is done rather than just having the severity as the only
- * attribute on the issue such that an issue can be configured with an
- * appropriate severity (such as {@link Severity#ERROR}) even when issues
- * are disabled by default for example because they are experimental or not
- * yet stable.
- *
- * @return the severity of the issues found by this detector
- */
- @NonNull
- public Severity getDefaultSeverity() {
- return mSeverity;
- }
-
- /**
- * Returns a link (a URL string) to more information, or null
- *
- * @return a link to more information, or null
- */
- @Nullable
- public String getMoreInfo() {
- return mMoreInfoUrl;
- }
-
- /**
- * Returns whether this issue should be enabled by default, unless the user
- * has explicitly disabled it.
- *
- * @return true if this issue should be enabled by default
- */
- public boolean isEnabledByDefault() {
- return mEnabledByDefault;
- }
-
- /**
- * Returns the scope required to analyze the code to detect this issue.
- * This is determined by the detectors which reports the issue.
- *
- * @return the required scope
- */
- @NonNull
- public EnumSet<Scope> getScope() {
- return mScope;
- }
-
- /**
- * Sorts the detectors alphabetically by id. This is intended to make it
- * convenient to store settings for detectors in a fixed order. It is not
- * intended as the order to be shown to the user; for that, a tool embedding
- * lint might consider the priorities, categories, severities etc of the
- * various detectors.
- *
- * @param other the {@link Issue} to compare this issue to
- */
- @Override
- public int compareTo(Issue other) {
- return getId().compareTo(other.getId());
- }
-
- /**
- * Sets a more info URL string
- *
- * @param moreInfoUrl url string
- * @return this, for constructor chaining
- */
- @NonNull
- public Issue setMoreInfo(@NonNull String moreInfoUrl) {
- mMoreInfoUrl = moreInfoUrl;
- return this;
- }
-
- /**
- * Sets whether this issue is enabled by default.
- *
- * @param enabledByDefault whether the issue should be enabled by default
- * @return this, for constructor chaining
- */
- @NonNull
- public Issue setEnabledByDefault(boolean enabledByDefault) {
- mEnabledByDefault = enabledByDefault;
- return this;
- }
-
- /**
- * Returns the sets of scopes required to analyze this issue, or null if all
- * scopes named by {@link Issue#getScope()} are necessary. Note that only
- * <b>one</b> match out of this collection is required, not all, and that
- * the scope set returned by {@link #getScope()} does not have to be returned
- * by this method, but is always implied to be included.
- * <p>
- * The scopes returned by {@link Issue#getScope()} list all the various
- * scopes that are <b>affected</b> by this issue, meaning the detector
- * should consider it. Frequently, the detector must analyze all these
- * scopes in order to properly decide whether an issue is found. For
- * example, the unused resource detector needs to consider both the XML
- * resource files and the Java source files in order to decide if a resource
- * is unused. If it analyzes just the Java files for example, it might
- * incorrectly conclude that a resource is unused because it did not
- * discover a resource reference in an XML file.
- * <p>
- * However, there are other issues where the issue can occur in a variety of
- * files, but the detector can consider each in isolation. For example, the
- * API checker is affected by both XML files and Java class files (detecting
- * both layout constructor references in XML layout files as well as code
- * references in .class files). It doesn't have to analyze both; it is
- * capable of incrementally analyzing just an XML file, or just a class
- * file, without considering the other.
- * <p>
- * The required scope list provides a list of scope sets that can be used to
- * analyze this issue. For each scope set, all the scopes must be matched by
- * the incremental analysis, but any one of the scope sets can be analyzed
- * in isolation.
- * <p>
- * The required scope list is not required to include the full scope set
- * returned by {@link #getScope()}; that set is always assumed to be
- * included.
- * <p>
- * NOTE: You would normally call {@link #isAdequate(EnumSet)} rather
- * than calling this method directly.
- *
- * @return a list of required scopes, or null.
- */
- @Nullable
- public Collection<EnumSet<Scope>> getAnalysisScopes() {
- return mAnalysisScopes;
- }
-
- /**
- * Sets the collection of scopes that are allowed to be analyzed independently.
- * See the {@link #getAnalysisScopes()} method for a full explanation.
- * Note that you usually want to just call {@link #addAnalysisScope(EnumSet)}
- * instead of constructing a list up front and passing it in here. This
- * method exists primarily such that commonly used share sets of analysis
- * scopes can be reused and set directly.
- *
- * @param required the collection of scopes
- * @return this, for constructor chaining
- */
- public Issue setAnalysisScopes(@Nullable List<EnumSet<Scope>> required) {
- mAnalysisScopes = required;
-
- return this;
- }
-
- /**
- * Returns true if the given scope is adequate for analyzing this issue.
- * This looks through the analysis scopes (see
- * {@link #addAnalysisScope(EnumSet)}) and if the scope passed in fully
- * covers at least one of them, or if it covers the scope of the issue
- * itself (see {@link #getScope()}, which should be a superset of all the
- * analysis scopes) returns true.
- * <p>
- * The scope set returned by {@link Issue#getScope()} lists all the various
- * scopes that are <b>affected</b> by this issue, meaning the detector
- * should consider it. Frequently, the detector must analyze all these
- * scopes in order to properly decide whether an issue is found. For
- * example, the unused resource detector needs to consider both the XML
- * resource files and the Java source files in order to decide if a resource
- * is unused. If it analyzes just the Java files for example, it might
- * incorrectly conclude that a resource is unused because it did not
- * discover a resource reference in an XML file.
- * <p>
- * However, there are other issues where the issue can occur in a variety of
- * files, but the detector can consider each in isolation. For example, the
- * API checker is affected by both XML files and Java class files (detecting
- * both layout constructor references in XML layout files as well as code
- * references in .class files). It doesn't have to analyze both; it is
- * capable of incrementally analyzing just an XML file, or just a class
- * file, without considering the other.
- * <p>
- * An issue can register additional scope sets that can are adequate
- * for analyzing the issue, by calling {@link #addAnalysisScope(EnumSet)}.
- * This method returns true if the given scope matches one or more analysis
- * scope, or the overall scope.
- *
- * @param scope the scope available for analysis
- * @return true if this issue can be analyzed with the given available scope
- */
- public boolean isAdequate(@NonNull EnumSet<Scope> scope) {
- if (scope.containsAll(mScope)) {
- return true;
- }
-
- if (mAnalysisScopes != null) {
- for (EnumSet<Scope> analysisScope : mAnalysisScopes) {
- if (mScope.containsAll(analysisScope)) {
- return true;
- }
- }
- }
-
- if (this == IssueRegistry.LINT_ERROR || this == IssueRegistry.PARSER_ERROR) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Adds a scope set that can be analyzed independently to uncover this issue.
- * See the {@link #getAnalysisScopes()} method for a full explanation.
- * Note that the {@link #getScope()} does not have to be added here; it is
- * always considered an analysis scope.
- *
- * @param scope the additional scope which can analyze this issue independently
- * @return this, for constructor chaining
- */
- public Issue addAnalysisScope(@Nullable EnumSet<Scope> scope) {
- if (mAnalysisScopes == null) {
- mAnalysisScopes = new ArrayList<EnumSet<Scope>>(2);
- }
- mAnalysisScopes.add(scope);
-
- return this;
- }
-
- /**
- * Returns the class of the detector to use to find this issue
- *
- * @return the class of the detector to use to find this issue
- */
- @NonNull
- public Class<? extends Detector> getDetectorClass() {
- return mClass;
- }
-
- @Override
- public String toString() {
- return mId;
- }
-
- /**
- * Converts the given markup text to HTML or text, depending on the.
- * <p>
- * This will recognize the following formatting conventions:
- * <ul>
- * <li>HTTP urls (http://...)
- * <li>Sentences immediately surrounded by * will be shown as bold.
- * <li>Sentences immediately surrounded by ` will be shown using monospace
- * fonts
- * </ul>
- * Furthermore, newlines are converted to br's when converting newlines.
- * Note: It does not insert {@code <html>} tags around the fragment for HTML output.
- * <p>
- * TODO: Consider switching to the restructured text format -
- * http://docutils.sourceforge.net/docs/user/rst/quickstart.html
- *
- * @param text the text to be formatted
- * @param html whether to convert into HTML or text
- * @return the corresponding HTML or text properly formatted
- */
- @NonNull
- public static String convertMarkup(@NonNull String text, boolean html) {
- StringBuilder sb = new StringBuilder(3 * text.length() / 2);
-
- char prev = 0;
- int flushIndex = 0;
- int n = text.length();
- for (int i = 0; i < n; i++) {
- char c = text.charAt(i);
- if ((c == '*' || c == '`' && i < n - 1)) {
- // Scout ahead for range end
- if (!Character.isLetterOrDigit(prev)
- && !Character.isWhitespace(text.charAt(i + 1))) {
- // Found * or ~ immediately before a letter, and not in the middle of a word
- // Find end
- int end = text.indexOf(c, i + 1);
- if (end != -1 && (end == n - 1 || !Character.isLetter(text.charAt(end + 1)))) {
- if (i > flushIndex) {
- appendEscapedText(sb, text, html, flushIndex, i);
- }
- if (html) {
- String tag = c == '*' ? "b" : "code"; //$NON-NLS-1$ //$NON-NLS-2$
- sb.append('<').append(tag).append('>');
- appendEscapedText(sb, text, html, i + 1, end);
- sb.append('<').append('/').append(tag).append('>');
- } else {
- appendEscapedText(sb, text, html, i + 1, end);
- }
- flushIndex = end + 1;
- i = flushIndex - 1; // -1: account for the i++ in the loop
- }
- }
- } else if (html && c == 'h' && i < n - 1 && text.charAt(i + 1) == 't'
- && text.startsWith(HTTP_PREFIX, i) && !Character.isLetterOrDigit(prev)) {
- // Find url end
- int end = i + HTTP_PREFIX.length();
- while (end < n) {
- char d = text.charAt(end);
- if (Character.isWhitespace(d)) {
- break;
- }
- end++;
- }
- char last = text.charAt(end - 1);
- if (last == '.' || last == ')' || last == '!') {
- end--;
- }
- if (end > i + HTTP_PREFIX.length()) {
- if (i > flushIndex) {
- appendEscapedText(sb, text, html, flushIndex, i);
- }
-
- String url = text.substring(i, end);
- sb.append("<a href=\""); //$NON-NLS-1$
- sb.append(url);
- sb.append('"').append('>');
- sb.append(url);
- sb.append("</a>"); //$NON-NLS-1$
-
- flushIndex = end;
- i = flushIndex - 1; // -1: account for the i++ in the loop
- }
- }
- prev = c;
- }
-
- if (flushIndex < n) {
- appendEscapedText(sb, text, html, flushIndex, n);
- }
-
- return sb.toString();
- }
-
- static void appendEscapedText(StringBuilder sb, String text, boolean html,
- int start, int end) {
- if (html) {
- for (int i = start; i < end; i++) {
- char c = text.charAt(i);
- if (c == '<') {
- sb.append("&lt;"); //$NON-NLS-1$
- } else if (c == '&') {
- sb.append("&amp;"); //$NON-NLS-1$
- } else if (c == '\n') {
- sb.append("<br/>\n");
- } else {
- if (c > 255) {
- sb.append("&#"); //$NON-NLS-1$
- sb.append(Integer.toString(c));
- sb.append(';');
- } else {
- sb.append(c);
- }
- }
- }
- } else {
- for (int i = start; i < end; i++) {
- char c = text.charAt(i);
- sb.append(c);
- }
- }
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/JavaContext.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/JavaContext.java
deleted file mode 100644
index ae86568..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/JavaContext.java
+++ /dev/null
@@ -1,108 +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 com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.tools.lint.client.api.IJavaParser;
-import com.android.tools.lint.client.api.LintDriver;
-
-import java.io.File;
-
-import lombok.ast.Node;
-
-/**
- * A {@link Context} used when checking Java files.
- * <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>
- */
-public class JavaContext extends Context {
- /** The parse tree */
- public Node compilationUnit;
- /** The parser which produced the parse tree */
- public IJavaParser parser;
-
- /**
- * Constructs a {@link JavaContext} for running lint on the given file, with
- * the given scope, in the given project reporting errors to the given
- * client.
- *
- * @param driver the driver running through the checks
- * @param project the project to run lint on which contains the given file
- * @param main the main project if this project is a library project, or
- * null if this is not a library project. The main project is
- * the root project of all library projects, not necessarily the
- * directly including project.
- * @param file the file to be analyzed
- */
- public JavaContext(
- @NonNull LintDriver driver,
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File file) {
- super(driver, project, main, file);
- }
-
- /**
- * Returns a location for the given node
- *
- * @param node the AST node to get a location for
- * @return a location for the given node
- */
- @NonNull
- public Location getLocation(@NonNull Node node) {
- if (parser != null) {
- return parser.getLocation(this, node);
- }
-
- return new Location(file, null, null);
- }
-
- @Override
- public void report(@NonNull Issue issue, @Nullable Location location,
- @NonNull String message, @Nullable Object data) {
- if (mDriver.isSuppressed(issue, compilationUnit)) {
- return;
- }
- super.report(issue, location, message, data);
- }
-
- /**
- * Reports an issue applicable to a given AST node. The AST node is used as the
- * scope to check for suppress lint annotations.
- *
- * @param issue the issue to report
- * @param scope the AST node scope the error applies to. The lint infrastructure
- * will check whether there are suppress annotations on this node (or its enclosing
- * nodes) and if so suppress the warning without involving the client.
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable Node scope,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (scope != null && mDriver.isSuppressed(issue, scope)) {
- return;
- }
- super.report(issue, location, message, data);
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LayoutDetector.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LayoutDetector.java
deleted file mode 100644
index b24c1a9..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LayoutDetector.java
+++ /dev/null
@@ -1,70 +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_URI;
-import static com.android.SdkConstants.ATTR_LAYOUT_HEIGHT;
-import static com.android.SdkConstants.ATTR_LAYOUT_WIDTH;
-import static com.android.SdkConstants.ATTR_PADDING;
-import static com.android.SdkConstants.ATTR_PADDING_BOTTOM;
-import static com.android.SdkConstants.ATTR_PADDING_LEFT;
-import static com.android.SdkConstants.ATTR_PADDING_RIGHT;
-import static com.android.SdkConstants.ATTR_PADDING_TOP;
-import static com.android.SdkConstants.VALUE_FILL_PARENT;
-import static com.android.SdkConstants.VALUE_MATCH_PARENT;
-
-import com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.google.common.annotations.Beta;
-
-import org.w3c.dom.Element;
-
-/**
- * Abstract class specifically intended for layout detectors which provides some
- * common utility methods shared by layout detectors.
- * <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 abstract class LayoutDetector extends ResourceXmlDetector {
- @Override
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return folderType == ResourceFolderType.LAYOUT;
- }
-
- private static boolean isFillParent(@NonNull Element element, @NonNull String dimension) {
- String width = element.getAttributeNS(ANDROID_URI, dimension);
- return width.equals(VALUE_MATCH_PARENT) || width.equals(VALUE_FILL_PARENT);
- }
-
- protected static boolean isWidthFillParent(@NonNull Element element) {
- return isFillParent(element, ATTR_LAYOUT_WIDTH);
- }
-
- protected static boolean isHeightFillParent(@NonNull Element element) {
- return isFillParent(element, ATTR_LAYOUT_HEIGHT);
- }
-
- protected boolean hasPadding(@NonNull Element root) {
- return root.hasAttributeNS(ANDROID_URI, ATTR_PADDING)
- || root.hasAttributeNS(ANDROID_URI, ATTR_PADDING_LEFT)
- || root.hasAttributeNS(ANDROID_URI, ATTR_PADDING_RIGHT)
- || root.hasAttributeNS(ANDROID_URI, ATTR_PADDING_TOP)
- || root.hasAttributeNS(ANDROID_URI, ATTR_PADDING_BOTTOM);
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
deleted file mode 100644
index 60c9e97..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java
+++ /dev/null
@@ -1,755 +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_MANIFEST_XML;
-import static com.android.SdkConstants.BIN_FOLDER;
-import static com.android.SdkConstants.DOT_XML;
-import static com.android.SdkConstants.ID_PREFIX;
-import static com.android.SdkConstants.NEW_ID_PREFIX;
-
-import com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.FolderTypeRelationship;
-import com.android.resources.ResourceFolderType;
-import com.android.resources.ResourceType;
-import com.android.tools.lint.client.api.LintClient;
-import com.android.utils.PositionXmlParser;
-import com.google.common.annotations.Beta;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Iterables;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.tree.AbstractInsnNode;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.FieldNode;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.List;
-
-import lombok.ast.ImportDeclaration;
-
-
-/**
- * Useful utility methods related to lint.
- * <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 LintUtils {
- /**
- * Format a list of strings, and cut of the list at {@code maxItems} if the
- * number of items are greater.
- *
- * @param strings the list of strings to print out as a comma separated list
- * @param maxItems the maximum number of items to print
- * @return a comma separated list
- */
- @NonNull
- public static String formatList(@NonNull List<String> strings, int maxItems) {
- StringBuilder sb = new StringBuilder(20 * strings.size());
-
- for (int i = 0, n = strings.size(); i < n; i++) {
- if (sb.length() > 0) {
- sb.append(", "); //$NON-NLS-1$
- }
- sb.append(strings.get(i));
-
- if (maxItems > 0 && i == maxItems - 1 && n > maxItems) {
- sb.append(String.format("... (%1$d more)", n - i - 1));
- break;
- }
- }
-
- return sb.toString();
- }
-
- /**
- * Determine if the given type corresponds to a resource that has a unique
- * file
- *
- * @param type the resource type to check
- * @return true if the given type corresponds to a file-type resource
- */
- public static boolean isFileBasedResourceType(@NonNull ResourceType type) {
- List<ResourceFolderType> folderTypes = FolderTypeRelationship.getRelatedFolders(type);
- for (ResourceFolderType folderType : folderTypes) {
- if (folderType != ResourceFolderType.VALUES) {
- if (type == ResourceType.ID) {
- return false;
- }
- return true;
- }
- }
- return false;
- }
-
- /**
- * Returns true if the given file represents an XML file
- *
- * @param file the file to be checked
- * @return true if the given file is an xml file
- */
- public static boolean isXmlFile(@NonNull File file) {
- String string = file.getName();
- return string.regionMatches(true, string.length() - DOT_XML.length(),
- DOT_XML, 0, DOT_XML.length());
- }
-
- /**
- * Case insensitive ends with
- *
- * @param string the string to be tested whether it ends with the given
- * suffix
- * @param suffix the suffix to check
- * @return true if {@code string} ends with {@code suffix},
- * case-insensitively.
- */
- public static boolean endsWith(@NonNull String string, @NonNull String suffix) {
- return string.regionMatches(true /* ignoreCase */, string.length() - suffix.length(),
- suffix, 0, suffix.length());
- }
-
- /**
- * Case insensitive starts with
- *
- * @param string the string to be tested whether it starts with the given prefix
- * @param prefix the prefix to check
- * @param offset the offset to start checking with
- * @return true if {@code string} starts with {@code prefix},
- * case-insensitively.
- */
- public static boolean startsWith(@NonNull String string, @NonNull String prefix, int offset) {
- return string.regionMatches(true /* ignoreCase */, offset, prefix, 0, prefix.length());
- }
-
- /**
- * Returns the basename of the given filename, unless it's a dot-file such as ".svn".
- *
- * @param fileName the file name to extract the basename from
- * @return the basename (the filename without the file extension)
- */
- public static String getBaseName(@NonNull String fileName) {
- int extension = fileName.indexOf('.');
- if (extension > 0) {
- return fileName.substring(0, extension);
- } else {
- return fileName;
- }
- }
-
- /**
- * Returns the children elements of the given node
- *
- * @param node the parent node
- * @return a list of element children, never null
- */
- @NonNull
- public static List<Element> getChildren(@NonNull Node node) {
- NodeList childNodes = node.getChildNodes();
- List<Element> children = new ArrayList<Element>(childNodes.getLength());
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.ELEMENT_NODE) {
- children.add((Element) child);
- }
- }
-
- return children;
- }
-
- /**
- * Returns the <b>number</b> of children of the given node
- *
- * @param node the parent node
- * @return the count of element children
- */
- public static int getChildCount(@NonNull Node node) {
- NodeList childNodes = node.getChildNodes();
- int childCount = 0;
- for (int i = 0, n = childNodes.getLength(); i < n; i++) {
- Node child = childNodes.item(i);
- if (child.getNodeType() == Node.ELEMENT_NODE) {
- childCount++;
- }
- }
-
- return childCount;
- }
-
- /**
- * Returns true if the given element is the root element of its document
- *
- * @param element the element to test
- * @return true if the element is the root element
- */
- public static boolean isRootElement(Element element) {
- return element == element.getOwnerDocument().getDocumentElement();
- }
-
- /**
- * Returns the given id without an {@code @id/} or {@code @+id} prefix
- *
- * @param id the id to strip
- * @return the stripped id, never null
- */
- @NonNull
- public static String stripIdPrefix(@Nullable String id) {
- if (id == null) {
- return "";
- } else if (id.startsWith(NEW_ID_PREFIX)) {
- return id.substring(NEW_ID_PREFIX.length());
- } else if (id.startsWith(ID_PREFIX)) {
- return id.substring(ID_PREFIX.length());
- }
-
- return id;
- }
-
- /**
- * Returns true if the given two id references match. This is similar to
- * String equality, but it also considers "{@code @+id/foo == @id/foo}.
- *
- * @param id1 the first id to compare
- * @param id2 the second id to compare
- * @return true if the two id references refer to the same id
- */
- public static boolean idReferencesMatch(String id1, String id2) {
- if (id1.startsWith(NEW_ID_PREFIX)) {
- if (id2.startsWith(NEW_ID_PREFIX)) {
- return id1.equals(id2);
- } else {
- assert id2.startsWith(ID_PREFIX);
- return ((id1.length() - id2.length())
- == (NEW_ID_PREFIX.length() - ID_PREFIX.length()))
- && id1.regionMatches(NEW_ID_PREFIX.length(), id2,
- ID_PREFIX.length(),
- id2.length() - ID_PREFIX.length());
- }
- } else {
- assert id1.startsWith(ID_PREFIX);
- if (id2.startsWith(ID_PREFIX)) {
- return id1.equals(id2);
- } else {
- assert id2.startsWith(NEW_ID_PREFIX);
- return (id2.length() - id1.length()
- == (NEW_ID_PREFIX.length() - ID_PREFIX.length()))
- && id2.regionMatches(NEW_ID_PREFIX.length(), id1,
- ID_PREFIX.length(),
- id1.length() - ID_PREFIX.length());
- }
- }
- }
-
- /**
- * Computes the edit distance (number of insertions, deletions or substitutions
- * to edit one string into the other) between two strings. In particular,
- * this will compute the Levenshtein distance.
- * <p>
- * See http://en.wikipedia.org/wiki/Levenshtein_distance for details.
- *
- * @param s the first string to compare
- * @param t the second string to compare
- * @return the edit distance between the two strings
- */
- public static int editDistance(@NonNull String s, @NonNull String t) {
- int m = s.length();
- int n = t.length();
- int[][] d = new int[m + 1][n + 1];
- for (int i = 0; i <= m; i++) {
- d[i][0] = i;
- }
- for (int j = 0; j <= n; j++) {
- d[0][j] = j;
- }
- for (int j = 1; j <= n; j++) {
- for (int i = 1; i <= m; i++) {
- if (s.charAt(i - 1) == t.charAt(j - 1)) {
- d[i][j] = d[i - 1][j - 1];
- } else {
- int deletion = d[i - 1][j] + 1;
- int insertion = d[i][j - 1] + 1;
- int substitution = d[i - 1][j - 1] + 1;
- d[i][j] = Math.min(deletion, Math.min(insertion, substitution));
- }
- }
- }
-
- return d[m][n];
- }
-
- /**
- * Returns true if assertions are enabled
- *
- * @return true if assertions are enabled
- */
- @SuppressWarnings("all")
- public static boolean assertionsEnabled() {
- boolean assertionsEnabled = false;
- assert assertionsEnabled = true; // Intentional side-effect
- return assertionsEnabled;
- }
-
- /**
- * Returns the layout resource name for the given layout file
- *
- * @param layoutFile the file pointing to the layout
- * @return the layout resource name, not including the {@code @layout}
- * prefix
- */
- public static String getLayoutName(File layoutFile) {
- String name = layoutFile.getName();
- int dotIndex = name.indexOf('.');
- if (dotIndex != -1) {
- name = name.substring(0, dotIndex);
- }
- return name;
- }
-
- /**
- * Splits the given path into its individual parts, attempting to be
- * tolerant about path separators (: or ;). It can handle possibly ambiguous
- * paths, such as {@code c:\foo\bar:\other}, though of course these are to
- * be avoided if possible.
- *
- * @param path the path variable to split, which can use both : and ; as
- * path separators.
- * @return the individual path components as an iterable of strings
- */
- public static Iterable<String> splitPath(String path) {
- if (path.indexOf(';') != -1) {
- return Splitter.on(';').omitEmptyStrings().trimResults().split(path);
- }
-
- List<String> combined = new ArrayList<String>();
- Iterables.addAll(combined, Splitter.on(':').omitEmptyStrings().trimResults().split(path));
- for (int i = 0, n = combined.size(); i < n; i++) {
- String p = combined.get(i);
- if (p.length() == 1 && i < n - 1 && Character.isLetter(p.charAt(0))
- // Technically, Windows paths do not have to have a \ after the :,
- // which means it would be using the current directory on that drive,
- // but that's unlikely to be the case in a path since it would have
- // unpredictable results
- && !combined.get(i+1).isEmpty() && combined.get(i+1).charAt(0) == '\\') {
- combined.set(i, p + ':' + combined.get(i+1));
- combined.remove(i+1);
- n--;
- continue;
- }
- }
-
- return combined;
- }
-
- /**
- * Computes the shared parent among a set of files (which may be null).
- *
- * @param files the set of files to be checked
- * @return the closest common ancestor file, or null if none was found
- */
- @Nullable
- public static File getCommonParent(@NonNull List<File> files) {
- int fileCount = files.size();
- if (fileCount == 0) {
- return null;
- } else if (fileCount == 1) {
- return files.get(0);
- } else if (fileCount == 2) {
- return getCommonParent(files.get(0), files.get(1));
- } else {
- File common = files.get(0);
- for (int i = 1; i < fileCount; i++) {
- common = getCommonParent(common, files.get(i));
- if (common == null) {
- return null;
- }
- }
-
- return common;
- }
- }
-
- /**
- * Computes the closest common parent path between two files.
- *
- * @param file1 the first file to be compared
- * @param file2 the second file to be compared
- * @return the closest common ancestor file, or null if the two files have
- * no common parent
- */
- @Nullable
- public static File getCommonParent(@NonNull File file1, @NonNull File file2) {
- if (file1.equals(file2)) {
- return file1;
- } else if (file1.getPath().startsWith(file2.getPath())) {
- return file2;
- } else if (file2.getPath().startsWith(file1.getPath())) {
- return file1;
- } else {
- // Dumb and simple implementation
- File first = file1.getParentFile();
- while (first != null) {
- File second = file2.getParentFile();
- while (second != null) {
- if (first.equals(second)) {
- return first;
- }
- second = second.getParentFile();
- }
-
- first = first.getParentFile();
- }
- }
- return null;
- }
-
- private static final String UTF_8 = "UTF-8"; //$NON-NLS-1$
- private static final String UTF_16 = "UTF_16"; //$NON-NLS-1$
- private static final String UTF_16LE = "UTF_16LE"; //$NON-NLS-1$
-
- /**
- * Returns the encoded String for the given file. This is usually the
- * same as {@code Files.toString(file, Charsets.UTF8}, but if there's a UTF byte order mark
- * (for UTF8, UTF_16 or UTF_16LE), use that instead.
- *
- * @param client the client to use for I/O operations
- * @param file the file to read from
- * @return the string
- * @throws IOException if the file cannot be read properly
- */
- @NonNull
- public static String getEncodedString(
- @NonNull LintClient client,
- @NonNull File file) throws IOException {
- byte[] bytes = client.readBytes(file);
- if (endsWith(file.getName(), DOT_XML)) {
- return PositionXmlParser.getXmlString(bytes);
- }
-
- return LintUtils.getEncodedString(bytes);
- }
-
- /**
- * Returns the String corresponding to the given data. This is usually the
- * same as {@code new String(data)}, but if there's a UTF byte order mark
- * (for UTF8, UTF_16 or UTF_16LE), use that instead.
- * <p>
- * NOTE: For XML files, there is the additional complication that there
- * could be a {@code encoding=} attribute in the prologue. For those files,
- * use {@link PositionXmlParser#getXmlString(byte[])} instead.
- *
- * @param data the byte array to construct the string from
- * @return the string
- */
- @NonNull
- public static String getEncodedString(@Nullable byte[] data) {
- if (data == null) {
- return "";
- }
-
- int offset = 0;
- String defaultCharset = UTF_8;
- String charset = null;
- // Look for the byte order mark, to see if we need to remove bytes from
- // the input stream (and to determine whether files are big endian or little endian) etc
- // for files which do not specify the encoding.
- // See http://unicode.org/faq/utf_bom.html#BOM for more.
- if (data.length > 4) {
- if (data[0] == (byte)0xef && data[1] == (byte)0xbb && data[2] == (byte)0xbf) {
- // UTF-8
- defaultCharset = charset = UTF_8;
- offset += 3;
- } else if (data[0] == (byte)0xfe && data[1] == (byte)0xff) {
- // UTF-16, big-endian
- defaultCharset = charset = UTF_16;
- offset += 2;
- } else if (data[0] == (byte)0x0 && data[1] == (byte)0x0
- && data[2] == (byte)0xfe && data[3] == (byte)0xff) {
- // UTF-32, big-endian
- defaultCharset = charset = "UTF_32"; //$NON-NLS-1$
- offset += 4;
- } else if (data[0] == (byte)0xff && data[1] == (byte)0xfe
- && data[2] == (byte)0x0 && data[3] == (byte)0x0) {
- // UTF-32, little-endian. We must check for this *before* looking for
- // UTF_16LE since UTF_32LE has the same prefix!
- defaultCharset = charset = "UTF_32LE"; //$NON-NLS-1$
- offset += 4;
- } else if (data[0] == (byte)0xff && data[1] == (byte)0xfe) {
- // UTF-16, little-endian
- defaultCharset = charset = UTF_16LE;
- offset += 2;
- }
- }
- int length = data.length - offset;
-
- // Guess encoding by searching for an encoding= entry in the first line.
- boolean seenOddZero = false;
- boolean seenEvenZero = false;
- for (int lineEnd = offset; lineEnd < data.length; lineEnd++) {
- if (data[lineEnd] == 0) {
- if ((lineEnd - offset) % 1 == 0) {
- seenEvenZero = true;
- } else {
- seenOddZero = true;
- }
- } else if (data[lineEnd] == '\n' || data[lineEnd] == '\r') {
- break;
- }
- }
-
- if (charset == null) {
- charset = seenOddZero ? UTF_16 : seenEvenZero ? UTF_16LE : UTF_8;
- }
-
- String text = null;
- try {
- text = new String(data, offset, length, charset);
- } catch (UnsupportedEncodingException e) {
- try {
- if (charset != defaultCharset) {
- text = new String(data, offset, length, defaultCharset);
- }
- } catch (UnsupportedEncodingException u) {
- // Just use the default encoding below
- }
- }
- if (text == null) {
- text = new String(data, offset, length);
- }
- return text;
- }
-
- /**
- * Returns true if the given class node represents a static inner class.
- *
- * @param classNode the inner class to be checked
- * @return true if the class node represents an inner class that is static
- */
- public static boolean isStaticInnerClass(@NonNull ClassNode classNode) {
- // Note: We can't just filter out static inner classes like this:
- // (classNode.access & Opcodes.ACC_STATIC) != 0
- // because the static flag only appears on methods and fields in the class
- // file. Instead, look for the synthetic this pointer.
-
- @SuppressWarnings("rawtypes") // ASM API
- List fieldList = classNode.fields;
- for (Object f : fieldList) {
- FieldNode field = (FieldNode) f;
- if (field.name.startsWith("this$") && (field.access & Opcodes.ACC_SYNTHETIC) != 0) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Returns the previous opcode prior to the given node, ignoring label and
- * line number nodes
- *
- * @param node the node to look up the previous opcode for
- * @return the previous opcode, or {@link Opcodes#NOP} if no previous node
- * was found
- */
- public static int getPrevOpcode(@NonNull AbstractInsnNode node) {
- AbstractInsnNode prev = getPrevInstruction(node);
- if (prev != null) {
- return prev.getOpcode();
- } else {
- return Opcodes.NOP;
- }
- }
-
- /**
- * Returns the previous instruction prior to the given node, ignoring label
- * and line number nodes.
- *
- * @param node the node to look up the previous instruction for
- * @return the previous instruction, or null if no previous node was found
- */
- @Nullable
- public static AbstractInsnNode getPrevInstruction(@NonNull AbstractInsnNode node) {
- AbstractInsnNode prev = node;
- while (true) {
- prev = prev.getPrevious();
- if (prev == null) {
- return null;
- } else {
- int type = prev.getType();
- if (type != AbstractInsnNode.LINE && type != AbstractInsnNode.LABEL
- && type != AbstractInsnNode.FRAME) {
- return prev;
- }
- }
- }
- }
-
- /**
- * Returns the next opcode after to the given node, ignoring label and line
- * number nodes
- *
- * @param node the node to look up the next opcode for
- * @return the next opcode, or {@link Opcodes#NOP} if no next node was found
- */
- public static int getNextOpcode(@NonNull AbstractInsnNode node) {
- AbstractInsnNode next = getNextInstruction(node);
- if (next != null) {
- return next.getOpcode();
- } else {
- return Opcodes.NOP;
- }
- }
-
- /**
- * Returns the next instruction after to the given node, ignoring label and
- * line number nodes.
- *
- * @param node the node to look up the next node for
- * @return the next instruction, or null if no next node was found
- */
- @Nullable
- public static AbstractInsnNode getNextInstruction(@NonNull AbstractInsnNode node) {
- AbstractInsnNode next = node;
- while (true) {
- next = next.getNext();
- if (next == null) {
- return null;
- } else {
- int type = next.getType();
- if (type != AbstractInsnNode.LINE && type != AbstractInsnNode.LABEL
- && type != AbstractInsnNode.FRAME) {
- return next;
- }
- }
- }
- }
-
- /**
- * Returns true if the given directory represents an Android project
- * directory. Note: This doesn't necessarily mean it's an Eclipse directory,
- * only that it looks like it contains a logical Android project -- one
- * including a manifest file, a resource folder, etc.
- *
- * @param dir the directory to check
- * @return true if the directory looks like an Android project
- */
- public static boolean isProjectDir(@NonNull File dir) {
- boolean hasManifest = new File(dir, ANDROID_MANIFEST_XML).exists();
- if (hasManifest) {
- // Special case: the bin/ folder can also contain a copy of the
- // manifest file, but this is *not* a project directory
- if (dir.getName().equals(BIN_FOLDER)) {
- // ...unless of course it just *happens* to be a project named bin, in
- // which case we peek at its parent to see if this is the case
- dir = dir.getParentFile();
- if (dir != null && isProjectDir(dir)) {
- // Yes, it's a bin/ directory inside a real project: ignore this dir
- return false;
- }
- }
- }
-
- return hasManifest;
- }
-
- /**
- * Look up the locale and region from the given parent folder name and
- * return it as a combined string, such as "en", "en-rUS", etc, or null if
- * no language is specified.
- *
- * @param folderName the folder name
- * @return the locale+region string or null
- */
- @Nullable
- public static String getLocaleAndRegion(@NonNull String folderName) {
- if (folderName.equals("values")) { //$NON-NLS-1$
- return null;
- }
-
- String locale = null;
-
- for (String qualifier : Splitter.on('-').split(folderName)) {
- int qualifierLength = qualifier.length();
- if (qualifierLength == 2) {
- char first = qualifier.charAt(0);
- char second = qualifier.charAt(1);
- if (first >= 'a' && first <= 'z' && second >= 'a' && second <= 'z') {
- locale = qualifier;
- }
- } else if (qualifierLength == 3 && qualifier.charAt(0) == 'r' && locale != null) {
- char first = qualifier.charAt(1);
- char second = qualifier.charAt(2);
- if (first >= 'A' && first <= 'Z' && second >= 'A' && second <= 'Z') {
- return locale + '-' + qualifier;
- }
- break;
- }
- }
-
- return locale;
- }
-
- /**
- * Returns true if the given class (specified by a fully qualified class
- * name) name is imported in the given compilation unit either through a fully qualified
- * import or by a wildcard import.
- *
- * @param compilationUnit the compilation unit
- * @param fullyQualifiedName the fully qualified class name
- * @return true if the given imported name refers to the given fully
- * qualified name
- */
- public static boolean isImported(
- @NonNull lombok.ast.Node compilationUnit,
- @NonNull String fullyQualifiedName) {
- int dotIndex = fullyQualifiedName.lastIndexOf('.');
- int dotLength = fullyQualifiedName.length() - dotIndex;
-
- boolean imported = false;
- for (lombok.ast.Node rootNode : compilationUnit.getChildren()) {
- if (rootNode instanceof ImportDeclaration) {
- ImportDeclaration importDeclaration = (ImportDeclaration) rootNode;
- String fqn = importDeclaration.asFullyQualifiedName();
- if (fqn.equals(fullyQualifiedName)) {
- return true;
- } else if (fullyQualifiedName.regionMatches(dotIndex, fqn,
- fqn.length() - dotLength, dotLength)) {
- // This import is importing the class name using some other prefix, so there
- // fully qualified class name cannot be imported under that name
- return false;
- } else if (importDeclaration.astStarImport()
- && fqn.regionMatches(0, fqn, 0, dotIndex + 1)) {
- imported = true;
- // but don't break -- keep searching in case there's a non-wildcard
- // import of the specific class name, e.g. if we're looking for
- // android.content.SharedPreferences.Editor, don't match on the following:
- // import android.content.SharedPreferences.*;
- // import foo.bar.Editor;
- }
- }
- }
-
- return imported;
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java
deleted file mode 100644
index f574189..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java
+++ /dev/null
@@ -1,712 +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 com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.google.common.annotations.Beta;
-
-import java.io.File;
-
-/**
- * Location information for a warning
- * <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 Location {
- private static final String SUPER_KEYWORD = "super"; //$NON-NLS-1$
-
- private final File mFile;
- private final Position mStart;
- private final Position mEnd;
- private String mMessage;
- private Location mSecondary;
- private Object mClientData;
-
- /**
- * (Private constructor, use one of the factory methods
- * {@link Location#create(File)},
- * {@link Location#create(File, Position, Position)}, or
- * {@link Location#create(File, String, int, int)}.
- * <p>
- * Constructs a new location range for the given file, from start to end. If
- * the length of the range is not known, end may be null.
- *
- * @param file the associated file (but see the documentation for
- * {@link #getFile()} for more information on what the file
- * represents)
- * @param start the starting position, or null
- * @param end the ending position, or null
- */
- protected Location(@NonNull File file, @Nullable Position start, @Nullable Position end) {
- super();
- mFile = file;
- mStart = start;
- mEnd = end;
- }
-
- /**
- * Returns the file containing the warning. Note that the file *itself* may
- * not yet contain the error. When editing a file in the IDE for example,
- * the tool could generate warnings in the background even before the
- * document is saved. However, the file is used as a identifying token for
- * the document being edited, and the IDE integration can map this back to
- * error locations in the editor source code.
- *
- * @return the file handle for the location
- */
- @NonNull
- public File getFile() {
- return mFile;
- }
-
- /**
- * The start position of the range
- *
- * @return the start position of the range, or null
- */
- @Nullable
- public Position getStart() {
- return mStart;
- }
-
- /**
- * The end position of the range
- *
- * @return the start position of the range, may be null for an empty range
- */
- @Nullable
- public Position getEnd() {
- return mEnd;
- }
-
- /**
- * Returns a secondary location associated with this location (if
- * applicable), or null.
- *
- * @return a secondary location or null
- */
- @Nullable
- public Location getSecondary() {
- return mSecondary;
- }
-
- /**
- * Sets a secondary location for this location.
- *
- * @param secondary a secondary location associated with this location
- */
- public void setSecondary(@Nullable Location secondary) {
- mSecondary = secondary;
- }
-
- /**
- * Sets a custom message for this location. This is typically used for
- * secondary locations, to describe the significance of this alternate
- * location. For example, for a duplicate id warning, the primary location
- * might say "This is a duplicate id", pointing to the second occurrence of
- * id declaration, and then the secondary location could point to the
- * original declaration with the custom message "Originally defined here".
- *
- * @param message the message to apply to this location
- */
- public void setMessage(@NonNull String message) {
- mMessage = message;
- }
-
- /**
- * Returns the custom message for this location, if any. This is typically
- * used for secondary locations, to describe the significance of this
- * alternate location. For example, for a duplicate id warning, the primary
- * location might say "This is a duplicate id", pointing to the second
- * occurrence of id declaration, and then the secondary location could point
- * to the original declaration with the custom message
- * "Originally defined here".
- *
- * @return the custom message for this location, or null
- */
- @Nullable
- public String getMessage() {
- return mMessage;
- }
-
- /**
- * Sets the client data associated with this location. This is an optional
- * field which can be used by the creator of the {@link Location} to store
- * temporary state associated with the location.
- *
- * @param clientData the data to store with this location
- */
- public void setClientData(@Nullable Object clientData) {
- mClientData = clientData;
- }
-
- /**
- * Returns the client data associated with this location - an optional field
- * which can be used by the creator of the {@link Location} to store
- * temporary state associated with the location.
- *
- * @return the data associated with this location
- */
- @Nullable
- public Object getClientData() {
- return mClientData;
- }
-
- @Override
- public String toString() {
- return "Location [file=" + mFile + ", start=" + mStart + ", end=" + mEnd + ", message="
- + mMessage + "]";
- }
-
- /**
- * Creates a new location for the given file
- *
- * @param file the file to create a location for
- * @return a new location
- */
- @NonNull
- public static Location create(@NonNull File file) {
- return new Location(file, null /*start*/, null /*end*/);
- }
-
- /**
- * Creates a new location for the given file and starting and ending
- * positions.
- *
- * @param file the file containing the positions
- * @param start the starting position
- * @param end the ending position
- * @return a new location
- */
- @NonNull
- public static Location create(
- @NonNull File file,
- @NonNull Position start,
- @Nullable Position end) {
- return new Location(file, start, end);
- }
-
- /**
- * Creates a new location for the given file, with the given contents, for
- * the given offset range.
- *
- * @param file the file containing the location
- * @param contents the current contents of the file
- * @param startOffset the starting offset
- * @param endOffset the ending offset
- * @return a new location
- */
- @NonNull
- public static Location create(
- @NonNull File file,
- @Nullable String contents,
- int startOffset,
- int endOffset) {
- if (startOffset < 0 || endOffset < startOffset) {
- throw new IllegalArgumentException("Invalid offsets");
- }
-
- if (contents == null) {
- return new Location(file,
- new DefaultPosition(-1, -1, startOffset),
- new DefaultPosition(-1, -1, endOffset));
- }
-
- int size = contents.length();
- endOffset = Math.min(endOffset, size);
- startOffset = Math.min(startOffset, endOffset);
- Position start = null;
- int line = 0;
- int lineOffset = 0;
- for (int offset = 0; offset <= size; offset++) {
- if (offset == startOffset) {
- start = new DefaultPosition(line, offset - lineOffset, offset);
- }
- if (offset == endOffset) {
- Position end = new DefaultPosition(line, offset - lineOffset, offset);
- return new Location(file, start, end);
- }
- char c = contents.charAt(offset);
- if (c == '\n') {
- lineOffset = offset + 1;
- line++;
- }
- }
- return Location.create(file);
- }
-
- /**
- * Creates a new location for the given file, with the given contents, for
- * the given line number.
- *
- * @param file the file containing the location
- * @param contents the current contents of the file
- * @param line the line number (0-based) for the position
- * @return a new location
- */
- @NonNull
- public static Location create(@NonNull File file, @NonNull String contents, int line) {
- return create(file, contents, line, null, null, null);
- }
-
- /**
- * Creates a new location for the given file, with the given contents, for
- * the given line number.
- *
- * @param file the file containing the location
- * @param contents the current contents of the file
- * @param line the line number (0-based) for the position
- * @param patternStart an optional pattern to search for from the line
- * match; if found, adjust the column and offsets to begin at the
- * pattern start
- * @param patternEnd an optional pattern to search for behind the start
- * pattern; if found, adjust the end offset to match the end of
- * the pattern
- * @param hints optional additional information regarding the pattern search
- * @return a new location
- */
- @NonNull
- public static Location create(@NonNull File file, @NonNull String contents, int line,
- @Nullable String patternStart, @Nullable String patternEnd,
- @Nullable SearchHints hints) {
- int currentLine = 0;
- int offset = 0;
- while (currentLine < line) {
- offset = contents.indexOf('\n', offset);
- if (offset == -1) {
- return Location.create(file);
- }
- currentLine++;
- offset++;
- }
-
- if (line == currentLine) {
- if (patternStart != null) {
- int index = offset;
-
- SearchDirection direction = SearchDirection.NEAREST;
- if (hints != null) {
- direction = hints.mDirection;
- }
-
- if (direction == SearchDirection.BACKWARD) {
- index = findPreviousMatch(contents, offset, patternStart, hints);
- line = adjustLine(contents, line, offset, index);
- } else if (direction == SearchDirection.EOL_BACKWARD) {
- int lineEnd = contents.indexOf('\n', offset);
- if (lineEnd == -1) {
- lineEnd = contents.length();
- }
-
- index = findPreviousMatch(contents, lineEnd, patternStart, hints);
- line = adjustLine(contents, line, offset, index);
- } else if (direction == SearchDirection.FORWARD) {
- index = findNextMatch(contents, offset, patternStart, hints);
- line = adjustLine(contents, line, offset, index);
- } else {
- assert direction == SearchDirection.NEAREST;
-
- int before = findPreviousMatch(contents, offset, patternStart, hints);
- int after = findNextMatch(contents, offset, patternStart, hints);
-
- if (before == -1) {
- index = after;
- line = adjustLine(contents, line, offset, index);
- } else if (after == -1) {
- index = before;
- line = adjustLine(contents, line, offset, index);
- } else if (offset - before < after - offset) {
- index = before;
- line = adjustLine(contents, line, offset, index);
- } else {
- index = after;
- line = adjustLine(contents, line, offset, index);
- }
- }
-
- if (index != -1) {
- int lineStart = contents.lastIndexOf('\n', index);
- if (lineStart == -1) {
- lineStart = 0;
- } else {
- lineStart++; // was pointing to the previous line's CR, not line start
- }
- int column = index - lineStart;
- if (patternEnd != null) {
- int end = contents.indexOf(patternEnd, offset + patternStart.length());
- if (end != -1) {
- return new Location(file, new DefaultPosition(line, column, index),
- new DefaultPosition(line, -1, end + patternEnd.length()));
- }
- } else if (hints != null && (hints.isJavaSymbol() || hints.isWholeWord())) {
- if (hints.isConstructor() && contents.startsWith(SUPER_KEYWORD, index)) {
- patternStart = SUPER_KEYWORD;
- }
- return new Location(file, new DefaultPosition(line, column, index),
- new DefaultPosition(line, column + patternStart.length(),
- index + patternStart.length()));
- }
- return new Location(file, new DefaultPosition(line, column, index),
- new DefaultPosition(line, column, index + patternStart.length()));
- }
- }
-
- Position position = new DefaultPosition(line, -1, offset);
- return new Location(file, position, position);
- }
-
- return Location.create(file);
- }
-
- private static int findPreviousMatch(@NonNull String contents, int offset, String pattern,
- @Nullable SearchHints hints) {
- while (true) {
- int index = contents.lastIndexOf(pattern, offset);
- if (index == -1) {
- return -1;
- } else {
- if (isMatch(contents, index, pattern, hints)) {
- return index;
- } else {
- offset = index - pattern.length();
- }
- }
- }
- }
-
- private static int findNextMatch(@NonNull String contents, int offset, String pattern,
- @Nullable SearchHints hints) {
- int constructorIndex = -1;
- if (hints != null && hints.isConstructor()) {
- // Special condition: See if the call is referenced as "super" instead.
- assert hints.isWholeWord();
- int index = contents.indexOf(SUPER_KEYWORD, offset);
- if (index != -1 && isMatch(contents, index, SUPER_KEYWORD, hints)) {
- constructorIndex = index;
- }
- }
-
- while (true) {
- int index = contents.indexOf(pattern, offset);
- if (index == -1) {
- return constructorIndex;
- } else {
- if (isMatch(contents, index, pattern, hints)) {
- if (constructorIndex != -1) {
- return Math.min(constructorIndex, index);
- }
- return index;
- } else {
- offset = index + pattern.length();
- }
- }
- }
- }
-
- private static boolean isMatch(@NonNull String contents, int offset, String pattern,
- @Nullable SearchHints hints) {
- if (!contents.startsWith(pattern, offset)) {
- return false;
- }
-
- if (hints != null) {
- char prevChar = offset > 0 ? contents.charAt(offset - 1) : 0;
- int lastIndex = offset + pattern.length() - 1;
- char nextChar = lastIndex < contents.length() - 1 ? contents.charAt(lastIndex + 1) : 0;
-
- if (hints.isWholeWord() && (Character.isLetter(prevChar)
- || Character.isLetter(nextChar))) {
- return false;
-
- }
-
- if (hints.isJavaSymbol()) {
- if (Character.isJavaIdentifierPart(prevChar)
- || Character.isJavaIdentifierPart(nextChar)) {
- return false;
- }
-
- if (prevChar == '"') {
- return false;
- }
-
- // TODO: Additional validation to see if we're in a comment, string, etc.
- // This will require lexing from the beginning of the buffer.
- }
-
- if (hints.isConstructor() && SUPER_KEYWORD.equals(pattern)) {
- // Only looking for super(), not super.x, so assert that the next
- // non-space character is (
- int index = lastIndex + 1;
- while (index < contents.length() - 1) {
- char c = contents.charAt(index);
- if (c == '(') {
- break;
- } else if (!Character.isWhitespace(c)) {
- return false;
- }
- index++;
- }
- }
- }
-
- return true;
- }
-
- private static int adjustLine(String doc, int line, int offset, int newOffset) {
- if (newOffset == -1) {
- return line;
- }
-
- if (newOffset < offset) {
- return line - countLines(doc, newOffset, offset);
- } else {
- return line + countLines(doc, offset, newOffset);
- }
- }
-
- private static int countLines(String doc, int start, int end) {
- int lines = 0;
- for (int offset = start; offset < end; offset++) {
- char c = doc.charAt(offset);
- if (c == '\n') {
- lines++;
- }
- }
-
- return lines;
- }
-
- /**
- * Reverses the secondary location list initiated by the given location
- *
- * @param location the first location in the list
- * @return the first location in the reversed list
- */
- public static Location reverse(Location location) {
- Location next = location.getSecondary();
- location.setSecondary(null);
- while (next != null) {
- Location nextNext = next.getSecondary();
- next.setSecondary(location);
- location = next;
- next = nextNext;
- }
-
- return location;
- }
-
- /**
- * A {@link Handle} is a reference to a location. The point of a location
- * handle is to be able to create them cheaply, and then resolve them into
- * actual locations later (if needed). This makes it possible to for example
- * delay looking up line numbers, for locations that are offset based.
- */
- public static interface Handle {
- /**
- * Compute a full location for the given handle
- *
- * @return create a location for this handle
- */
- @NonNull
- Location resolve();
-
- /**
- * Sets the client data associated with this location. This is an optional
- * field which can be used by the creator of the {@link Location} to store
- * temporary state associated with the location.
- *
- * @param clientData the data to store with this location
- */
- public void setClientData(@Nullable Object clientData);
-
- /**
- * Returns the client data associated with this location - an optional field
- * which can be used by the creator of the {@link Location} to store
- * temporary state associated with the location.
- *
- * @return the data associated with this location
- */
- @Nullable
- public Object getClientData();
- }
-
- /** A default {@link Handle} implementation for simple file offsets */
- public static class DefaultLocationHandle implements Handle {
- private File mFile;
- private String mContents;
- private int mStartOffset;
- private int mEndOffset;
- private Object mClientData;
-
- /**
- * Constructs a new {@link DefaultLocationHandle}
- *
- * @param context the context pointing to the file and its contents
- * @param startOffset the start offset within the file
- * @param endOffset the end offset within the file
- */
- public DefaultLocationHandle(@NonNull Context context, int startOffset, int endOffset) {
- mFile = context.file;
- mContents = context.getContents();
- mStartOffset = startOffset;
- mEndOffset = endOffset;
- }
-
- @Override
- @NonNull
- public Location resolve() {
- return Location.create(mFile, mContents, mStartOffset, mEndOffset);
- }
-
- @Override
- public void setClientData(@Nullable Object clientData) {
- mClientData = clientData;
- }
-
- @Override
- @Nullable
- public Object getClientData() {
- return mClientData;
- }
- }
-
- /**
- * Whether to look forwards, or backwards, or in both directions, when
- * searching for a pattern in the source code to determine the right
- * position range for a given symbol.
- * <p>
- * When dealing with bytecode for example, there are only line number entries
- * within method bodies, so when searching for the method declaration, we should only
- * search backwards from the first line entry in the method.
- */
- public enum SearchDirection {
- /** Only search forwards */
- FORWARD,
-
- /** Only search backwards */
- BACKWARD,
-
- /** Search backwards from the current end of line (normally it's the beginning of
- * the current line) */
- EOL_BACKWARD,
-
- /**
- * Search both forwards and backwards from the given line, and prefer
- * the match that is closest
- */
- NEAREST,
- }
-
- /**
- * Extra information pertaining to finding a symbol in a source buffer,
- * used by {@link Location#create(File, String, int, String, String, SearchHints)}
- */
- public static class SearchHints {
- /**
- * the direction to search for the nearest match in (provided
- * {@code patternStart} is non null)
- */
- @NonNull
- private SearchDirection mDirection;
-
- /** Whether the matched pattern should be a whole word */
- private boolean mWholeWord;
-
- /**
- * Whether the matched pattern should be a Java symbol (so for example,
- * a match inside a comment or string literal should not be used)
- */
- private boolean mJavaSymbol;
-
- /**
- * Whether the matched pattern corresponds to a constructor; if so, look for
- * some other possible source aliases too, such as "super".
- */
- private boolean mConstructor;
-
- private SearchHints(SearchDirection direction) {
- super();
- mDirection = direction;
- }
-
- /**
- * Constructs a new {@link SearchHints} object
- *
- * @param direction the direction to search in for the pattern
- * @return a new @link SearchHints} object
- */
- public static SearchHints create(SearchDirection direction) {
- return new SearchHints(direction);
- }
-
- /**
- * Indicates that pattern matches should apply to whole words only
-
- * @return this, for constructor chaining
- */
- public SearchHints matchWholeWord() {
- mWholeWord = true;
-
- return this;
- }
-
- /** @return true if the pattern match should be for whole words only */
- public boolean isWholeWord() {
- return mWholeWord;
- }
-
- /**
- * Indicates that pattern matches should apply to Java symbols only
- *
- * @return this, for constructor chaining
- */
- public SearchHints matchJavaSymbol() {
- mJavaSymbol = true;
- mWholeWord = true;
-
- return this;
- }
-
- /** @return true if the pattern match should be for Java symbols only */
- public boolean isJavaSymbol() {
- return mJavaSymbol;
- }
-
- /**
- * Indicates that pattern matches should apply to constructors. If so, look for
- * some other possible source aliases too, such as "super".
- *
- * @return this, for constructor chaining
- */
- public SearchHints matchConstructor() {
- mConstructor = true;
- mWholeWord = true;
- mJavaSymbol = true;
-
- return this;
- }
-
- /** @return true if the pattern match should be for a constructor */
- public boolean isConstructor() {
- return mConstructor;
- }
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Position.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Position.java
deleted file mode 100644
index 6407cc9..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Position.java
+++ /dev/null
@@ -1,50 +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 com.google.common.annotations.Beta;
-
-/**
- * Information about a position in a file/document.
- * <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 abstract class Position {
- /**
- * Returns the line number (0-based where the first line is line 0)
- *
- * @return the 0-based line number
- */
- public abstract int getLine();
-
- /**
- * The character offset
- *
- * @return the 0-based character offset
- */
- public abstract int getOffset();
-
- /**
- * Returns the column number (where the first character on the line is 0),
- * or -1 if unknown
- *
- * @return the 0-based column number
- */
- public abstract int getColumn();
-}
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;
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ResourceXmlDetector.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ResourceXmlDetector.java
deleted file mode 100644
index 68685c6..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ResourceXmlDetector.java
+++ /dev/null
@@ -1,60 +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 com.android.annotations.NonNull;
-import com.android.resources.ResourceFolderType;
-import com.google.common.annotations.Beta;
-
-import java.io.File;
-
-/**
- * Specialized detector intended for XML resources. Detectors that apply to XML
- * resources should extend this detector instead since it provides special
- * iteration hooks that are more efficient.
- * <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 abstract class ResourceXmlDetector extends Detector implements Detector.XmlScanner {
- @Override
- public boolean appliesTo(@NonNull Context context, @NonNull File file) {
- return LintUtils.isXmlFile(file);
- }
-
- /**
- * Returns whether this detector applies to the given folder type. This
- * allows the detectors to be pruned from iteration, so for example when we
- * are analyzing a string value file we don't need to look up detectors
- * related to layout.
- *
- * @param folderType the folder type to be visited
- * @return true if this detector can apply to resources in folders of the
- * given type
- */
- public boolean appliesTo(@NonNull ResourceFolderType folderType) {
- return true;
- }
-
- @Override
- public void run(@NonNull Context context) {
- // The infrastructure should never call this method on an xml detector since
- // it will run the various visitors instead
- assert false;
- }
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java
deleted file mode 100644
index a917c11..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Scope.java
+++ /dev/null
@@ -1,137 +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 com.android.annotations.NonNull;
-import com.google.common.annotations.Beta;
-
-import java.util.EnumSet;
-
-/**
- * The scope of a detector is the set of files a detector must consider when
- * performing its analysis. This can be used to determine when issues are
- * potentially obsolete, whether a detector should re-run on a file save, etc.
- * <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 enum Scope {
- /**
- * The analysis only considers a single XML resource file at a time.
- * <p>
- * Issues which are only affected by a single resource file can be checked
- * for incrementally when a file is edited.
- */
- RESOURCE_FILE,
-
- /**
- * The analysis considers <b>all</b> the resource file. This scope must not
- * be used in conjunction with {@link #RESOURCE_FILE}; an issue scope is
- * either considering just a single resource file or all the resources, not
- * both.
- */
- ALL_RESOURCE_FILES,
-
- /**
- * The analysis only considers a single Java source file at a time.
- * <p>
- * Issues which are only affected by a single Java source file can be
- * checked for incrementally when a Java source file is edited.
- */
- JAVA_FILE,
-
- /**
- * The analysis considers <b>all</b> the Java source files together.
- * <p>
- * This flag is mutually exclusive with {@link #JAVA_FILE}.
- */
- ALL_JAVA_FILES,
-
- /**
- * The analysis only considers a single Java class file at a time.
- * <p>
- * Issues which are only affected by a single Java class file can be checked
- * for incrementally when a Java source file is edited and then recompiled.
- */
- CLASS_FILE,
-
- /** The analysis considers the manifest file */
- MANIFEST,
-
- /** The analysis considers the Proguard configuration file */
- PROGUARD_FILE,
-
- /**
- * The analysis considers classes in the libraries for this project. These
- * will be analyzed before the classes themselves.
- */
- JAVA_LIBRARIES;
-
- /**
- * Returns true if the given scope set corresponds to scanning a single file
- * rather than a whole project
- *
- * @param scopes the scope set to check
- * @return true if the scope set references a single file
- */
- public static boolean checkSingleFile(@NonNull EnumSet<Scope> scopes) {
- int size = scopes.size();
- if (size == 2) {
- // When single checking a Java source file, we check both its Java source
- // and the associated class files
- return scopes.contains(JAVA_FILE) && scopes.contains(CLASS_FILE);
- } else {
- return size == 1 &&
- (scopes.contains(JAVA_FILE)
- || scopes.contains(CLASS_FILE)
- || scopes.contains(RESOURCE_FILE)
- || scopes.contains(PROGUARD_FILE)
- || scopes.contains(MANIFEST));
- }
- }
-
- /**
- * Returns the intersection of two scope sets
- *
- * @param scope1 the first set to intersect
- * @param scope2 the second set to intersect
- * @return the intersection of the two sets
- */
- @NonNull
- public static EnumSet<Scope> intersect(
- @NonNull EnumSet<Scope> scope1,
- @NonNull EnumSet<Scope> scope2) {
- EnumSet<Scope> scope = EnumSet.copyOf(scope1);
- scope.retainAll(scope2);
-
- return scope;
- }
-
- /** All scopes: running lint on a project will check these scopes */
- public static final EnumSet<Scope> ALL = EnumSet.allOf(Scope.class);
- /** Scope-set used for detectors which are affected by a single resource file */
- public static final EnumSet<Scope> RESOURCE_FILE_SCOPE = EnumSet.of(RESOURCE_FILE);
- /** Scope-set used for detectors which scan all resources */
- public static final EnumSet<Scope> ALL_RESOURCES_SCOPE = EnumSet.of(ALL_RESOURCE_FILES);
- /** Scope-set used for detectors which are affected by a single Java source file */
- public static final EnumSet<Scope> JAVA_FILE_SCOPE = EnumSet.of(JAVA_FILE);
- /** Scope-set used for detectors which are affected by a single Java class file */
- public static final EnumSet<Scope> CLASS_FILE_SCOPE = EnumSet.of(CLASS_FILE);
- /** Scope-set used for detectors which are affected by the manifest only */
- public static final EnumSet<Scope> MANIFEST_SCOPE = EnumSet.of(MANIFEST);
-}
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Severity.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Severity.java
deleted file mode 100644
index cde61bd..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Severity.java
+++ /dev/null
@@ -1,77 +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 com.android.annotations.NonNull;
-import com.google.common.annotations.Beta;
-
-/**
- * Severity of an issue found by lint
- * <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 enum Severity {
- /**
- * Fatal: Use sparingly because a warning marked as fatal will be
- * considered critical and will abort Export APK etc in ADT
- */
- @NonNull
- FATAL("Fatal"),
-
- /**
- * Errors: The issue is known to be a real error that must be addressed.
- */
- @NonNull
- ERROR("Error"),
-
- /**
- * Warning: Probably a problem.
- */
- @NonNull
- WARNING("Warning"),
-
- /**
- * Information only: Might not be a problem, but the check has found
- * something interesting to say about the code.
- */
- @NonNull
- INFORMATIONAL("Information"),
-
- /**
- * Ignore: The user doesn't want to see this issue
- */
- @NonNull
- IGNORE("Ignore");
-
- @NonNull
- private final String mDisplay;
-
- private Severity(@NonNull String display) {
- mDisplay = display;
- }
-
- /**
- * Returns a description of this severity suitable for display to the user
- *
- * @return a description of the severity
- */
- public @NonNull String getDescription() {
- return mDisplay;
- }
-} \ No newline at end of file
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Speed.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Speed.java
deleted file mode 100644
index 8c20a19..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Speed.java
+++ /dev/null
@@ -1,55 +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 com.android.annotations.NonNull;
-import com.google.common.annotations.Beta;
-
-/**
- * Enum which describes the different computation speeds of various detectors
- * <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 enum Speed {
- /** The detector can run very quickly */
- FAST("Fast"),
-
- /** The detector runs reasonably fast */
- NORMAL("Normal"),
-
- /** The detector might take a long time to run */
- SLOW("Slow");
-
- private String mDisplayName;
-
- Speed(@NonNull String displayName) {
- mDisplayName = displayName;
- }
-
- /**
- * Returns the user-visible description of the speed of the given
- * detector
- *
- * @return the description of the speed to display to the user
- */
- @NonNull
- public String getDisplayName() {
- return mDisplayName;
- }
-} \ No newline at end of file
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/XmlContext.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/XmlContext.java
deleted file mode 100644
index 14e0a91..0000000
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/XmlContext.java
+++ /dev/null
@@ -1,189 +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 com.android.annotations.NonNull;
-import com.android.annotations.Nullable;
-import com.android.resources.ResourceFolderType;
-import com.android.tools.lint.client.api.IDomParser;
-import com.android.tools.lint.client.api.LintDriver;
-import com.google.common.annotations.Beta;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Node;
-
-import java.io.File;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A {@link Context} used when checking XML files.
- * <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 XmlContext extends Context {
- /** The XML parser */
- public IDomParser parser;
- /** The XML document */
- public Document document;
- private final ResourceFolderType mFolderType;
-
- /**
- * Construct a new {@link XmlContext}
- *
- * @param driver the driver running through the checks
- * @param project the project containing the file being checked
- * @param main the main project if this project is a library project, or
- * null if this is not a library project. The main project is
- * the root project of all library projects, not necessarily the
- * directly including project.
- * @param file the file being checked
- * @param folderType the {@link ResourceFolderType} of this file, if any
- */
- public XmlContext(
- @NonNull LintDriver driver,
- @NonNull Project project,
- @Nullable Project main,
- @NonNull File file,
- @Nullable ResourceFolderType folderType) {
- super(driver, project, main, file);
- mFolderType = folderType;
- }
-
- /**
- * Returns the location for the given node, which may be an element or an attribute.
- *
- * @param node the node to look up the location for
- * @return the location for the node
- */
- @NonNull
- public Location getLocation(@NonNull Node node) {
- if (parser != null) {
- return parser.getLocation(this, node);
- }
-
- return Location.create(file);
- }
-
- /**
- * Creates a new location within an XML text node
- *
- * @param textNode the text node
- * @param begin the start offset within the text node (inclusive)
- * @param end the end offset within the text node (exclusive)
- * @return a new location
- */
- @NonNull
- public Location getLocation(@NonNull Node textNode, int begin, int end) {
- assert textNode.getNodeType() == Node.TEXT_NODE;
- if (parser != null) {
- return parser.getLocation(this, textNode, begin, end);
- }
-
- return Location.create(file);
- }
-
-
- /**
- * Reports an issue applicable to a given DOM node. The DOM node is used as the
- * scope to check for suppress lint annotations.
- *
- * @param issue the issue to report
- * @param scope the DOM node scope the error applies to. The lint infrastructure
- * will check whether there are suppress directives on this node (or its enclosing
- * nodes) and if so suppress the warning without involving the client.
- * @param location the location of the issue, or null if not known
- * @param message the message for this warning
- * @param data any associated data, or null
- */
- public void report(
- @NonNull Issue issue,
- @Nullable Node scope,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- if (scope != null && mDriver.isSuppressed(issue, scope)) {
- return;
- }
- super.report(issue, location, message, data);
- }
-
- @Override
- public void report(
- @NonNull Issue issue,
- @Nullable Location location,
- @NonNull String message,
- @Nullable Object data) {
- // Warn if clients use the non-scoped form? No, there are cases where an
- // XML detector's error isn't applicable to one particular location (or it's
- // not feasible to compute it cheaply)
- //mDriver.getClient().log(null, "Warning: Issue " + issue
- // + " was reported without a scope node: Can't be suppressed.");
-
- // For now just check the document root itself
- if (document != null && mDriver.isSuppressed(issue, document)) {
- return;
- }
-
- super.report(issue, location, message, data);
- }
-
- /**
- * Returns the resource folder type of this XML file, if any.
- *
- * @return the resource folder type or null
- */
- @Nullable
- public ResourceFolderType getResourceFolderType() {
- return mFolderType;
- }
-
-
- private final static Pattern sVersionPattern = Pattern.compile("^v(\\d+)$");//$NON-NLS-1$
-
- private static File sCachedFolder = null;
- private static int sCachedFolderVersion = -1;
-
- /**
- * Returns the folder version. For example, for the file values-v14/foo.xml,
- * it returns 14.
- *
- * @return the folder version, or -1 if no specific version was specified
- */
- public int getFolderVersion() {
- File parent = file.getParentFile();
- if (parent.equals(sCachedFolder)) {
- return sCachedFolderVersion;
- }
-
- sCachedFolder = parent;
- sCachedFolderVersion = -1;
-
- String[] qualifiers = parent.getName().split("-"); //$NON-NLS-1$
- for (String qualifier : qualifiers) {
- Matcher matcher = sVersionPattern.matcher(qualifier);
- if (matcher.matches()) {
- sCachedFolderVersion = Integer.parseInt(matcher.group(1));
- break;
- }
- }
-
- return sCachedFolderVersion;
- }
-}