| /* |
| * 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.tools.lint.detector.api.TextFormat.RAW; |
| |
| import com.android.annotations.NonNull; |
| import com.android.tools.lint.client.api.Configuration; |
| import com.google.common.annotations.Beta; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| 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 final String mId; |
| private final String mBriefDescription; |
| private final String mExplanation; |
| private final Category mCategory; |
| private final int mPriority; |
| private final Severity mSeverity; |
| private Object mMoreInfoUrls; |
| private boolean mEnabledByDefault = true; |
| private Implementation mImplementation; |
| |
| // Use factory methods |
| private Issue( |
| @NonNull String id, |
| @NonNull String shortDescription, |
| @NonNull String explanation, |
| @NonNull Category category, |
| int priority, |
| @NonNull Severity severity, |
| @NonNull Implementation implementation) { |
| assert !shortDescription.isEmpty(); |
| assert !explanation.isEmpty(); |
| |
| mId = id; |
| mBriefDescription = shortDescription; |
| mExplanation = explanation; |
| mCategory = category; |
| mPriority = priority; |
| mSeverity = severity; |
| mImplementation = implementation; |
| } |
| |
| /** |
| * Creates a new issue. The description strings can use some simple markup; |
| * see the {@link TextFormat#RAW} documentation |
| * for details. |
| * |
| * @param id the fixed id of the issue |
| * @param briefDescription short summary (typically 5-6 words or less), typically |
| * describing the <b>problem</b> rather than the <b>fix</b> |
| * (e.g. "Missing minSdkVersion") |
| * @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 implementation the default implementation for this issue |
| * @return a new {@link Issue} |
| */ |
| @NonNull |
| public static Issue create( |
| @NonNull String id, |
| @NonNull String briefDescription, |
| @NonNull String explanation, |
| @NonNull Category category, |
| int priority, |
| @NonNull Severity severity, |
| @NonNull Implementation implementation) { |
| return new Issue(id, briefDescription, explanation, category, priority, |
| severity, implementation); |
| } |
| |
| /** |
| * For compatibility with older custom rules) |
| * |
| * @deprecated Use {@link #create(String, String, String, Category, int, Severity, Implementation)} instead |
| */ |
| @NonNull |
| @Deprecated |
| public static Issue create( |
| @NonNull String id, |
| @NonNull String briefDescription, |
| @SuppressWarnings("UnusedParameters") @NonNull String description, |
| @NonNull String explanation, |
| @NonNull Category category, |
| int priority, |
| @NonNull Severity severity, |
| @NonNull Implementation implementation) { |
| return new Issue(id, briefDescription, explanation, category, priority, |
| severity, implementation); |
| } |
| |
| /** |
| * 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 (in a couple of words) describes these errors |
| * |
| * @return a brief summary of the issue, never null, never empty |
| */ |
| @NonNull |
| public String getBriefDescription(@NonNull TextFormat format) { |
| return RAW.convertTo(mBriefDescription, format); |
| } |
| |
| /** |
| * 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()}. |
| * |
| * @param format the format to write the format as |
| * @return an explanation of the issue, never null, never empty |
| */ |
| @NonNull |
| public String getExplanation(@NonNull TextFormat format) { |
| return RAW.convertTo(mExplanation, format); |
| } |
| |
| /** |
| * 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 |
| */ |
| @NonNull |
| public List<String> getMoreInfo() { |
| if (mMoreInfoUrls == null) { |
| return Collections.emptyList(); |
| } else if (mMoreInfoUrls instanceof String) { |
| return Collections.singletonList((String) mMoreInfoUrls); |
| } else { |
| assert mMoreInfoUrls instanceof List; |
| //noinspection unchecked |
| return (List<String>) mMoreInfoUrls; |
| } |
| } |
| |
| /** |
| * Adds a more info URL string |
| * |
| * @param moreInfoUrl url string |
| * @return this, for constructor chaining |
| */ |
| @NonNull |
| public Issue addMoreInfo(@NonNull String moreInfoUrl) { |
| // Nearly all issues supply at most a single URL, so don't bother with |
| // lists wrappers for most of these issues |
| if (mMoreInfoUrls == null) { |
| mMoreInfoUrls = moreInfoUrl; |
| } else if (mMoreInfoUrls instanceof String) { |
| String existing = (String) mMoreInfoUrls; |
| List<String> list = new ArrayList<String>(2); |
| list.add(existing); |
| list.add(moreInfoUrl); |
| mMoreInfoUrls = list; |
| } else { |
| assert mMoreInfoUrls instanceof List; |
| //noinspection unchecked |
| ((List<String>) mMoreInfoUrls).add(moreInfoUrl); |
| } |
| return this; |
| } |
| |
| /** |
| * 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 implementation for the given issue |
| * |
| * @return the implementation for this issue |
| */ |
| @NonNull |
| public Implementation getImplementation() { |
| return mImplementation; |
| } |
| |
| /** |
| * Sets the implementation for the given issue. This is typically done by |
| * IDEs that can offer a replacement for a given issue which performs better |
| * or in some other way works better within the IDE. |
| * |
| * @param implementation the new implementation to use |
| */ |
| public void setImplementation(@NonNull Implementation implementation) { |
| mImplementation = implementation; |
| } |
| |
| /** |
| * 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(@NonNull Issue other) { |
| return getId().compareTo(other.getId()); |
| } |
| |
| /** |
| * 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; |
| } |
| |
| @Override |
| public String toString() { |
| return mId; |
| } |
| } |