/* * Copyright (C) 2013 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; /** * An {@linkplain Implementation} of an {@link Issue} maps to the {@link Detector} * class responsible for analyzing the issue, as well as the {@link Scope} required * by the detector to perform its analysis. * <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 Implementation { private final Class<? extends Detector> mClass; private final EnumSet<Scope> mScope; private EnumSet<Scope>[] mAnalysisScopes; @SuppressWarnings("unchecked") private static final EnumSet<Scope>[] EMPTY = new EnumSet[0]; /** * Creates a new implementation for analyzing one or more issues * * @param detectorClass the class of the detector to find this issue * @param scope the scope of files required to analyze this issue */ @SuppressWarnings("unchecked") public Implementation( @NonNull Class<? extends Detector> detectorClass, @NonNull EnumSet<Scope> scope) { this(detectorClass, scope, EMPTY); } /** * Creates a new implementation for analyzing one or more issues * * @param detectorClass the class of the detector to find this issue * @param scope the scope of files required to analyze this issue * @param analysisScopes optional set of extra scopes the detector is capable of working in */ public Implementation( @NonNull Class<? extends Detector> detectorClass, @NonNull EnumSet<Scope> scope, @NonNull EnumSet<Scope>... analysisScopes) { mClass = detectorClass; mScope = scope; mAnalysisScopes = analysisScopes; } /** * 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 mClass.toString(); } /** * 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; } /** * Returns the sets of scopes required to analyze this issue, or null if all * scopes named by {@link #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 #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. */ @NonNull public EnumSet<Scope>[] getAnalysisScopes() { return mAnalysisScopes; } /** * Returns true if the given scope is adequate for analyzing this issue. * This looks through the analysis scopes (see * {@link #getAnalysisScopes()}) 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 #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 supplying it to * {@link #Implementation(Class, java.util.EnumSet, java.util.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 (scope.containsAll(analysisScope)) { return true; } } } return false; } }