Name: detekt
Description: Static code analysis for Kotlin
Created: 2016-10-23 21:04:45.0
Updated: 2018-01-19 16:15:20.0
Pushed: 2018-01-20 11:54:56.0
Size: 3280
Language: Kotlin
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
Meet detekt, a static code analysis tool for the Kotlin programming language. It operates on the abstract syntax tree provided by the Kotlin compiler.
intellij
distribution for formatting and inspecting kotlin codeFileProcessListener's
git clone https://github.com/arturbosch/detekt
cd detekt
./gradlew build shadowJar
java -jar detekt-cli/build/libs/detekt-cli-[version]-all.jar [parameters]*
The following parameters are shown when --help
is entered. The --input
/-i
option is required:
e: detekt [options]
tions:
--baseline, -b
If a baseline xml file is passed in, only new code smells not in the
baseline are printed in the console.
--config, -c
Path to the config file (path/to/config.yml).
--config-resource, -cr
Path to the config resource on detekt's classpath (path/to/config.yml).
--create-baseline, -cb
Treats current analysis findings as a smell baseline for future detekt
runs.
Default: false
--debug
Debugs given ktFile by printing its elements.
Default: false
--disable-default-rulesets, -dd
Disables default rule sets.
Default: false
--filters, -f
Path filters defined through regex with separator ';' (".*test.*").
--generate-config, -gc
Export default config to default-detekt-config.yml.
Default: false
--help, -h
Shows the usage.
--input, -i
Input path to analyze (path/to/project).
--output, -o
Directory where output reports are stored.
--output-name, -on
The base name for output reports is derived from this parameter.
--parallel
Enables parallel compilation of source files. Should only be used if the
analyzing project has more than ~200 kotlin files.
Default: false
--plugins, -p
Extra paths to plugin jars separated by ',' or ';'.
--input
can either be a directory or a single Kotlin file.
The currently only supported configuration format is yaml. --config
should point to one. Generating a default configuration file is as easy as using the --generate-config
parameter.
filters
can be used for example to exclude all test directories.
With rules
you can point to additional ruleset.jar's creating by yourself or others.
More on this topic see section Custom RuleSets.
Use the groovy or kotlin dsl of gradle and configure the detekt closure as described here.
For gradle version >= 2.1
dscript {
repositories {
jcenter()
}
ins {
id "io.gitlab.arturbosch.detekt" version "1.0.0.[version]"
kt {
version = "1.0.0.[version]"
profile("main") {
input = "$projectDir/src/main/kotlin"
config = "$projectDir/detekt.yml"
filters = ".*test.*,.*/resources/.*,.*/tmp/.*"
}
For all gradle versions:
dscript {
positories {
jcenter()
maven { url "https://plugins.gradle.org/m2/" }
pendencies {
classpath "gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.0.0.[version]"
y plugin: "io.gitlab.arturbosch.detekt"
kt {
version = "1.0.0.[version]"
profile("main") {
input = "$projectDir/src/main/kotlin"
config = "$projectDir/detekt.yml"
filters = ".*test.*,.*/resources/.*,.*/tmp/.*"
}
For gradle version >= 4.1
rt io.gitlab.arturbosch.detekt.DetektExtension
dscript {
repositories {
jcenter()
}
ins {
id("io.gitlab.arturbosch.detekt").version("1.0.0.[version]")
kt {
version = "1.0.0.[version]"
profile("main", Action {
input = "$projectDir/src/main/kotlin"
config = "$projectDir/detekt.yml"
filters = ".*test.*,.*/resources/.*,.*/tmp/.*"
})
When using Android make sure to have detekt configured in the project level build.gradle file. The new preferred plugin configuration way is used, the old way is commented out.
dscript {
repositories {
maven { url "https://plugins.gradle.org/m2/" }
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath "gradle.plugin.io.gitlab.arturbosch.detekt:detekt-gradle-plugin:1.0.0.[version]"
}
ins {
id "io.gitlab.arturbosch.detekt" version "1.0.0.[version]"
ply plugin: 'io.gitlab.arturbosch.detekt'
rojects {
repositories {
jcenter()
}
clean(type: Delete) {
delete rootProject.buildDir
kt {
version = "1.0.0.[version]"
profile("main") {
input = "$projectDir/your/app"
config = "$projectDir/detekt.yml"
filters = ".*test.*,.*/resources/.*,.*/tmp/.*"
}
detektCheck
- Runs a detekt analysis and complexity report. Configure the analysis inside the detekt-closure
. By default the standard rule set is used without output report or black- and whitelist checks.detektGenerateConfig
- Generates a default detekt config file into your projects location.detektBaseline
- Like detektCheck
, but creates a code smell baseline. Further detekt runs will only feature new smells not in this list.detektIdeaFormat
- Uses a local idea
installation to format your kotlin (and other) code according to the specified code-style.xml
.detektIdeaInspect
Uses a local idea
installation to run inspections on your kotlin (and other) code according to the specified inspections.xml
profile.kt {
version = "1.0.0.[version]" // When unspecified the latest detekt version found, will be used. Override to stay on the same version.
// A profile basically abstracts over the argument vector passed to detekt.
// Different profiles can be specified and used for different sub modules or testing code.
profile("main") {
input = "$projectDir/src/main/kotlin" // Which part of your project should be analyzed?
config = "$projectDir/detekt.yml" // Use $project.projectDir or to navigate inside your project
configResource = "/detekt.yml" // Use this parameter instead of config if your detekt yaml file is inside your resources. Is needed for multi project maven tasks.
filters = ".*test.*, .*/resources/.*" // What paths to exclude? Use comma or semicolon to separate
ruleSets = "other/optional/ruleset.jar" // Custom rule sets can be linked to this, use comma or semicolon to separate, remove if unused.
disableDefaultRuleSets = false // Disables the default rule set. Just use detekt as the detection engine with your custom rule sets.
output = "$project.projectDir/reports" // Directory where output reports are stored (if present).
outputName = "my-module" // This parameter is used to derive the output report name
baseline = "$project.projectDir/reports/baseline.xml" // If present all current findings are saved in a baseline.xml to only consider new code smells for further runs.
parallel = true // Use this flag if your project has more than 200 files.
/ Definines a secondary profile `gradle detektCheck -Ddetekt.profile=override` will use this profile.
/ The main profile gets always loaded but specified profiles override main profiles parameters.
rofile("override") {
config = "$projectDir/detekt-test-config.yml"
~/.idea
detekt-closure
code-style.xml
and inpect.xml
from idea settings (Settings>CodeStyle>Scheme
and Settings>Inspections>Profile
)detektIdeaFormat
or detektIdeaInspect
ng USER_HOME = System.getProperty("user.home")
kt {
profile("main") {
input = "$projectDir/src/main/kotlin"
output = "$projectDir/reports/report.xml"
outputFormat = "xml"
}
idea {
path = "$USER_HOME/.idea"
codeStyleScheme = "$USER_HOME/.idea/idea-code-style.xml"
inspectionsProfile = "$USER_HOME/.idea/inspect.xml"
report = "project.projectDir/reports"
mask = "*.kt,"
}
For more information on using idea as a headless formatting/inspection tool see here.
gradle detekt
check.dependsOn detekt
if you want to run detekt on every build
sitories {
jcenter()
igurations {
detekt
detekt(type: JavaExec) {
main = "io.gitlab.arturbosch.detekt.cli.Main"
classpath = configurations.detekt
def input = "$projectDir"
def config = "$projectDir/detekt.yml"
def filters = ".*test.*"
def rulesets = ""
def params = [ '-i', input, '-c', config, '-f', filters, '-r', rulesets]
args(params)
ndencies {
detekt 'io.gitlab.arturbosch.detekt:detekt-cli:1.0.0.[version]'
Attention Android Developers! the dependencies section must be at the bottom, after the repository, configurations and task sections!
mvn verify
(when using the verify phase as I did here)ld>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<!-- This can be run separately with mvn antrun:run@detekt -->
<id>detekt</id>
<phase>verify</phase>
<configuration>
<target name="detekt">
<java taskname="detekt" dir="${basedir}" fork="true" failonerror="true"
classname="io.gitlab.arturbosch.detekt.cli.Main" classpathref="maven.plugin.classpath">
<arg value="-i"/>
<arg value="${basedir}/src"/>
<arg value="-f"/>
<arg value=".*test.*"/>
<arg value="--useTabs"/>
</java>
</target>
</configuration>
<goals><goal>run</goal></goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>io.gitlab.arturbosch.detekt</groupId>
<artifactId>detekt-cli</artifactId>
<version>1.0.0.[CURRENT_MILESTONE]</version>
</dependency>
</dependencies>
</plugin>
</plugins>
ild>
ginRepositories>
luginRepository>
<id>arturbosch-code-analysis</id>
<name>arturbosch-code-analysis (for detekt)</name>
<url>https://dl.bintray.com/arturbosch/code-analysis/</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
<updatePolicy>never</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
<updatePolicy>never</updatePolicy>
</snapshots>
pluginRepository>
uginRepositories>
Currently there are seven rule sets which are used per default when running the CLI.
To turn off specific rules/rule sets or change threshold values for certain rules a yaml configuration file can be used. There are two approaches to configuring your rulesets.
Export the default config with the --generate-config
flag or copy and modify the default-detekt-config.yml for your needs.
failFast
option)Set failFast: true
in your detekt.yml configuration file. As a result, every rule will be enabled and warningThreshold
and errorThreshold
will be set to 0. Weights can then be ignored and left untouched.
To adjust, for example, the maxLineLength value, use this configuration file:
Fast:true
Correct: true
e:
xLineLength:
maxLineLength: 100
All rules are turned on by default and the value of maxLineLength is adjusted to 100. If you don't want to have the CommentOverPrivateMethod turned on, you append:
ents:
mmentOverPrivateMethod:
active: false
detekt supports the Java (@SuppressWarnings
) and Kotlin (@Suppress
) style suppression. If both annotations are present, only Kotlin's annotation is used! To suppress a rule, the id of the rule must be written inside the values field of the annotation e.g. @Suppress("LongMethod", "LongParameterList", ...)
detekt now can throw a BuildFailure(Exception) and let the build fail with following config parameters:
d:
rningThreshold: 5 // Five weighted findings
ilThreshold: 10 // Ten weighted smells to fail the build
ights:
complexity: 2 // Whole complexity rule should add two for each finding.
LongParameterList: 1 // The specific rule should not add two.
comments: 0 // Comments should not fail the build at all?!
Every rule and rule set can be attached with an integer value which is the weight of the finding. For example: If you have 5 findings of the category complexity, then your failThreshold of 10 is reached as 5 x 2 = 10.
The formula for weights: RuleID > RuleSetID > 1. Only integer values are supported.
detekt uses a ServiceLoader to collect all instances of RuleSetProvider-interfaces. So it is possible
to define rules/rule sets and enhance detekt with your own flavor.
Attention: You need a resources/META-INF/services/io.gitlab.arturbosch.detekt.api.RuleSetProvider
file which
has as content the fully qualified name of your RuleSetProvider e.g. io.gitlab.arturbosch.detekt.sampleruleset.SampleProvider.
The easiest way to define a rule set is to clone the provided detekt-sample-ruleset project.
Own rules have to extend the abstract Rule class and override the visitXXX
functions from the AST.
A RuleSetProvider
must be implemented which declares a RuleSet
in the instance
method.
To allow your rule to be configurable, pass it a Config object from within your rule set provider.
You can also specify a Severity type for your rule.
Example of a custom rule:
s TooManyFunctions : Rule("TooManyFunctions") {
private var amount: Int = 0
override fun visitFile(file: PsiFile) {
super.visitFile(file)
if (amount > 10) {
addFindings(CodeSmell(id, Entity.from(file)))
}
}
override fun visitNamedFunction(function: KtNamedFunction) {
amount++
}
Example of a much preciser rule in terms of more specific CodeSmell constructor and Rule attributes:
s TooManyFunctions2(config: Config) : Rule("TooManyFunctionsTwo", Severity.Maintainability, config) {
private var amount: Int = 0
override fun visitFile(file: PsiFile) {
super.visitFile(file)
if (amount > 10) {
addFindings(CodeSmell(
id = id, entity = Entity.from(file),
description = "Too many functions can make the maintainability of a file costlier",
metrics = listOf(Metric(type = "SIZE", value = amount, threshold = 10)),
references = listOf())
)
}
}
override fun visitNamedFunction(function: KtNamedFunction) {
amount++
}
If you want your rule to be configurable, write down your properties inside the detekt.yml file
and use the withConfig
function:
leSet:
Rule:
MyMetric: 5
threshold: 10
herRule:
active: false
By specifying the rule set and rule ids, detekt will use the sub configuration of MyRule:
# Maven
our using maven to build rule sets or use _detekt_ as a dependency, you have to run the additional task `publishToMavenLocal`
<a name="customprocessors">Custom Processors</a>
<a name="customreports">Custom Reports</a>
ekt_ allows you to extend the console output and to create custom output formats.
example if you do not like the default printing of findings, we can ... TODO
<a name="testing">Testing your rules</a>
est your rules you need a KtFile object and use its _visit_ method.
e are two predefined methods to help obtaining a KtFile:
mpileContentForTest(content: String): KtFile
mpileForTest(path: Path): KtFile
with M3 there is a special detekt-test module, which specifies above two methods but also
extension functions that allow to skip compilation, ktFile and visit procedures.
le.lint(StringContent/Path/KtFile) returns just the findings for given content
<a name="baseline">Code Smell baseline and ignore list</a>
ify a report output with `--output` parameter and specify its format with `--output-format`.
you can generate a report which holds all findings of current analysis.
`--baseline` you generate a `baseline.xml` where code smells are white- or blacklisted.
<ID>CatchRuntimeException:Junk.kt$e: RuntimeException</ID>
<ID>NestedBlockDepth:Indentation.kt$Indentation$override fun procedure(node: ASTNode)</ID>
<ID>ComplexCondition:SpacingAroundOperator.kt$SpacingAroundOperator$tokenSet.contains(node.elementType) && node is LeafPsiElement && !node.isPartOf(KtPrefixExpression::class) && // not unary !node.isPartOf(KtTypeParameterList::class) && // fun <T>fn(): T {} !node.isPartOf(KtTypeArgumentList::class) && // C<T> !node.isPartOf(KtValueArgument::class) && // fn(*array) !node.isPartOf(KtImportDirective::class) && // import * !node.isPartOf(KtSuperExpression::class)</ID>
<ID>TooManyFunctions:LargeClass.kt$io.gitlab.arturbosch.detekt.rules.complexity.LargeClass.kt</ID>
<ID>ComplexMethod:DetektExtension.kt$DetektExtension$fun convertToArguments(): MutableList<String></ID>
intention of a whitelist is that only new code smells are printed on further analysis. The blacklist can be used
rite down false positive detections. The `ID` node must be build of `<RuleID>:<Signature>`. Both values can be found
de the report file.
<a name="contributors">Contributors</a>
ou contributed to detekt but your name is not in the list, please feel free to add yourself to it!
rtur Bosch](https://github.com/arturbosch) - Maintainer
arvin Ramin](https://github.com/Mauin) - Collaborator, Bunch of rules, Active on Issues, refactorings, MultiRule
chalks](https://github.com/schalkms) - Collaborator, Active on Issues, Bunch of rules, Project metrics
iklas Baudy](https://github.com/vanniktech) - Active on Issues, Bunch of rules, Bug fixes
ummax](https://github.com/lummax) - Cli enhancements
vyatoslav Chatchenko](https://github.com/MyDogTom) - Active on Issues, NamingConventions and UnusedImport fixes
ean Flanigan](https://github.com/seanf) - Config from classpath resource
ebastian Schuberth](https://github.com/sschuberth) - Active on Issues, Windows support
livier Lemasle](https://github.com/olivierlemasle) - NP-Bugfix
arc Prengemann](https://github.com/winterDroid) - Support for custom output formats, prototyped Rule-Context-Issue separation
ebastiano Poggi](https://github.com/rock3r) - Enhanced milestone report script, Magic number fixes
lya Tretyakov](https://github.com/jvilya) - Sonar runs should not auto correct formatting.
ndrey T](https://github.com/mr-procrastinator) - Readme fix
van Balaksha](https://github.com/tagantroy) - Rules: UnsafeCast, SpreadOperator, UnsafeCallOnNullableType, LabeledExpression
nna Y](https://github.com/Nevvea7) - Readme fix
arol Wrótniak](https://github.com/koral--) - Treat comments as not empty blocks
adim Vaculik](https://github.com/radimvaculik) - VariableMaxLength - bugfix
artin Nonnenmacher](https://github.com/mnonnenmacher) - UndocumentedPublicClass - enum support
mytro Troynikov](https://github.com/DmytroTroynikov) - Updated Magic Number rule to ignore Named Arguments
ndrew Ochsner](https://github.com/aochsner) - Updated Readme for `failFast` option
aul Merlin](https://github.com/eskatos) - Gradle build improvements
onstantin Aksenov](https://github.com/vacxe) - Coding improvement
atthew Haughton](https://github.com/3flex) - Started type resolution, Dependency updates, Coding + Documentation improvements
anusz Bagi?ski](https://github.com/jbaginski) - Fixed line number reporting for MaxLineLengthRule
ike Kobit](https://github.com/mkobit) - Gradle build improvements
hilipp Hofmann](https://github.com/philipphofmann) - Readme improvements
livier PEREZ](https://github.com/olivierperez) - Fixed Typo in Readme
ebastian Kaspari](https://github.com/pocmo) - Html-Output-Format, Documentation fix
lya Zorin](https://github.com/geralt-encore) - Rule improvement: UnnecessaryAbstractClass
esh Markov](https://github.com/markov) - Improve error message for incorrect configuration file
atrick Pilch](https://github.com/patrickpilch) - Rule improvement: ReturnCount
erj Lotutovici](https://github.com/serj-lotutovici) - Rule improvement: LongParameterList
mitry Primshyts](https://github.com/deeprim) - Rule improvement: MagicNumber
gor Neliuba](https://github.com/egor-n) - Rule improvement: EmptyFunctionBlock, EmptyClassBlock
aid Tahsin Dane](https://github.com/tasomaniac/) - Gradle plugin improvements
<a name="mentions">Mentions</a>
ndroidweekly](https://img.shields.io/badge/androidweekly.net-259-orange.svg?style=flat-square)](http://androidweekly.net/issues/issue-259)
ndroidweekly](https://img.shields.io/badge/androidweekly.cn-154-orange.svg?style=flat-square)](http://androidweekly.cn/android-dev-wekly-issue-154/)
entioned/used in ...
medium/acerezoluna/static-code-analysis-tools-for-kotlin-in-android](https://medium.com/@acerezoluna/static-code-analysis-tools-for-kotlin-in-android-fa072125fd50)
medium/annayan/writing-custom-lint-rules-for-your-kotlin-project-with-detekt](https://proandroiddev.com/writing-custom-lint-rules-for-your-kotlin-project-with-detekt-653e4dbbe8b9)
ree Continuous Integration for modern Android apps with CircleCI](https://tips.seebrock3r.me/free-continuous-integration-for-modern-android-apps-with-circleci-940e33451c83)
putnik is a free tool for static code review and provides support for detekt](https://github.com/TouK/sputnik)
radle plugin that generates ErrorProne, Findbugs, Checkstyle, PMD, CPD, Lint, Detekt & Ktlint Tasks for every subproject](https://github.com/vanniktech/gradle-code-quality-tools-plugin)
ava library for parsing report files from static code analysis](https://github.com/tomasbjerre/violations-lib)
tatic code analysis for Kotlin in Android](https://blog.thefuntasty.com/static-code-analysis-for-kotlin-in-android-8676c8d6a3c5)
he Art of Android DevOps](https://blog.undabot.com/the-art-of-android-devops-fa29396bc9ee)
ndroid Basics: Continuous Integration](https://academy.realm.io/posts/360-andev-2017-mark-scheel-continuous-integration-android/)
Credits
etBrains](https://github.com/jetbrains/) - Creating Intellij + Kotlin
MD](https://github.com/pmd/pmd) & [Checkstyle](https://github.com/checkstyle/checkstyle) & [KtLint](https://github.com/shyiko/ktlint) - Ideas for threshold values and style rules