[fenix] Closes https://github.com/mozilla-mobile/fenix/issues/8944 - Adds custom lint checks
parent
058e6b3e9f
commit
ccee01a230
@ -0,0 +1 @@
|
||||
/build
|
@ -0,0 +1,21 @@
|
||||
/* 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')
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/* 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
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/* 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
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/* 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.tools.lint.client.api.IssueRegistry
|
||||
import com.android.tools.lint.detector.api.Issue
|
||||
|
||||
/**
|
||||
* Registry which provides a list of our custom lint checks to be performed on an Android project.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
class LintIssueRegistry : IssueRegistry() {
|
||||
override val api: Int = com.android.tools.lint.detector.api.CURRENT_API
|
||||
override val issues: List<Issue> = listOf(
|
||||
AndroidSrcXmlDetector.ISSUE_XML_SRC_USAGE,
|
||||
TextViewAndroidSrcXmlDetector.ISSUE_XML_SRC_USAGE,
|
||||
ImageViewAndroidTintXmlDetector.ISSUE_XML_SRC_USAGE
|
||||
)
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/* 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_DRAWABLE_BOTTOM
|
||||
import com.android.SdkConstants.ATTR_DRAWABLE_END
|
||||
import com.android.SdkConstants.ATTR_DRAWABLE_LEFT
|
||||
import com.android.SdkConstants.ATTR_DRAWABLE_RIGHT
|
||||
import com.android.SdkConstants.ATTR_DRAWABLE_START
|
||||
import com.android.SdkConstants.ATTR_DRAWABLE_TOP
|
||||
import com.android.SdkConstants.FQCN_TEXT_VIEW
|
||||
import com.android.SdkConstants.TEXT_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 TextViewAndroidSrcXmlDetector : ResourceXmlDetector() {
|
||||
companion object {
|
||||
const val SCHEMA = "http://schemas.android.com/apk/res/android"
|
||||
|
||||
const val ERROR_MESSAGE =
|
||||
"Using android:drawableX to define resource instead of app:drawableXCompat"
|
||||
|
||||
val ISSUE_XML_SRC_USAGE = Issue.create(
|
||||
id = "TextViewAndroidSrcXmlDetector",
|
||||
briefDescription = "Prohibits using android namespace to define drawables in TextViews",
|
||||
explanation = "TextView drawables should be declared using app:drawableXCompat",
|
||||
category = Category.CORRECTNESS,
|
||||
severity = Severity.ERROR,
|
||||
implementation = Implementation(
|
||||
TextViewAndroidSrcXmlDetector::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_TEXT_VIEW,
|
||||
TEXT_VIEW
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitElement(context: XmlContext, element: Element) {
|
||||
val node = when {
|
||||
element.hasAttributeNS(SCHEMA, ATTR_DRAWABLE_BOTTOM) -> element.getAttributeNodeNS(
|
||||
SCHEMA,
|
||||
ATTR_DRAWABLE_BOTTOM
|
||||
)
|
||||
element.hasAttributeNS(SCHEMA, ATTR_DRAWABLE_END) -> element.getAttributeNodeNS(
|
||||
SCHEMA,
|
||||
ATTR_DRAWABLE_END
|
||||
)
|
||||
element.hasAttributeNS(SCHEMA, ATTR_DRAWABLE_LEFT) -> element.getAttributeNodeNS(
|
||||
SCHEMA,
|
||||
ATTR_DRAWABLE_LEFT
|
||||
)
|
||||
element.hasAttributeNS(
|
||||
SCHEMA,
|
||||
ATTR_DRAWABLE_RIGHT
|
||||
) -> element.getAttributeNodeNS(SCHEMA, ATTR_DRAWABLE_RIGHT)
|
||||
element.hasAttributeNS(
|
||||
SCHEMA,
|
||||
ATTR_DRAWABLE_START
|
||||
) -> element.getAttributeNodeNS(SCHEMA, ATTR_DRAWABLE_START)
|
||||
element.hasAttributeNS(SCHEMA, ATTR_DRAWABLE_TOP) -> element.getAttributeNodeNS(
|
||||
SCHEMA,
|
||||
ATTR_DRAWABLE_TOP
|
||||
)
|
||||
else -> null
|
||||
} ?: return
|
||||
|
||||
context.report(
|
||||
issue = ISSUE_XML_SRC_USAGE,
|
||||
scope = node,
|
||||
location = context.getLocation(node),
|
||||
message = ERROR_MESSAGE
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue