diff options
author | Tor Norbye <tnorbye@google.com> | 2012-02-20 08:57:56 -0800 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2012-02-21 09:17:02 -0800 |
commit | e0281950ddcd517c9ef4c6ed118f33a9fd063cec (patch) | |
tree | 3d2d09a32bf479ae34d5263de15c7f4f1904ae68 /lint | |
parent | 556b907792f0658a6c3f676e23469b83175e3431 (diff) | |
download | sdk-e0281950ddcd517c9ef4c6ed118f33a9fd063cec.zip sdk-e0281950ddcd517c9ef4c6ed118f33a9fd063cec.tar.gz sdk-e0281950ddcd517c9ef4c6ed118f33a9fd063cec.tar.bz2 |
Use lint error mechanism for config issues like no classes found
If Lint cannot find the .class files for a project, it cannot run any
of the class-file based checks (such as the NewApi check).
This changeset adds a new category and issue id, "Lint Error", for
these types of issues. In HTML reports, these errors are listed at the
top. The issue explanation states that these errors don't represent
bugs in the user's code, but that lint was not able to check certain
things for the reasons given.
In the case of no .class files found, it asks whether the project
needs to be built first. It also uses these lint errors to emit
errors in processing lint.xml configuration files.
(Note that if you don't want to see these types of errors, you can
suppress it via --disable LintError.)
Change-Id: Ifc2f55566f3a0cd20189d43e4205201bc21ee280
Diffstat (limited to 'lint')
6 files changed, 66 insertions, 13 deletions
diff --git a/lint/cli/src/com/android/tools/lint/Main.java b/lint/cli/src/com/android/tools/lint/Main.java index 1484a1d..629c932 100644 --- a/lint/cli/src/com/android/tools/lint/Main.java +++ b/lint/cli/src/com/android/tools/lint/Main.java @@ -16,6 +16,8 @@ package com.android.tools.lint; +import static com.android.tools.lint.client.api.IssueRegistry.LINT_ERROR; +import static com.android.tools.lint.client.api.IssueRegistry.PARSER_ERROR; import static com.android.tools.lint.detector.api.LintConstants.DOT_XML; import static com.android.tools.lint.detector.api.LintUtils.endsWith; @@ -1030,7 +1032,7 @@ public class Main extends LintClient { } } - if (mCheck != null) { + if (mCheck != null && issue != LINT_ERROR && issue != PARSER_ERROR) { return Severity.IGNORE; } @@ -1081,6 +1083,9 @@ public class Main extends LintClient { chop++; } path = path.substring(chop); + if (path.length() == 0) { + path = file.getName(); + } } return path; 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 index 1281987..56cee8e 100644 --- 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 @@ -31,6 +31,7 @@ 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; @@ -196,6 +197,15 @@ public class DefaultConfiguration extends Configuration { } } + 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; + mClient.report(new Context(null, mProject, mProject, mConfigFile), + IssueRegistry.LINT_ERROR, Location.create(mConfigFile), message, null); + } + private void readConfig() { mSuppressed = new HashMap<String, List<String>>(); mSeverity = new HashMap<String, Severity>(); @@ -218,8 +228,7 @@ public class DefaultConfiguration extends Configuration { Element element = (Element) node; String id = element.getAttribute(ATTR_ID); if (id.length() == 0) { - mClient.log(null, - "Invalid lint config file: Missing required issue id attribute"); + formatError("Invalid lint config file: Missing required issue id attribute"); continue; } @@ -238,7 +247,7 @@ public class DefaultConfiguration extends Configuration { } } } else { - mClient.log(null, "Unexpected attribute %1$s", name); + formatError("Unexpected attribute \"%1$s\"", name); } } @@ -251,7 +260,7 @@ public class DefaultConfiguration extends Configuration { Element ignore = (Element) child; String path = ignore.getAttribute(ATTR_PATH); if (path.length() == 0) { - mClient.log(null, "Missing required %1$s attribute under %2$s", + formatError("Missing required %1$s attribute under %2$s", ATTR_PATH, id); } else { List<String> paths = mSuppressed.get(id); @@ -265,6 +274,8 @@ public class DefaultConfiguration extends Configuration { } } } + } catch (SAXParseException e) { + formatError(e.getMessage()); } catch (Exception e) { mClient.log(e, null); } 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 index a809841..7d9471d 100644 --- 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 @@ -61,6 +61,27 @@ public abstract class IssueRegistry { 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, + null, + 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 @@ -213,6 +234,7 @@ public abstract class IssueRegistry { } sIdToIssue.put(PARSER_ERROR.getId(), PARSER_ERROR); + sIdToIssue.put(LINT_ERROR.getId(), LINT_ERROR); } return sIdToIssue.get(id); } 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 index 31622eb..4ebc9ed 100644 --- 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 @@ -830,8 +830,12 @@ public class LintDriver { List<File> classFolders = project.getJavaClassFolders(); List<ClassEntry> classEntries; if (classFolders.size() == 0) { - //mClient.log(null, "Warning: Class-file checks are enabled, but no " + - // "output folders found. Does the project need to be built first?"); + 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, location, message, null); classEntries = Collections.emptyList(); } else { classEntries = new ArrayList<ClassEntry>(64); @@ -1247,7 +1251,7 @@ public class LintDriver { @Nullable Object data) { Configuration configuration = context.getConfiguration(); if (!configuration.isEnabled(issue)) { - if (issue != IssueRegistry.PARSER_ERROR) { + if (issue != IssueRegistry.PARSER_ERROR && issue != IssueRegistry.LINT_ERROR) { mDelegate.log(null, "Incorrect detector reported disabled issue %1$s", issue.toString()); } 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 index 75aaa0b..6978ef0 100644 --- 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 @@ -136,6 +136,9 @@ public final class Category implements Comparable<Category> { 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); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java index 97cb5f6..95ca8b9 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java @@ -125,7 +125,7 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann @Override public void afterCheckFile(Context context) { - if (mSeenUsesSdk == 0) { + if (mSeenUsesSdk == 0 && context.isEnabled(USES_SDK)) { context.report(USES_SDK, Location.create(context.file), "Manifest should specify a minimum API level with " + "<uses-sdk android:minSdkVersion=\"?\" />; if it really supports " + @@ -175,34 +175,42 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann } location.setSecondary(secondary); - context.report(MULTIPLE_USES_SDK, element, location, + if (context.isEnabled(MULTIPLE_USES_SDK)) { + context.report(MULTIPLE_USES_SDK, element, location, "There should only be a single <uses-sdk> element in the manifest:" + " merge these together", null); + } return; } if (!element.hasAttributeNS(ANDROID_URI, ATTR_MIN_SDK_VERSION)) { - context.report(USES_SDK, element, context.getLocation(element), + if (context.isEnabled(USES_SDK)) { + context.report(USES_SDK, element, context.getLocation(element), "<uses-sdk> tag should specify a minimum API level with " + "android:minSdkVersion=\"?\"", null); + } } else if (context.getProject().getMinSdk() <= 9 && !element.hasAttributeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION)) { // Warn if not setting target SDK -- but only if the min SDK is somewhat // old so there's some compatibility stuff kicking in (such as the menu // button etc) - context.report(USES_SDK, element, context.getLocation(element), + if (context.isEnabled(USES_SDK)) { + context.report(USES_SDK, element, context.getLocation(element), "<uses-sdk> tag should specify a target API level (the " + "highest verified version; when running on later versions, " + "compatibility behaviors may be enabled) with " + "android:targetSdkVersion=\"?\"", null); + } } } if (tag.equals(TAG_APPLICATION)) { mSeenApplication = true; } else if (mSeenApplication) { - context.report(ORDER, element, context.getLocation(element), + if (context.isEnabled(ORDER)) { + context.report(ORDER, element, context.getLocation(element), String.format("<%1$s> tag appears after <application> tag", tag), null); + } // Don't complain for *every* element following the <application> tag mSeenApplication = false; |