- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想编写一个 lint 检查,以确保将 @ContributesAndroidInjector
添加到所有需要它的 fragment 中。
有没有办法在调用 visitClass(node: UClass)
之前收集所有用 @Module
注解的类?
现在我已经手动添加了列表中的所有模块(请参阅代码示例),但这对我来说不是正确的解决方案,因为添加新模块时我需要不断更新我的检测器。
探测器:
class MissingContributorDetector : Detector(), Detector.UastScanner {
override fun getApplicableUastTypes(): List<Class<out UElement>> {
return listOf(UClass::class.java)
}
override fun createUastHandler(context: JavaContext) = Visitor(context)
class Visitor(private val context: JavaContext) : UElementHandler() {
private val returnTypes: List<String>
init {
returnTypes = MODULES.mapNotNull { context.evaluator.findClass(it) }
.flatMap { it.methods.toList() }
.filter { it.hasAnnotation(DAGGER_MODULE_ANNOTATION) }
.mapNotNull { it.returnType }
.mapNotNull { PsiUtil.resolveClassInType(it)?.qualifiedName }
}
override fun visitClass(node: UClass) {
// logic to determine if there is an issue
}
}
companion object {
private val MODULES = listOf(
"com.dagger.module.ModuleOne",
"com.dagger.module.ModuleTwo",
"com.dagger.module.ModuleThree",
)
}
}
模块:
@Module
abstract class ModuleOne {
@ContributesAndroidInjector
abstract fun contributesFragment(): HomeFragment
}
最佳答案
Is there a way to gather all classes that are annotated with @Module before visitClass(node: UClass) is called?
检测器可以编写为执行两次传递。第一遍将收集数据结构中的所有类,该数据结构将在第二遍期间可供检测器使用。在此方案中,将在第一次和第二次传递期间为每个类调用 visitClass()
。
MissingContributorDetector.kt
/*
Process this lint check in two passes. The fist pass collects all the classes that have
the @Module annotation. The second pass does the actual check but has a the class list
produced in the first pass at its disposal.
*/
class MissingContributorDetector : Detector(), Detector.UastScanner {
private val mModuleClasses: MutableList<UClass> = ArrayList()
override fun getApplicableUastTypes(): List<Class<out UElement>> {
return listOf(UClass::class.java)
}
override fun createUastHandler(context: JavaContext) = Visitor(context)
// Cues up the second phase for the actual lint check.
override fun afterCheckEachProject(context: Context) {
super.afterCheckEachProject(context)
if (context.phase == 1) { // Rescan classes
context.requestRepeat(this, MissingContributorIssue.implementation.scope)
}
}
inner class Visitor(private val context: JavaContext) : UElementHandler() {
// Search for classes that are annotated with @Module
override fun visitClass(node: UClass) {
if (context.phase == 1) { // Just collect class names
if (hasAnnotation(node.annotations, DAGGER_MODULE_ANNOTATION_QUALIFIED_NAME)) {
// Build the class list that will be used during the second pass.
mModuleClasses.add(node)
}
} else { // phase 2
// Do whatever processing is necessary. Here we just check for
// @ContributesAndroidInjector on each method in a class annotated with @Module.
// The mModuleClasses structure is fully populated from the first pass.
if (mModuleClasses.contains(node)) {
node.methods.forEach { checkMethodForContributesAndroidInjector(it) }
}
}
}
// Check for @ContributesAndroidInjector on non-constructor methods
private fun checkMethodForContributesAndroidInjector(node: UMethod) {
if (node.isConstructor ||
!isFragmentReturnType(node) ||
hasAnnotation(node.annotations, DAGGER_CONTRIBUTESANDROIDINJECTOR_QUALIFIED_NAME)) {
return
}
context.report(
MissingContributorIssue,
node,
context.getNameLocation(node),
MissingContributorIssue.getExplanation(TextFormat.TEXT)
)
}
private fun isFragmentReturnType(node: UMethod): Boolean {
val returnTypeRef = node.returnTypeReference
return returnTypeRef?.getQualifiedName() == HOME_FRAGMENT
}
private fun hasAnnotation(annotations: List<UAnnotation>, toCheck: String): Boolean {
return annotations.any { it.qualifiedName == toCheck }
}
}
companion object {
const val DAGGER_MODULE_ANNOTATION_QUALIFIED_NAME = "dagger.Module"
const val DAGGER_CONTRIBUTESANDROIDINJECTOR_QUALIFIED_NAME = "dagger.android.ContributesAndroidInjector"
const val HOME_FRAGMENT = "com.dagger.module.HomeFragment"
val MissingContributorIssue: Issue = Issue.create(
id = "MissingContributesAndroidInjector",
briefDescription = "Must specify @ContributesAndroidInjector",
implementation = Implementation(
MissingContributorDetector::class.java,
Scope.JAVA_FILE_SCOPE),
explanation = "Method must be annotated with @ContributesAndroidInjector if enclosing class is annotated with @Module.",
category = Category.CORRECTNESS,
priority = 1,
severity = Severity.FATAL
)
}
}
<小时/><小时/>
只需一次通过的旧答案
可以编写检测器来查看每个类,并仅选择那些用 @Module
注释的类。选择类后,可以检查每个返回 HomeFragment
的方法是否有 @ContributesAndroidInjector
注释。然后可以添加和扫描类,而无需更新模块列表。
MissingContributorDetector.kt
class MissingContributorDetector : Detector(), Detector.UastScanner {
override fun getApplicableUastTypes(): List<Class<out UElement>> {
return listOf(UClass::class.java)
}
override fun createUastHandler(context: JavaContext) = Visitor(context)
class Visitor(private val context: JavaContext) : UElementHandler() {
// Search for classes that are annotated with @Module
override fun visitClass(node: UClass) {
if (hasAnnotation(node.annotations, DAGGER_MODULE_ANNOTATION_QUALIFIED_NAME)) {
node.methods.forEach { checkMethodForContributesAndroidInjector(it) }
}
}
// Check for @ContributesAndroidInjector on non-constructor methods
private fun checkMethodForContributesAndroidInjector(node: UMethod) {
if (node.isConstructor ||
!isFragmentReturnType(node) ||
hasAnnotation(node.annotations, DAGGER_CONTRIBUTESANDROIDINJECTOR_QUALIFIED_NAME)) {
return
}
context.report(
MissingContributorIssue.ISSUE,
node,
context.getNameLocation(node),
MissingContributorIssue.ISSUE.getExplanation(TextFormat.TEXT)
)
}
private fun isFragmentReturnType(node: UMethod): Boolean {
val returnTypeRef = node.returnTypeReference
return returnTypeRef?.getQualifiedName() == HOME_FRAGMENT
}
private fun hasAnnotation(annotations: List<UAnnotation>, toCheck: String): Boolean {
return annotations.any { it.qualifiedName == toCheck }
}
}
object MissingContributorIssue {
private const val ID = "MissingContributesAndroidInjector"
private const val DESCRIPTION = "Must specify @ContributesAndroidInjector"
private const val EXPLANATION = ("Method must be annotated with @ContributesAndroidInjector if enclosing class is annotated with @Module.")
private val CATEGORY: Category = Category.CORRECTNESS
private const val PRIORITY = 1
private val SEVERITY = Severity.FATAL
val ISSUE: Issue = Issue.create(
ID,
DESCRIPTION,
EXPLANATION,
CATEGORY,
PRIORITY,
SEVERITY,
Implementation(
MissingContributorDetector::class.java,
Scope.JAVA_FILE_SCOPE)
)
}
companion object {
const val DAGGER_MODULE_ANNOTATION_QUALIFIED_NAME = "dagger.Module"
const val DAGGER_CONTRIBUTESANDROIDINJECTOR_QUALIFIED_NAME = "dagger.android.ContributesAndroidInjector"
const val HOME_FRAGMENT = "com.dagger.module.HomeFragment"
}
}
用于测试此检测器的文件:
ModuleOne.kt
@Module
abstract class ModuleOne {
@ContributesAndroidInjector
abstract fun isAnnotated(): HomeFragment
abstract fun shouldBeAnnotated(): HomeFragment
abstract fun notAnnotated()
}
abstract class ModuleTwo {
abstract fun okIsNotAnnotated(): HomeFragment
}
显示标记项目的 lint 报告:
关于android - 在运行 lint 检测器之前收集特定类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59028731/
PHPLint、JSLint,我最近在阅读一些IDE. 那么,什么是“linting”? 最佳答案 Linting 是运行程序的过程,该程序将分析代码是否存在潜在错误。 参见lint在维基百科上: l
Elixir是否有 Lint (如Javascript)可以检查每个函数是否具有类型规范? 最佳答案 有一个Erlang编译器开关+warn_missing_spec可以做到这一点,但是目前我无法使其
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 5 年前。 Improve this qu
例如,我让它在 .rb 和 .js 文件上匹配。 例如**/*.{js,rb} 并且还想在 Gemfile 和 Rakefile 上进行匹配。 最佳答案 解决方案是递归地使用 {},例如 "lin
我有一个自述文件,其中包含文件夹的文档、包含的库以及如何使用它们。 自述文件不是任何库的一部分,因此 nx-lint 会引发此错误: NX ERROR The following file(s
我的 React Native 构建突然失败并出现错误,尽管一天前工作得很好,没有任何相关的更改。 FAILURE: Build failed with an exception. * What we
我有一个 lint-gradle-api.jar 错误,我在论坛上查看了其他类似的问题,但我仍然有问题。有人有想法吗? Error running Gradle: Exit code 1 from:
我已经将 Android Studio 更新到 3.2.1,现在停止了这样的问题:找不到 lint-gradle-api.jar (com.android.tools.lint:lint-gradle
我目前正在从 tslint 迁移到 eslint。我在我的 .eslintignore 中配置了几个文件夹,我想从 linting 中完全忽略它们。这确实有效,但现在我收到错误: “无效的 lint
Q (tldr;): 我如何使用 android-lint 中的 JavaScanner 检查特定函数调用是否具有特定作为参数的字符串已被 try/catch block 包围。 详细信息:我已经完成
我有一个在 Cocoapods 上发布的库。 当我运行pod lib lint时从包含 MyProject.podspec 的目录中,命令行挂起 $ pod lib lint -> MyProject
我正在尝试使用 Android lint 来检查有关我的项目的一些事情。它似乎忽略了我提供的 lint.xml 文件,使我无法启用检查。 我在 Ubuntu 14.04 上使用 Android Stu
我正在使用工具栏附带的 CodeMirror 设计一个应用程序。由于性能原因,我没有通过异步或异步模式执行 lint。 我在工具栏中提供了一个图标,单击它我正在解析和构建错误。但是我对如何在编辑器中更
使用 ./gradlew lintDebug 生成 Android lint 报告时,报告中不包括 javac lint 错误,例如弃用或未经检查的转换。 我目前只是在编译时启用这些 javac 选项
默认情况下,在 gradle 中为发布构建启用了 lint。没有 abortOnError false 此选项会中止构建。 我的发布构建成功执行(没有 lint 警告),但是当我通过 gradle 调
我有一个使用 Android 构建工具版本 1.3.1 的 gradle Android 构建,并对我的代码运行 lint 检查。运行 Sonar 任务(由 org.sonarqube gradle
只是想知道是否有人可以帮助我进行 Gulp 设置。目前我正在使用 gulp-sass 和 gulp-scss-lint 进行监视任务。我想要发生的是,当为 linting 任务完全运行保存一个 scs
我正在做一个项目,最近更新到 android Gradle 构建工具 3.0.0 (com.android.tools.build:gradle:3.0.0)。我现在在通过 Android studi
我有一个带有 gradle 的 Android 项目。虽然 gradle 插件是 2.x.x,但运行 ./gradlew lint 的时间大约为 4 分钟。我已经将项目升级到 gradle plugi
事情是这样的。我有一个与 API 15 及更高版本兼容的应用程序,但由于它非常大并且我已经达到 65k 方法限制,我不得不将它设为 MultiDexApplication 类的后代。这会稍微减慢构建时
我是一名优秀的程序员,十分优秀!