diff options
Diffstat (limited to 'lint')
9 files changed, 336 insertions, 199 deletions
diff --git a/lint/cli/src/com/android/tools/lint/HtmlReporter.java b/lint/cli/src/com/android/tools/lint/HtmlReporter.java index f5b1b25..404d1e2 100644 --- a/lint/cli/src/com/android/tools/lint/HtmlReporter.java +++ b/lint/cli/src/com/android/tools/lint/HtmlReporter.java @@ -26,21 +26,17 @@ import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.Location; import com.android.tools.lint.detector.api.Position; import com.android.tools.lint.detector.api.Severity; -import com.google.common.io.Files; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; +import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; /** * A reporter which emits lint results into an HTML report. @@ -57,19 +53,11 @@ class HtmlReporter extends Reporter { */ private static final int SHOWN_COUNT = SPLIT_LIMIT - 3; - private final Main mClient; - private final File mOutput; - private File mResources; - private boolean mSimpleFormat; - private boolean mBundleResources; - private Map<String, String> mUrlMap; - private Map<File, String> mResourceUrl = new HashMap<File, String>(); - private Map<String, File> mNameToFile = new HashMap<String, File>(); + private final Writer mWriter; HtmlReporter(Main client, File output) throws IOException { - super(new BufferedWriter(new FileWriter(output))); - mClient = client; - mOutput = output; + super(client, output); + mWriter = new BufferedWriter(new FileWriter(output)); } @Override @@ -77,7 +65,7 @@ class HtmlReporter extends Reporter { mWriter.write( "<html>\n" + //$NON-NLS-1$ "<head>\n" + //$NON-NLS-1$ - "<title>Lint Report</title>\n" + //$NON-NLS-1$ + "<title>" + mTitle + "</title>\n" + //$NON-NLS-1$//$NON-NLS-2$ "<style type=\"text/css\">\n" + //$NON-NLS-1$ // CSS stylesheet for the report: @@ -164,7 +152,7 @@ class HtmlReporter extends Reporter { "</head>\n" + //$NON-NLS-1$ "<body>\n" + //$NON-NLS-1$ "<h1>" + //$NON-NLS-1$ - "Lint Report" + + mTitle + "</h1>"); //$NON-NLS-1$ Issue previousIssue = null; @@ -269,6 +257,7 @@ class HtmlReporter extends Reporter { url = writeLocation(warning.file, warning.path, warning.line); } mWriter.write(':'); + mWriter.write(' '); // Is the URL for a single image? If so, place it here near the top // of the error floating on the right. If there are multiple images, @@ -305,6 +294,7 @@ class HtmlReporter extends Reporter { String path = mClient.getDisplayPath(warning.project, l.getFile()); writeLocation(l.getFile(), path, line); mWriter.write(':'); + mWriter.write(' '); mWriter.write("<span class=\"message\">"); //$NON-NLS-1$ appendEscapedText(l.getMessage()); mWriter.write("</span>"); //$NON-NLS-1$ @@ -435,7 +425,6 @@ class HtmlReporter extends Reporter { mWriter.write(Integer.toString(line + 1)); } mWriter.write("</span>"); //$NON-NLS-1$ - mWriter.write(' '); return url; } @@ -578,143 +567,4 @@ class HtmlReporter extends Reporter { } } } - - private String getUrl(File file) { - if (mBundleResources && !mSimpleFormat) { - String url = getRelativeResourceUrl(file); - if (url != null) { - return url; - } - } - - if (mUrlMap != null) { - String path = file.getAbsolutePath(); - try { - // Perform the comparison using URLs such that we properly escape spaces etc. - String pathUrl = URLEncoder.encode(path, "UTF-8"); //$NON-NLS-1$ - for (Map.Entry<String, String> entry : mUrlMap.entrySet()) { - String prefix = entry.getKey(); - String prefixUrl = URLEncoder.encode(prefix, "UTF-8"); //$NON-NLS-1$ - if (pathUrl.startsWith(prefixUrl)) { - String relative = pathUrl.substring(prefixUrl.length()); - return entry.getValue() - + relative.replace("%2F", "/"); //$NON-NLS-1$ //$NON-NLS-2$ - } - } - } catch (UnsupportedEncodingException e) { - // This shouldn't happen for UTF-8 - System.err.println("Invalid URL map specification - " + e.getLocalizedMessage()); - } - } - - return null; - } - - /** Encodes the given String as a safe URL substring, escaping spaces etc */ - private static String encodeUrl(String url) { - try { - return URLEncoder.encode(url, "UTF-8"); //$NON-NLS-1$ - } catch (UnsupportedEncodingException e) { - // This shouldn't happen for UTF-8 - System.err.println("Invalid string " + e.getLocalizedMessage()); - return url; - } - } - - /** Set mapping of path prefixes to corresponding URLs in the HTML report */ - void setUrlMap(Map<String, String> urlMap) { - mUrlMap = urlMap; - } - - /** Gets a pointer to the local resource directory, if any */ - private File getResourceDir() { - if (mResources == null && mBundleResources) { - String fileName = mOutput.getName(); - int dot = fileName.indexOf('.'); - if (dot != -1) { - fileName = fileName.substring(0, dot); - } - - mResources = new File(mOutput.getParentFile(), fileName + "_files"); //$NON-NLS-1$ - if (!mResources.mkdir()) { - mResources = null; - mBundleResources = false; - } - } - - return mResources; - } - - /** Returns a URL to a local copy of the given file, or null */ - private String getRelativeResourceUrl(File file) { - String resource = mResourceUrl.get(file); - if (resource != null) { - return resource; - } - - String name = file.getName(); - if (!endsWith(name, DOT_PNG) || endsWith(name, DOT_9PNG)) { - return null; - } - - // Attempt to make local copy - File resourceDir = getResourceDir(); - if (resourceDir != null) { - String base = file.getName(); - - File path = mNameToFile.get(base); - if (path != null && !path.equals(file)) { - // That filename already exists and is associated with a different path: - // make a new unique version - for (int i = 0; i < 100; i++) { - base = '_' + base; - path = mNameToFile.get(base); - if (path == null || path.equals(file)) { - break; - } - } - } - - File target = new File(resourceDir, base); - try { - Files.copy(file, target); - } catch (IOException e) { - return null; - } - return resourceDir.getName() + '/' + encodeUrl(base); - } - return null; - } - - /** - * Sets whether the report should bundle up resources along with the HTML report. - * This implies a non-simple format (see {@link #setSimpleFormat(boolean)}). - * - * @param bundleResources if true, copy images into a directory relative to - * the report - */ - public void setBundleResources(boolean bundleResources) { - mBundleResources = bundleResources; - mSimpleFormat = false; - } - - /** - * Sets whether the report should use simple formatting (meaning no JavaScript, - * embedded images, etc). - * - * @param simpleFormat whether the formatting should be simple - */ - public void setSimpleFormat(boolean simpleFormat) { - mSimpleFormat = simpleFormat; - } - - /** - * Returns whether the report should use simple formatting (meaning no JavaScript, - * embedded images, etc). - * - * @return whether the report should use simple formatting - */ - public boolean isSimpleFormat() { - return mSimpleFormat; - } } diff --git a/lint/cli/src/com/android/tools/lint/Main.java b/lint/cli/src/com/android/tools/lint/Main.java index 4d734a4..c7fab5e 100644 --- a/lint/cli/src/com/android/tools/lint/Main.java +++ b/lint/cli/src/com/android/tools/lint/Main.java @@ -246,6 +246,22 @@ public class Main extends LintClient { System.exit(ERRNO_INVALIDARGS); } File output = new File(args[++index]); + if (output.isDirectory() || + (!output.exists() && output.getName().indexOf('.') == -1)) { + if (!output.exists()) { + boolean mkdirs = output.mkdirs(); + if (!mkdirs) { + log(null, "Could not create output directory %1$s", output); + System.exit(ERRNO_EXISTS); + } + } + MultiProjectHtmlReporter reporter = new MultiProjectHtmlReporter(this, output); + if (arg.equals(ARG_SIMPLEHTML)) { + reporter.setSimpleFormat(true); + } + mReporter = reporter; + continue; + } if (output.exists()) { boolean delete = output.delete(); if (!delete) { @@ -253,7 +269,7 @@ public class Main extends LintClient { System.exit(ERRNO_EXISTS); } } - if (output.canWrite()) { + if (!output.getParentFile().canWrite()) { System.err.println("Cannot write HTML output file " + output); System.exit(ERRNO_EXISTS); } @@ -386,7 +402,6 @@ public class Main extends LintClient { } files.add(file); } - // TODO: Add flag to point to a file of specific errors to suppress } if (files.size() == 0) { @@ -402,29 +417,28 @@ public class Main extends LintClient { } mReporter = new TextReporter(this, new PrintWriter(System.out, true)); - } else if (mReporter instanceof HtmlReporter) { - HtmlReporter htmlReporter = (HtmlReporter) mReporter; - + } else { if (urlMap == null) { // By default just map from /foo to file:///foo // TODO: Find out if we need file:// on Windows. urlMap = "=file://"; //$NON-NLS-1$ - if (!htmlReporter.isSimpleFormat()) { - htmlReporter.setBundleResources(true); + if (!mReporter.isSimpleFormat()) { + mReporter.setBundleResources(true); } - } - Map<String, String> map = new HashMap<String, String>(); - String[] replace = urlMap.split(","); //$NON-NLS-1$ - for (String s : replace) { - String[] v = s.split("="); //$NON-NLS-1$ - if (v.length != 2) { - System.err.println( - "The URL map argument must be of the form 'path_prefix=url_prefix'"); - System.exit(ERRNO_INVALIDARGS); + } else { + Map<String, String> map = new HashMap<String, String>(); + String[] replace = urlMap.split(","); //$NON-NLS-1$ + for (String s : replace) { + String[] v = s.split("="); //$NON-NLS-1$ + if (v.length != 2) { + System.err.println( + "The URL map argument must be of the form 'path_prefix=url_prefix'"); + System.exit(ERRNO_INVALIDARGS); + } + map.put(v[0], v[1]); } - map.put(v[0], v[1]); + mReporter.setUrlMap(map); } - htmlReporter.setUrlMap(map); } Lint analyzer = new Lint(registry, this); @@ -644,7 +658,9 @@ public class Main extends LintClient { ARG_NOLINES, "Do not include the source file lines with errors " + "in the output. By default, the error output includes snippets of source code " + "on the line containing the error, but this flag turns it off.", - ARG_HTML + " <filename>", "Create an HTML report instead.", + ARG_HTML + " <filename>", "Create an HTML report instead. If the filename is a " + + "directory (or a new filename without an extension), lint will create a " + + "separate report for each scanned project.", ARG_URL + " filepath=url", "Add links to HTML report, replacing local " + "path prefixes with url prefix. The mapping can be a comma-separated list of " + "path prefixes to corresponding URL prefixes, such as " + @@ -918,18 +934,18 @@ public class Main extends LintClient { if (lint.getPhase() > 1) { System.out.print(String.format( "\nScanning %1$s (Phase %2$d): ", - context.getProject().getDir().getName(), + context.getProject().getName(), lint.getPhase())); } else { System.out.print(String.format( "\nScanning %1$s: ", - context.getProject().getDir().getName())); + context.getProject().getName())); } break; case SCANNING_LIBRARY_PROJECT: System.out.print(String.format( "\n - %1$s: ", - context.getProject().getDir().getName())); + context.getProject().getName())); break; case SCANNING_FILE: System.out.print('.'); diff --git a/lint/cli/src/com/android/tools/lint/MultiProjectHtmlReporter.java b/lint/cli/src/com/android/tools/lint/MultiProjectHtmlReporter.java new file mode 100644 index 0000000..12dc357 --- /dev/null +++ b/lint/cli/src/com/android/tools/lint/MultiProjectHtmlReporter.java @@ -0,0 +1,82 @@ +/* + * 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; + +import com.android.tools.lint.detector.api.Project; +import com.android.tools.lint.detector.api.Severity; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * "Multiplexing" reporter which allows output to be split up into a separate + * report for each separate project + */ +class MultiProjectHtmlReporter extends Reporter { + MultiProjectHtmlReporter(Main client, File dir) { + super(client, dir); + } + + @Override + void write(int errorCount, int warningCount, List<Warning> allIssues) throws IOException { + Map<Project, List<Warning>> projectToWarnings = new HashMap<Project, List<Warning>>(); + for (Warning warning : allIssues) { + List<Warning> list = projectToWarnings.get(warning.project); + if (list == null) { + list = new ArrayList<Warning>(); + projectToWarnings.put(warning.project, list); + } + list.add(warning); + } + for (Project project : projectToWarnings.keySet()) { + // TODO: Can I get the project name from the Android manifest file instead? + String projectName = project.getName(); + File output = new File(mOutput, projectName + ".html"); //$NON-NLS-1$ + if (output.exists()) { + boolean deleted = output.delete(); + if (!deleted) { + mClient.log(null, "Could not delete old file %1$s", output); + continue; + } + } + if (!output.getParentFile().canWrite()) { + mClient.log(null, "Cannot write output file %1$s", output); + continue; + } + HtmlReporter reporter = new HtmlReporter(mClient, output); + reporter.setBundleResources(mBundleResources); + reporter.setSimpleFormat(mSimpleFormat); + reporter.setTitle(String.format("Lint Report for %1$s", projectName)); + + List<Warning> issues = projectToWarnings.get(project); + errorCount = 0; + warningCount = 0; + for (Warning warning: issues) { + if (warning.severity == Severity.ERROR) { + errorCount++; + } else if (warning.severity == Severity.WARNING) { + warningCount++; + } + } + reporter.write(errorCount, warningCount, issues); + } + } +} diff --git a/lint/cli/src/com/android/tools/lint/Reporter.java b/lint/cli/src/com/android/tools/lint/Reporter.java index 43cd048..e488140 100644 --- a/lint/cli/src/com/android/tools/lint/Reporter.java +++ b/lint/cli/src/com/android/tools/lint/Reporter.java @@ -16,17 +16,190 @@ package com.android.tools.lint; +import static com.android.tools.lint.detector.api.LintConstants.DOT_9PNG; +import static com.android.tools.lint.detector.api.LintConstants.DOT_PNG; +import static com.android.tools.lint.detector.api.LintUtils.endsWith; + +import com.google.common.io.Files; + +import java.io.File; import java.io.IOException; -import java.io.Writer; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** A reporter is an output generator for lint warnings */ abstract class Reporter { - protected Writer mWriter; + protected final Main mClient; + protected final File mOutput; + protected String mTitle = "Lint Report"; + protected boolean mSimpleFormat; + protected boolean mBundleResources; + protected Map<String, String> mUrlMap; + protected File mResources; + protected Map<File, String> mResourceUrl = new HashMap<File, String>(); + protected Map<String, File> mNameToFile = new HashMap<String, File>(); - Reporter(Writer writer) { - mWriter = writer; + abstract void write(int errorCount, int warningCount, List<Warning> issues) throws IOException; + + protected Reporter(Main client, File output) { + mClient = client; + mOutput = output; } - abstract void write(int errorCount, int warningCount, List<Warning> issues) throws IOException; + /** + * Sets the report title + * + * @param title the title of the report + */ + void setTitle(String title) { + mTitle = title; + } + + /** @return the title of the report */ + String getTitle() { + return mTitle; + } + + /** + * Sets whether the report should bundle up resources along with the HTML report. + * This implies a non-simple format (see {@link #setSimpleFormat(boolean)}). + * + * @param bundleResources if true, copy images into a directory relative to + * the report + */ + void setBundleResources(boolean bundleResources) { + mBundleResources = bundleResources; + mSimpleFormat = false; + } + + /** + * Sets whether the report should use simple formatting (meaning no JavaScript, + * embedded images, etc). + * + * @param simpleFormat whether the formatting should be simple + */ + void setSimpleFormat(boolean simpleFormat) { + mSimpleFormat = simpleFormat; + } + + /** + * Returns whether the report should use simple formatting (meaning no JavaScript, + * embedded images, etc). + * + * @return whether the report should use simple formatting + */ + boolean isSimpleFormat() { + return mSimpleFormat; + } + + + String getUrl(File file) { + if (mBundleResources && !mSimpleFormat) { + String url = getRelativeResourceUrl(file); + if (url != null) { + return url; + } + } + + if (mUrlMap != null) { + String path = file.getAbsolutePath(); + try { + // Perform the comparison using URLs such that we properly escape spaces etc. + String pathUrl = URLEncoder.encode(path, "UTF-8"); //$NON-NLS-1$ + for (Map.Entry<String, String> entry : mUrlMap.entrySet()) { + String prefix = entry.getKey(); + String prefixUrl = URLEncoder.encode(prefix, "UTF-8"); //$NON-NLS-1$ + if (pathUrl.startsWith(prefixUrl)) { + String relative = pathUrl.substring(prefixUrl.length()); + return entry.getValue() + + relative.replace("%2F", "/"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } catch (UnsupportedEncodingException e) { + // This shouldn't happen for UTF-8 + System.err.println("Invalid URL map specification - " + e.getLocalizedMessage()); + } + } + + return null; + } + + /** Encodes the given String as a safe URL substring, escaping spaces etc */ + static String encodeUrl(String url) { + try { + return URLEncoder.encode(url, "UTF-8"); //$NON-NLS-1$ + } catch (UnsupportedEncodingException e) { + // This shouldn't happen for UTF-8 + System.err.println("Invalid string " + e.getLocalizedMessage()); + return url; + } + } + + /** Set mapping of path prefixes to corresponding URLs in the HTML report */ + void setUrlMap(Map<String, String> urlMap) { + mUrlMap = urlMap; + } + + /** Gets a pointer to the local resource directory, if any */ + File getResourceDir() { + if (mResources == null && mBundleResources) { + String fileName = mOutput.getName(); + int dot = fileName.indexOf('.'); + if (dot != -1) { + fileName = fileName.substring(0, dot); + } + + mResources = new File(mOutput.getParentFile(), fileName + "_files"); //$NON-NLS-1$ + if (!mResources.mkdir()) { + mResources = null; + mBundleResources = false; + } + } + + return mResources; + } + + /** Returns a URL to a local copy of the given file, or null */ + protected String getRelativeResourceUrl(File file) { + String resource = mResourceUrl.get(file); + if (resource != null) { + return resource; + } + + String name = file.getName(); + if (!endsWith(name, DOT_PNG) || endsWith(name, DOT_9PNG)) { + return null; + } + + // Attempt to make local copy + File resourceDir = getResourceDir(); + if (resourceDir != null) { + String base = file.getName(); + + File path = mNameToFile.get(base); + if (path != null && !path.equals(file)) { + // That filename already exists and is associated with a different path: + // make a new unique version + for (int i = 0; i < 100; i++) { + base = '_' + base; + path = mNameToFile.get(base); + if (path == null || path.equals(file)) { + break; + } + } + } + + File target = new File(resourceDir, base); + try { + Files.copy(file, target); + } catch (IOException e) { + return null; + } + return resourceDir.getName() + '/' + encodeUrl(base); + } + return null; + } }
\ No newline at end of file diff --git a/lint/cli/src/com/android/tools/lint/TextReporter.java b/lint/cli/src/com/android/tools/lint/TextReporter.java index 8157f7c..66f0e56 100644 --- a/lint/cli/src/com/android/tools/lint/TextReporter.java +++ b/lint/cli/src/com/android/tools/lint/TextReporter.java @@ -25,11 +25,11 @@ import java.util.List; /** A reporter which emits lint warnings as plain text strings */ class TextReporter extends Reporter { - private Main mClient; + private final Writer mWriter; TextReporter(Main client, Writer writer) { - super(writer); - mClient = client; + super(client, null); + mWriter = writer; } @Override diff --git a/lint/cli/src/com/android/tools/lint/XmlReporter.java b/lint/cli/src/com/android/tools/lint/XmlReporter.java index 4c92810..4de1dd7 100644 --- a/lint/cli/src/com/android/tools/lint/XmlReporter.java +++ b/lint/cli/src/com/android/tools/lint/XmlReporter.java @@ -31,13 +31,11 @@ import java.util.List; * A reporter which emits lint results into an XML report. */ class XmlReporter extends Reporter { - private final File mOutput; - private final Main mClient; + private final Writer mWriter; XmlReporter(Main client, File output) throws IOException { - super(new BufferedWriter(Files.newWriter(output, Charsets.UTF_8))); - mClient = client; - mOutput = output; + super(client, output); + mWriter = new BufferedWriter(Files.newWriter(output, Charsets.UTF_8)); } @Override 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 index 2d2d146..26f69bb 100644 --- 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 @@ -66,6 +66,7 @@ public class Project { private int mMinSdk = 1; private int mTargetSdk = -1; private boolean mLibrary; + private String mName; /** The SDK info, if any */ private SdkInfo mSdkInfo; @@ -492,4 +493,19 @@ public class Project { return null; } + + /** + * 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; + } } diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LocationTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LocationTest.java index b9e1acd..6404202 100644 --- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LocationTest.java +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/LocationTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * - * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * 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.eclipse.org/org/documents/epl-v10.php + * 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, @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.tools.lint.detector.api; import java.io.File; diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/ScopeTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/ScopeTest.java index c92eff9..e95c502 100644 --- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/ScopeTest.java +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/detector/api/ScopeTest.java @@ -1,11 +1,11 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * - * Licensed under the Eclipse Public License, Version 1.0 (the "License"); + * 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.eclipse.org/org/documents/epl-v10.php + * 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, @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.android.tools.lint.detector.api; import java.util.EnumSet; |