detekt: Cannot write extension that requires a bindingContext
Moving over the very helpful discussion that I incorrectly started against the PR to add ForbiddenMethodCall
check to styles
. I am trying to write a custom extension that does a very similar thing and yet my visitor is never called with non-empty bindingContext
. I took @cortinico’s very helpful advice and made some additions to my configuration but that does not seem to help. To debug, I attempted to simply use the ForbiddenMethodCall
check but could not even get that to work. I am going to paste (part of) our configuration below for additional context. Any help you can offer would be great! Thank you for all the help and such a great product!
Expected Behavior
The use of a forbidden method should be flagged.
Observed Behavior
None of the methods were flagged as being banned.
Steps to Reproduce
I am running detekt
with gradle via:
./gradlew detekt
Context
Your Environment
- Version of detekt used: 1.3.1
- Version of Gradle used (if applicable): 5.6.0
- Operating System and version: Linux
- Link to your project (if it’s a public repository): This branch is not yet public. Relevant config:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath Deps.tools_androidgradle
classpath Deps.tools_kotlingradle
classpath Deps.androidx_safeargs
classpath Deps.allopen
classpath Deps.osslicenses_plugin
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
plugins {
id("io.gitlab.arturbosch.detekt").version("1.3.1")
}
allprojects {
repositories {
google()
maven {
url "https://snapshots.maven.mozilla.org/maven2"
}
maven {
url "https://maven.mozilla.org/maven2"
}
maven {
url "https://repo.leanplum.com/"
}
jcenter()
}
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.allWarningsAsErrors = true
kotlinOptions.freeCompilerArgs += ["-Xuse-experimental=kotlin.Experimental", "-Xskip-runtime-version-check"]
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
detekt {
// The version number is duplicated, please refer to plugins block for more details
version = "1.3.1"
input = files("$projectDir/app/src")
config = files("$projectDir/config/detekt.yml")
//exclude = ".*test.*,.*/resources/.*,.*/tmp/.*"
reports {
html {
enabled = true
destination = file("$projectDir/build/reports/detekt.html")
}
xml {
enabled = false
}
}
}
configurations {
ktlint
}
dependencies {
ktlint "com.pinterest:ktlint:0.34.2"
detekt project(":mozilla-detekt-rules")
detekt "io.gitlab.arturbosch.detekt:detekt-cli:${Versions.detekt}"
}
task ktlint(type: JavaExec, group: "verification") {
description = "Check Kotlin code style."
classpath = configurations.ktlint
main = "com.pinterest.ktlint.Main"
args "app/src/**/*.kt"
}
tasks.withType(io.gitlab.arturbosch.detekt.Detekt) {
jvmTarget = "1.8"
}
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 17 (7 by maintainers)
I think that this is about the best that I am going to do. As a recap, here is my goal and my context:
Context: An Android application written in Kotlin with a large number of dependencies.
Goal: Use a custom Detekt plugin that determines whether banned methods are called. The custom plugin requires a binding context in order to do method resolution. Without resolution, writing such a plugin is possible, but would have to be imprecise. For example, consider a scenario where we want to ban Foo.methodA. Resolution is necessary to determine whether either invoking
x.methodA()
ory.methodA()
are okay. We need to know the type ofx
and the type ofy
. In the absence of resolution information, we would have to resort to banning all calls tomethodA
which would lead to a significant number of false positives which would, in turn, lead developers to develop mistrust of the tool.Solution: To get a binding context in the custom plugin from Detekt, it is necessary to configure Detekt with a
classpath
and ajvmTarget
. That is relatively straightforward:The problem is, with Android’s finagling in gradle, a meaningful classpath that takes into account the Android application’s dependencies is not completely built until after the configuration phase of the gradle lifecycle is complete. This is after a
SourceTask
orVerificationTask
executes (the type of the Detekt task). Therefore, we have to delay execution of the Detekt task until after the configuration phase of the gradle lifecycle is complete.Doing this is not easy, but it is possible. Here’s how we achieved it:
I will eventually turn this into a blog post, but I want to get it down on paper early in case it helps someone else!
Still working through some issues on this getting the classpath exactly right. I will post as soon as everything is perfect. Sorry for the delay and thanks again everyone!
I was able to get this to work. I will post here later tonight with my solution for people who are looking at it in the future and might be having the same problem! Thank you to @arturbosch and @schalkms and others who helped debug this!
It looks like https://arturbosch.github.io/detekt/groovydsl.html still refers to the old ways of configuring?
This really helps, thank you! I guess that I know have the same question about setting the other items that would normally go in the
detekt
“closure” like config, excludes etc?obviously, yes!! If you think that it would be useful. I wasn’t sure people would find it so.