Add the lint guide to the androidx repo

Make the lint guide published on go/androidx also available publically
inside of the repo. This way we have some guidance for external devs
looking to contribute lint rules.

BYPASS_INCLUSIVE_LANGUAGE_REASON=This is the branch name

Test: ./gradlew bOS

Change-Id: I957b4fd43c2171c86eb142982bc603820053aa76
diff --git a/docs/LINT.md b/docs/LINT.md
new file mode 100644
index 0000000..5916b6d
--- /dev/null
+++ b/docs/LINT.md
@@ -0,0 +1,647 @@
+# Adding custom Lint checks
+
+## Getting started
+
+Lint is a static analysis tool that checks Android project source files. Lint
+checks come with Android Studio by default, but custom Lint checks can be added
+to specific library modules to help avoid potential bugs and encourage best code
+practices.
+
+### Create a module
+
+If this is the first Lint rule for a library, you will need to create a module
+by doing the following:
+
+Add a new `ignore` rule to the `PublishDocsRules.kt` file to prevent the module
+from showing up in published docs:
+
+```
+ignore(LibraryGroups.MyLibrary.group, "mylibrary-lint")
+```
+
+Include the project in the top-level `settings.gradle` file so that it shows up
+in Android Studio's list of modules:
+
+```
+includeProject(":mylibrary:mylibrary-lint", "mylibrary/mylibrary-lint")
+```
+
+Manually create a new module in `frameworks/support` (preferably in the
+directory you are making lint rules for). In the new module, add a `src` folder
+and a `build.gradle` file containing the needed dependencies.
+
+build.gradle
+
+```
+import static androidx.build.dependencies.DependenciesKt.*
+import androidx.build.AndroidXExtension
+import androidx.build.CompilationTarget
+import androidx.build.LibraryGroups
+import androidx.build.LibraryVersions
+import androidx.build.SdkHelperKt
+import androidx.build.Publish
+
+plugins {
+    id("AndroidXPlugin")
+    id("kotlin")
+}
+
+dependencies {
+    // compileOnly because we use lintChecks and it doesn't allow other types of deps
+    // this ugly hack exists because of b/63873667
+    if (rootProject.hasProperty("android.injected.invoked.from.ide")) {
+        compileOnly LINT_API_LATEST
+    } else {
+        compileOnly LINT_API_MIN
+    }
+    compileOnly KOTLIN_STDLIB
+
+    testImplementation KOTLIN_STDLIB
+    testImplementation LINT_CORE
+    testImplementation LINT_TESTS
+}
+
+androidx {
+    name = "Android MyLibrary Lint Checks"
+    toolingProject = true
+    publish = Publish.NONE
+    mavenVersion = LibraryVersions.MYLIBRARY
+    mavenGroup = LibraryGroups.MYLIBRARY
+    inceptionYear = "2019"
+    description = "Android MyLibrary Lint Checks"
+    url = AndroidXExtension.ARCHITECTURE_URL
+    compilationTarget = CompilationTarget.HOST
+}
+```
+
+Build the project and a `mylibrary-lint.iml` file should be created
+automatically in the module directory.
+
+### Issue registry
+
+Your new module will need to have a registry that contains a list of all of the
+checks to be performed on the library. There is an
+[`IssueRegistry`](https://cs.android.com/android/platform/superproject/+/master:tools/base/lint/libs/lint-api/src/main/java/com/android/tools/lint/client/api/IssueRegistry.java)
+class provided by the tools team. Extend this class into your own
+`IssueRegistry` class, and provide it with the issues in the module.
+
+MyLibraryIssueRegistry.kt
+
+```kotlin
+class MyLibraryIssueRegistry : IssueRegistry() {
+    override val api = 6
+    override val minApi = CURRENT_API
+    override val issues get() = listOf(MyLibraryDetector.ISSUE)
+}
+```
+
+The maximum version this Lint check will will work with is defined by `api = 6`,
+where versions 0-6 correspond to Lint/Studio versions 3.0-3.6.
+
+`minApi = CURRENT_API` sets the lowest version of Lint that this will work with.
+
+`CURRENT_API` is defined by the Lint API version against which your project is
+compiled, as defined in the module's `build.gradle` file. Jetpack Lint modules
+should compile using Lint API version 3.3 defined in
+[Dependencies.kt](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:buildSrc/src/main/kotlin/androidx/build/dependencies/Dependencies.kt;l=84).
+
+We guarantee that our Lint checks work with versions 3.3-3.6 by running our
+tests with both versions 3.3 and 3.6. For newer versions of Android Studio (and
+consequently, Lint) the API variable will need to be updated.
+
+The `IssueRegistry` requires a list of all of the issues to check. You must
+override the `IssueRegistry.getIssues()` method. Here, we override that method
+with a Kotlin `get()` property delegate:
+
+[Example IssueRegistry Implementation](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:fragment/fragment-lint/src/main/java/androidx/fragment/lint/FragmentIssueRegistry.kt)
+
+There are 4 primary types of Lint checks:
+
+1.  Code - Applied to source code, ex. `.java` and `.kt` files
+1.  XML - Applied to XML resource files
+1.  Android Manifest - Applied to `AndroidManifest.xml`
+1.  Gradle - Applied to Gradle configuration files, ex. `build.gradle`
+
+It is also possible to apply Lint checks to compiled bytecode (`.class` files)
+or binary resource files like images, but these are less common.
+
+## PSI & UAST mapping
+
+To view the PSI structure of any file in Android Studio, use the
+[PSI Viewer](https://www.jetbrains.com/help/idea/psi-viewer.html) located in
+`Tools > View PSI Structure`. The PSI Viewer should be enabled by default on the
+Android Studio configuration loaded by `studiow` in `androidx-master-dev`. If it
+is not available under `Tools`, you must enable it by adding the line
+`idea.is.internal=true` to `idea.properties.`
+
+<table>
+  <tr>
+   <td><strong>PSI</strong>
+   </td>
+   <td><strong>UAST</strong>
+   </td>
+  </tr>
+  <tr>
+   <td>PsiAnnotation
+   </td>
+   <td>UAnnotation
+   </td>
+  </tr>
+  <tr>
+   <td>PsiAnonymousClass
+   </td>
+   <td>UAnonymousClass
+   </td>
+  </tr>
+  <tr>
+   <td>PsiArrayAccessExpression
+   </td>
+   <td>UArrayAccessExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiBinaryExpression
+   </td>
+   <td>UArrayAccesExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiCallExpression
+   </td>
+   <td>UCallExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiCatchSection
+   </td>
+   <td>UCatchClause
+   </td>
+  </tr>
+  <tr>
+   <td>PsiClass
+   </td>
+   <td>UClass
+   </td>
+  </tr>
+  <tr>
+   <td>PsiClassObjectAccessExpression
+   </td>
+   <td>UClassLiteralExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiConditionalExpression
+   </td>
+   <td>UIfExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiDeclarationStatement
+   </td>
+   <td>UDeclarationExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiDoWhileStatement
+   </td>
+   <td>UDoWhileExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiElement
+   </td>
+   <td>UElement
+   </td>
+  </tr>
+  <tr>
+   <td>PsiExpression
+   </td>
+   <td>UExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiForeachStatement
+   </td>
+   <td>UForEachExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiIdentifier
+   </td>
+   <td>USimpleNameReferenceExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiLiteral
+   </td>
+   <td>ULiteralExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiLocalVariable
+   </td>
+   <td>ULocalVariable
+   </td>
+  </tr>
+  <tr>
+   <td>PsiMethod
+   </td>
+   <td>UMethod
+   </td>
+  </tr>
+  <tr>
+   <td>PsiMethodCallExpression
+   </td>
+   <td>UCallExpression
+   </td>
+  </tr>
+  <tr>
+   <td>PsiParameter
+   </td>
+   <td>UParameter
+   </td>
+  </tr>
+</table>
+
+## Code detector
+
+These are Lint checks that will apply to source code files -- primarily Java and
+Kotlin, but can also be used for other similar file types. All code detectors
+that analyze Java or Kotlin files should implement the
+[SourceCodeScanner](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/SourceCodeScanner.kt).
+
+### API surface
+
+#### Calls to specific methods
+
+##### getApplicableMethodNames
+
+This defines the list of methods where lint will call the visitMethodCall
+callback.
+
+```kotlin
+override fun getApplicableMethodNames(): List<String>? = listOf(METHOD_NAMES)
+```
+
+##### visitMethodCall
+
+This defines the callback that Lint will call when it encounters a call to an
+applicable method.
+
+```kotlin
+override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {}
+```
+
+#### Calls to specific class instantiations
+
+##### getApplicableConstructorTypes
+
+```kotlin
+override fun getApplicableConstructorTypes(): List<String>? = listOf(CLASS_NAMES)
+```
+
+##### visitConstructor
+
+```kotlin
+override fun visitConstructor(context: JavaContext, node: UCallExpression, method: PsiMethod) {}
+```
+
+#### Classes that extend given superclasses
+
+##### getApplicableSuperClasses
+
+```kotlin
+override fun applicableSuperClasses(): List<String>? = listOf(CLASS_NAMES)
+```
+
+##### visitClass
+
+```kotlin
+override fun visitClass(context: JavaContext, declaration: UClass) {}
+```
+
+#### Call graph support
+
+It is possible to perform analysis on the call graph of a project. However, this
+is highly resource intensive since it generates a single call graph of the
+entire project and should only be used for whole project analysis. To perform
+this analysis you must enable call graph support by overriding the
+`isCallGraphRequired` method and access the call graph with the
+`analyzeCallGraph(context: Context, callGraph: CallGraphResult)` callback
+method.
+
+For performing less resource intensive, on-the-fly analysis it is best to
+recursively analyze method bodies. However, when doing this there should be a
+depth limit on the exploration. If possible, lint should also not explore within
+files that are currently not open in studio.
+
+### Method call analysis
+
+#### resolve()
+
+Resolves into a `UCallExpression` or `UMethod` to perform analysis requiring the
+method body or containing class.
+
+#### ReceiverType
+
+Each `UCallExpression` has a `receiverType` corresponding to the `PsiType` of
+the receiver of the method call.
+
+```kotlin
+public abstract class LiveData<T> {
+    public void observe() {}
+}
+
+public abstract class MutableLiveData<T> extends LiveData<T> {}
+
+MutableLiveData<String> liveData = new MutableLiveData<>();
+liveData.observe() // receiverType = PsiType<MutableLiveData>
+```
+
+#### Kotlin named parameter mapping
+
+`JavaEvaluator`contains a helper method `computeArgumentMapping(call:
+UCallExpression, method: PsiMethod)` that creates a mapping between method call
+parameters and the corresponding resolved method arguments, accounting for
+Kotlin named parameters.
+
+```kotlin
+override fun visitMethodCall(context: JavaContext, node: UCallExpression,
+    method: PsiMethod) {
+    val argMap: Map<UExpression, PsiParameter> = context.evaluator.computArgumentMapping(node, psiMethod)
+}
+```
+
+### Testing
+
+Because the `LintDetectorTest` API does not have access to library classes and
+methods, you must implement stubs for any necessary classes and include these as
+additional files in your test cases. For example, if a lint check involves
+Fragment's `getViewLifecycleOwner` and `onViewCreated` methods, then we must
+create a stub for this:
+
+```
+java("""
+    package androidx.fragment.app;
+
+    import androidx.lifecycle.LifecycleOwner;
+
+    public class Fragment {
+        public LifecycleOwner getViewLifecycleOwner() {}
+        public void onViewCreated() {}
+    }
+""")
+```
+
+Since this class also depends on the `LifecycleOwner` class it is necessary to
+create another stub for this.
+
+## XML resource detector
+
+These are Lint rules that will apply to resource files including `anim`,
+`layout`, `values`, etc. Lint rules being applied to resource files should
+extend
+[`ResourceXmlDetector`](https://cs.android.com/android/platform/superproject/+/master:tools/base/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/ResourceXmlDetector.java).
+The `Detector` must define the issue it is going to detect, most commonly as a
+static variable of the class.
+
+```kotlin
+companion object {
+    val ISSUE = Issue.create(
+        id = "TitleOfMyIssue",
+        briefDescription = "Short description of issue. This will be what the studio inspection menu shows",
+        explanation = """Here is where you define the reason that this lint rule exists in detail.""",
+        category = Category.CORRECTNESS,
+        severity = Severity.LEVEL,
+        implementation = Implementation(
+            MyIssueDetector::class.java, Scope.RESOURCE_FILE_SCOPE
+        ),
+        androidSpecific = true
+    ).addMoreInfo(
+        "https://linkToMoreInfo.com"
+    )
+}
+```
+
+### API surface
+
+The following methods can be overridden:
+
+```kotlin
+appliesTo(folderType: ResourceFolderType)
+getApplicableElements()
+visitElement(context: XmlContext, element: Element)
+```
+
+#### appliesTo
+
+This determines the
+[ResourceFolderType](https://cs.android.com/android/platform/superproject/+/master:tools/base/layoutlib-api/src/main/java/com/android/resources/ResourceFolderType.java)
+that the check will run against.
+
+```kotlin
+override fun appliesTo(folderType: ResourceFolderType): Boolean {
+    return folderType == ResourceFolderType.TYPE
+}
+```
+
+#### getApplicableElements
+
+This defines the list of elements where Lint will call your visitElement
+callback method when encountered.
+
+```kotlin
+override fun getApplicableElements(): Collection<String>? = Collections.singleton(ELEMENT)
+```
+
+#### visitElement
+
+This defines the behavior when an applicable element is found. Here you normally
+place the actions you want to take if a violation of the Lint check is found.
+
+```kotlin
+override fun visitElement(context: XmlContext, element: Element) {
+    context.report(
+        ISSUE,
+        context.getNameLocation(element),
+        "My issue message",
+        fix().replace()
+            .text(ELEMENT)
+            .with(REPLACEMENT TEXT)
+            .build()
+    )
+}
+```
+
+In this instance, the call to `report()` takes the definition of the issue, the
+location of the element that has the issue, the message to display on the
+element, as well as a quick fix. In this case we replace our element text with
+some other text.
+
+[Example Detector Implementation](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:fragment/fragment-lint/src/main/java/androidx/fragment/lint/FragmentTagDetector.kt)
+
+### Testing
+
+You need tests for two things. First, you must test that the API Lint version is
+properly set. That is done with a simple `ApiLintVersionTest` class. It asserts
+the api version code set earlier in the `IssueRegistry()` class. This test
+intentionally fails in the IDE because different Lint API versions are used in
+the studio and command line.
+
+Example `ApiLintVersionTest`:
+
+```kotlin
+class ApiLintVersionsTest {
+
+    @Test
+    fun versionsCheck() {
+        val registry = MyLibraryIssueRegistry()
+        assertThat(registry.api).isEqualTo(CURRENT_API)
+        assertThat(registry.minApi).isEqualTo(3)
+    }
+}
+```
+
+Next, you must test the `Detector` class. The Tools team provides a
+[`LintDetectorTest`](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-tests/src/main/java/com/android/tools/lint/checks/infrastructure/LintDetectorTest.java)
+class that should be extended. Override `getDetector()` to return an instance of
+the `Detector` class:
+
+```kotlin
+override fun getDetector(): Detector = MyLibraryDetector()
+```
+
+Override `getIssues()` to return the list of Detector Issues:
+
+```kotlin
+getIssues(): MutableList<Issue> = mutableListOf(MyLibraryDetector.ISSUE)
+```
+
+[`LintDetectorTest`](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-tests/src/main/java/com/android/tools/lint/checks/infrastructure/LintDetectorTest.java)
+provides a `lint()` method that returns a
+[`TestLintTask`](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-tests/src/main/java/com/android/tools/lint/checks/infrastructure/TestLintTask.java).
+`TestLintTask` is a builder class for setting up lint tests. Call the `files()`
+method and provide an `.xml` test file, along with a file stub. After completing
+the set up, call `run()` which returns a
+[`TestLintResult`](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-tests/src/main/java/com/android/tools/lint/checks/infrastructure/TestLintResult.kt).
+`TestLintResult` provides methods for checking the outcome of the provided
+`TestLintTask`. `ExpectClean()` means the output is expected to be clean because
+the lint rule was followed. `Expect()` takes a string literal of the expected
+output of the `TestLintTask` and compares the actual result to the input string.
+If a quick fix was implemented, you can check that the fix is correct by calling
+`checkFix()` and providing the expected output file stub.
+
+[TestExample](https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:fragment/fragment-lint/src/test/java/androidx/fragment/lint/FragmentTagDetectorTest.kt)
+
+## Android manifest detector
+
+Lint checks targeting `AndroidManifest.xml` files should implement the
+[XmlScanner](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/XmlScanner.kt)
+and define target scope in issues as `Scope.MANIFEST`
+
+## Gradle detector
+
+Lint checks targeting Gradle configuration files should implement the
+[GradleScanner](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api/GradleScanner.kt)
+and define target scope in issues as `Scope.GRADLE_SCOPE`
+
+### API surface
+
+#### checkDslPropertyAssignment
+
+Analyzes each DSL property assignment, providing the property and value strings.
+
+```kotlin
+fun checkDslPropertyAssignment(
+    context: GradleContext,
+    property: String,
+    value: String,
+    parent: String,
+    parentParent: String?,
+    propertyCookie: Any,
+    valueCookie: Any,
+    statementCookie: Any
+) {}
+```
+
+The property, value, and parent string parameters provided by this callback are
+the literal values in the gradle file. Any string values in the Gradle file will
+be quote enclosed in the value parameter. Any constant values cannot be resolved
+to their values.
+
+The cookie parameters should be used for reporting Lint errors. To report an
+issue on the value, use `context.getLocation(statementCookie)`.
+
+## Enabling Lint for a library
+
+Once the Lint module is implemented we need to enable it for the desired
+library. This can be done by adding a `lintPublish` rule to the `build.gradle`
+of the library the Lint check should apply to.
+
+```
+lintPublish(project(':mylibrary:mylibrary-lint'))
+```
+
+This adds a `lint.jar` file into the `.aar` bundle of the desired library.
+
+Then we should add a `com.android.tools.lint.client.api.IssueRegistry` file in
+`main > resources > META-INF > services`. The file should contain a single line
+that has the `IssueRegistry` class name with the full path. This class can
+contain more than one line if the module contains multiple registries.
+
+```
+androidx.mylibrary.lint.MyLibraryIssueRegistry
+```
+
+## Advanced topics:
+
+### Analyzing multiple different file types
+
+Sometimes it is necessary to implement multiple different scanners in a Lint
+detector. For example, the
+[Unused Resource](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/UnusedResourceDetector.java)
+Lint check implements an XML and SourceCode Scanner in order to determine if
+resources defined in XML files are ever references in the Java/Kotlin source
+code.
+
+#### File type iteration order
+
+The Lint system processes files in a predefined order:
+
+1.  Manifests
+1.  Android XML Resources (alphabetical by folder type)
+1.  Java & Kotlin
+1.  Bytecode
+1.  Gradle
+
+### Multi-pass analysis
+
+It is often necessary to process the sources more than once. This can be done by
+using `context.driver.requestRepeat(detector, scope)`.
+
+## Useful classes/packages
+
+### [`SdkConstants`](https://cs.android.com/android/platform/superproject/+/master:tools/base/common/src/main/java/com/android/SdkConstants.java;l=38?q=SdkCon)
+
+Contains most of the canonical names for android core library classes, as well
+as XML tag names.
+
+## Helpful links
+
+[Studio Lint Rules](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks)
+
+[Lint Detectors and Scanners Source Code](https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-api/src/main/java/com/android/tools/lint/detector/api)
+
+[Creating Custom Link Checks (external)](https://twitter.com/alexjlockwood/status/1176675045281693696)
+
+[Android Custom Lint Rules by Tor](https://github.com/googlesamples/android-custom-lint-rules)
+
+[Public lint-dev Google Group](https://groups.google.com/forum/#!forum/lint-dev)
+
+[In-depth Lint Video Presentation by Tor](https://www.youtube.com/watch?v=p8yX5-lPS6o)
+(partially out-dated)
+([Slides](https://resources.jetbrains.com/storage/products/kotlinconf2017/slides/KotlinConf+Lint+Slides.pdf))
+
+[ADS 19 Presentation by Alan & Rahul](https://www.youtube.com/watch?v=jCmJWOkjbM0)
+
+[META-INF vs Manifest](https://groups.google.com/forum/#!msg/lint-dev/z3NYazgEIFQ/hbXDMYp5AwAJ)
\ No newline at end of file