Commit 414e905b authored by ekager's avatar ekager Committed by liuche
Browse files

Closes #8944 - Adds custom lint checks

parent 06e5efd0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -581,6 +581,8 @@ dependencies {
    // For the initial release of Glean 19, we require consumer applications to
    // depend on a separate library for unit tests. This will be removed in future releases.
    testImplementation "org.mozilla.telemetry:glean-forUnitTests:${project.ext.glean_version}"

    lintChecks project(":mozilla-lint-rules")
}

if (project.hasProperty("raptor")) {
+1 −0
Original line number Diff line number Diff line
/build
+21 −0
Original line number Diff line number Diff line
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

apply plugin: 'java-library'
apply plugin: 'kotlin'

targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_1_8

dependencies {
    compileOnly "org.jetbrains.kotlin:kotlin-stdlib:1.3.61"
    compileOnly "com.android.tools.lint:lint-api:26.6.1"
    compileOnly "com.android.tools.lint:lint-checks:26.6.1"
}

jar {
    manifest {
        attributes('Lint-Registry-v2': 'org.mozilla.fenix.lintrules.LintIssueRegistry')
    }
}
+80 −0
Original line number Diff line number Diff line
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.fenix.lintrules

import com.android.SdkConstants.ATTR_SRC
import com.android.SdkConstants.FQCN_IMAGE_BUTTON
import com.android.SdkConstants.FQCN_IMAGE_VIEW
import com.android.SdkConstants.IMAGE_BUTTON
import com.android.SdkConstants.IMAGE_VIEW
import com.android.resources.ResourceFolderType
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.ResourceXmlDetector
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.XmlContext
import org.w3c.dom.Element

/**
 * A custom lint check that prohibits not using the app:srcCompat for ImageViews
 */
class AndroidSrcXmlDetector : ResourceXmlDetector() {
    companion object {
        const val SCHEMA = "http://schemas.android.com/apk/res/android"
        const val FULLY_QUALIFIED_APP_COMPAT_IMAGE_BUTTON =
            "androidx.appcompat.widget.AppCompatImageButton"
        const val FULLY_QUALIFIED_APP_COMPAT_VIEW_CLASS =
            "androidx.appcompat.widget.AppCompatImageView"
        const val APP_COMPAT_IMAGE_BUTTON = "AppCompatImageButton"
        const val APP_COMPAT_IMAGE_VIEW = "AppCompatImageView"

        const val ERROR_MESSAGE = "Using android:src to define resource instead of app:srcCompat"

        val ISSUE_XML_SRC_USAGE = Issue.create(
            id = "AndroidSrcXmlDetector",
            briefDescription = "Prohibits using android:src in ImageViews and ImageButtons",
            explanation = "ImageView (and descendants) images should be declared using app:srcCompat",
            category = Category.CORRECTNESS,
            severity = Severity.ERROR,
            implementation = Implementation(
                AndroidSrcXmlDetector::class.java,
                Scope.RESOURCE_FILE_SCOPE
            )
        )
    }

    override fun appliesTo(folderType: ResourceFolderType): Boolean {
        // Return true if we want to analyze resource files in the specified resource
        // folder type. In this case we only need to analyze layout resource files.
        return folderType == ResourceFolderType.LAYOUT
    }

    override fun getApplicableElements(): Collection<String>? {
        return setOf(
            FQCN_IMAGE_VIEW,
            IMAGE_VIEW,
            FQCN_IMAGE_BUTTON,
            IMAGE_BUTTON,
            FULLY_QUALIFIED_APP_COMPAT_IMAGE_BUTTON,
            FULLY_QUALIFIED_APP_COMPAT_VIEW_CLASS,
            APP_COMPAT_IMAGE_BUTTON,
            APP_COMPAT_IMAGE_VIEW
        )
    }

    override fun visitElement(context: XmlContext, element: Element) {
        if (!element.hasAttributeNS(SCHEMA, ATTR_SRC)) return
        val node = element.getAttributeNodeNS(SCHEMA, ATTR_SRC)

        context.report(
            issue = ISSUE_XML_SRC_USAGE,
            scope = node,
            location = context.getLocation(node),
            message = ERROR_MESSAGE
        )
    }
}
+81 −0
Original line number Diff line number Diff line
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.fenix.lintrules

import com.android.SdkConstants.ATTR_TINT
import com.android.SdkConstants.FQCN_IMAGE_BUTTON
import com.android.SdkConstants.FQCN_IMAGE_VIEW
import com.android.SdkConstants.IMAGE_BUTTON
import com.android.SdkConstants.IMAGE_VIEW
import com.android.resources.ResourceFolderType
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.ResourceXmlDetector
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.XmlContext
import org.w3c.dom.Element

/**
 * A custom lint check that prohibits not using the app:tint for ImageViews
 */
class ImageViewAndroidTintXmlDetector : ResourceXmlDetector() {
    companion object {
        const val SCHEMA = "http://schemas.android.com/apk/res/android"
        const val FULLY_QUALIFIED_APP_COMPAT_IMAGE_BUTTON =
            "androidx.appcompat.widget.AppCompatImageButton"
        const val FULLY_QUALIFIED_APP_COMPAT_VIEW_CLASS =
            "androidx.appcompat.widget.AppCompatImageView"
        const val APP_COMPAT_IMAGE_BUTTON = "AppCompatImageButton"
        const val APP_COMPAT_IMAGE_VIEW = "AppCompatImageView"

        const val ERROR_MESSAGE =
            "Using android:tint to tint ImageView instead of app:tint with AppCompatImageView"

        val ISSUE_XML_SRC_USAGE = Issue.create(
            id = "AndroidSrcXmlDetector",
            briefDescription = "Prohibits using android:tint in ImageViews and ImageButtons",
            explanation = "ImageView (and descendants) should be tinted using app:tint",
            category = Category.CORRECTNESS,
            severity = Severity.ERROR,
            implementation = Implementation(
                ImageViewAndroidTintXmlDetector::class.java,
                Scope.RESOURCE_FILE_SCOPE
            )
        )
    }

    override fun appliesTo(folderType: ResourceFolderType): Boolean {
        // Return true if we want to analyze resource files in the specified resource
        // folder type. In this case we only need to analyze layout resource files.
        return folderType == ResourceFolderType.LAYOUT
    }

    override fun getApplicableElements(): Collection<String>? {
        return setOf(
            FQCN_IMAGE_VIEW,
            IMAGE_VIEW,
            FQCN_IMAGE_BUTTON,
            IMAGE_BUTTON,
            FULLY_QUALIFIED_APP_COMPAT_IMAGE_BUTTON,
            FULLY_QUALIFIED_APP_COMPAT_VIEW_CLASS,
            APP_COMPAT_IMAGE_BUTTON,
            APP_COMPAT_IMAGE_VIEW
        )
    }

    override fun visitElement(context: XmlContext, element: Element) {
        if (!element.hasAttributeNS(SCHEMA, ATTR_TINT)) return
        val node = element.getAttributeNodeNS(SCHEMA, ATTR_TINT)

        context.report(
            issue = ISSUE_XML_SRC_USAGE,
            scope = node,
            location = context.getLocation(node),
            message = ERROR_MESSAGE
        )
    }
}
Loading