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

com.android.tools.lint.client.api.IssueRegistry Maven / Gradle / Ivy

There is a newer version: 25.3.0
Show newest version
/*
 * 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.Implementation;
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 com.google.common.collect.Maps;

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
 * 

* 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. */ @Beta public abstract class IssueRegistry { private static List sCategories; private static Map sIdToIssue; private static Map, List> sScopeIssues = Maps.newHashMap(); /** * Creates a new {@linkplain IssueRegistry} */ protected IssueRegistry() { } private static final Implementation DUMMY_IMPLEMENTATION = new Implementation(Detector.class, EnumSet.noneOf(Scope.class)); /** * 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$ "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, DUMMY_IMPLEMENTATION); /** * 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$ "Lint Failure", "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, DUMMY_IMPLEMENTATION); /** * Issue reported when lint is canceled */ @NonNull public static final Issue CANCELLED = Issue.create( "LintCanceled", //$NON-NLS-1$ "Lint Canceled", "Lint canceled by user; the issue report may not be complete.", Category.LINT, 0, Severity.INFORMATIONAL, DUMMY_IMPLEMENTATION); /** * 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 getIssues(); /** * Get an approximate issue count for a given scope. This is just an optimization, * so the number does not have to be accurate. * * @param scope the scope set * @return an approximate ceiling of the number of issues expected for a given scope set */ protected int getIssueCapacity(@NonNull EnumSet scope) { return 20; } /** * Returns all available issues of a given scope (regardless of whether * they are actually enabled for a given configuration etc) * * @param scope the applicable scope set * @return a list of issues */ @NonNull protected List getIssuesForScope(@NonNull EnumSet scope) { List list = sScopeIssues.get(scope); if (list == null) { List issues = getIssues(); if (scope.equals(Scope.ALL)) { list = issues; } else { list = new ArrayList(getIssueCapacity(scope)); for (Issue issue : issues) { // Determine if the scope matches if (issue.getImplementation().isAdequate(scope)) { list.add(issue); } } } sScopeIssues.put(scope, list); } return list; } /** * Creates a list of detectors applicable to the given scope, 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 createDetectors( @NonNull LintClient client, @NonNull Configuration configuration, @NonNull EnumSet scope, @Nullable Map> scopeToDetectors) { List issues = getIssuesForScope(scope); if (issues.isEmpty()) { return Collections.emptyList(); } Set> detectorClasses = new HashSet>(); Map, EnumSet> detectorToScope = new HashMap, EnumSet>(); for (Issue issue : issues) { Implementation implementation = issue.getImplementation(); Class detectorClass = implementation.getDetectorClass(); EnumSet issueScope = implementation.getScope(); if (!detectorClasses.contains(detectorClass)) { // Determine if the issue is enabled if (!configuration.isEnabled(issue)) { continue; } assert implementation.isAdequate(scope); // Ensured by getIssuesForScope above detectorClass = client.replaceDetector(detectorClass); assert detectorClass != null : issue.getId(); detectorClasses.add(detectorClass); } if (scopeToDetectors != null) { EnumSet s = detectorToScope.get(detectorClass); if (s == null) { detectorToScope.put(detectorClass, issueScope); } else if (!s.containsAll(issueScope)) { EnumSet union = EnumSet.copyOf(s); union.addAll(issueScope); detectorToScope.put(detectorClass, union); } } } List detectors = new ArrayList(detectorClasses.size()); for (Class clz : detectorClasses) { try { Detector detector = clz.newInstance(); detectors.add(detector); if (scopeToDetectors != null) { EnumSet union = detectorToScope.get(clz); for (Scope s : union) { List list = scopeToDetectors.get(s); if (list == null) { list = new ArrayList(); 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 category : getCategories()) { if (category.getName().equals(name) || category.getFullName().equals(name)) { return true; } } return false; } /** * Returns the available categories * * @return an iterator for all the categories, never null */ @NonNull public List getCategories() { if (sCategories == null) { final Set categories = new HashSet(); for (Issue issue : getIssues()) { categories.add(issue.getCategory()); } List sorted = new ArrayList(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 issues = getIssues(); sIdToIssue = new HashMap(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. *

* NOTE: This is only intended for testing purposes. */ @VisibleForTesting protected static void reset() { sIdToIssue = null; sCategories = null; sScopeIssues = Maps.newHashMap(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy