<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Wilfried Mbouenda</title>
    <description>The latest articles on DEV Community by Wilfried Mbouenda (@willyshakes).</description>
    <link>https://dev.to/willyshakes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1108640%2F242a3af0-21c6-4777-8d49-2b2db95728f6.png</url>
      <title>DEV Community: Wilfried Mbouenda</title>
      <link>https://dev.to/willyshakes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/willyshakes"/>
    <language>en</language>
    <item>
      <title>Detekt Explained: Enhance Kotlin Projects with Static Analysis - part 1</title>
      <dc:creator>Wilfried Mbouenda</dc:creator>
      <pubDate>Tue, 30 Jun 2026 23:23:41 +0000</pubDate>
      <link>https://dev.to/willyshakes/detekt-explained-enhance-kotlin-projects-with-static-analysis-part-1-165k</link>
      <guid>https://dev.to/willyshakes/detekt-explained-enhance-kotlin-projects-with-static-analysis-part-1-165k</guid>
      <description>&lt;p&gt;This article was originally published on &lt;a href="https://wilfried.hashnode.dev/detekt-explained-enhance-kotlin-projects-with-static-analysis-part-1" rel="noopener noreferrer"&gt;wilfried.hashnode.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Static analysis isn't about making your code "look nice." It's about catching the kind of problems that quietly slow teams down: hidden complexity, fragile logic, and maintainability debt.&lt;/p&gt;

&lt;p&gt;In most Android codebases, quality doesn't degrade because engineers don't care—it degrades because there's no consistent, automated feedback loop.&lt;/p&gt;

&lt;p&gt;That's where detekt comes in.&lt;/p&gt;

&lt;p&gt;This article kicks off a practical series on using detekt in real projects—from zero setup to custom rules and CI enforcement.&lt;/p&gt;

&lt;p&gt;In this first part, we'll cover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Why Detekt Exists&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What Makes Detekt Different&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How Detekt Works&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rules and Rule Sets&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extensibility&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Production-Ready Setup&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why Detekt Exists
&lt;/h2&gt;

&lt;p&gt;When Kotlin 1.0 was released in 2016, it solved many problems—null safety, conciseness, better readability.&lt;/p&gt;

&lt;p&gt;But it created a new one: tooling.&lt;/p&gt;

&lt;p&gt;Java teams relied on Checkstyle, PMD, and FindBugs — none of which translated to Kotlin. Checkstyle physically can't parse .kt files. PMD took seven years to add experimental Kotlin support, held back by compiler instability and the cost of building custom ANTLR parsers. FindBugs died in 2015, before Kotlin 1.0 was released.&lt;/p&gt;

&lt;p&gt;FindBugs could technically handle Kotlin because it operates on Java bytecode which has the same format as Kotlin bytecode. The problem is FindBugs will give false positives because Kotlin provides advanced structural features that do not natively exist in Java (null safety, data classes, coroutines…)&lt;/p&gt;

&lt;p&gt;Let's take the example of a Kotlin data class.&lt;/p&gt;

&lt;p&gt;Kotlin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Java bytecode representation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Synthesized component methods for destructuring&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="nf"&gt;component1&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;component2&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// Synthesized copy mechanism&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;FindBugs sees &lt;code&gt;component1()&lt;/code&gt;, &lt;code&gt;component2()&lt;/code&gt;, &lt;code&gt;copy()&lt;/code&gt; as suspicious methods with no obvious call sites in the code — because they're used via Kotlin destructuring which compiles away. It would flag them as dead code or unused methods. That's the false positive.&lt;/p&gt;

&lt;h3&gt;
  
  
  The gap Artur Bosch filled
&lt;/h3&gt;

&lt;p&gt;Kotlin 1.0 launched in 2016. Detekt also started in 2016. In 2016, the Android and Kotlin ecosystem was at a massive turning point. The landscape was predominantly Java-based, but the official release of Kotlin 1.0 in February sparked a quiet revolution among developers eager to escape Java's verbosity and NullPointerExceptions. It was the right time for a tool like detekt to emerge — it was a bet. If Kotlin became a success, it would become the first Kotlin static analyzer tool in the space.&lt;/p&gt;

&lt;p&gt;JetBrains was focused on adoption, not tooling — which left room for the community to fill the gap. Detekt was created by Artur Bosch in 2016 to fill that gap: a static analysis tool built specifically for Kotlin.&lt;/p&gt;

&lt;p&gt;Today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It has hundreds of contributors&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It's actively maintained&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It's widely adopted across serious Kotlin codebases&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sponsors include Emerge, CodeRabbit, PostHog, American Express, and Doist.&lt;/p&gt;

&lt;p&gt;More importantly, it has survived Kotlin's evolution — which is the real signal of maturity.&lt;/p&gt;

&lt;h3&gt;
  
  
  How detekt survived for 10 years
&lt;/h3&gt;

&lt;p&gt;Kotlin has evolved from a niche JVM language designed to fix Java's stagnation into a mature, multiplatform ecosystem backed by Google and JetBrains. Detekt emerged in 2016 with the first stable release of Kotlin and survived 10 years by adapting to Kotlin changes. It evolved from a simple standalone code smell scanner into a deeply integrated, highly extensible compiler plugin that enforces best practices, security, and architectural rules in both pure Kotlin and Android projects.&lt;/p&gt;

&lt;p&gt;Here are the major moves detekt made to adapt:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google endorsing Kotlin in 2019 → detekt became a Gradle plugin.&lt;/strong&gt; Android developers were forced to migrate from Java to Kotlin. Before the Gradle plugin, the only way to run detekt on Android was via the command line or manual Gradle task wiring. That was a barrier. A first-class Gradle plugin meant detekt could plug directly into the Android build lifecycle — run automatically on every build, integrate with lint reports, fit the workflow Android developers already had.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kotlin went multiplatform with KMP → detekt added KMP support.&lt;/strong&gt; A tool that only worked on Android/JVM would have become irrelevant to half the Kotlin community overnight.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Kotlin introduces Kotlin compiler plugin → Detekt 2.0 brings native compilation with a Kotlin compiler plugin.&lt;/strong&gt; Detekt now leverages the speed of the compiler for the analysis.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Makes Detekt Different
&lt;/h2&gt;

&lt;p&gt;Detekt doesn't operate on raw text. It uses the Kotlin compiler's PSI (Program Structure Interface).&lt;/p&gt;

&lt;p&gt;In practical terms: it understands your code the same way the compiler does.&lt;/p&gt;

&lt;p&gt;That enables deeper analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Detecting complex functions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Identifying large classes doing too much work&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Spotting unsafe patterns, not just style violations&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a key distinction from formatting tools like ktlint.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ktlint → enforces how your code looks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;detekt → evaluates how your code behaves and evolves over time&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will use the rule &lt;code&gt;ComplexMethod&lt;/code&gt;. &lt;code&gt;ComplexMethod&lt;/code&gt; is a rule of the complexity rule set. It measures the cyclomatic complexity of a function or constructor — the number of independent branching paths. It matters because a complex method is hard to maintain in a codebase. A text-based tool can count lines of code but cannot understand the structure of the code like PSI can.&lt;/p&gt;

&lt;p&gt;Let's see this snippet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;processItems&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;compute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;computeFallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;B&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nc"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HIGH&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleHigh&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="nc"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LOW&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleLow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;handleDefault&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;handleInactive&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ktlint: ✅ perfectly formatted detekt: ❌ flags &lt;code&gt;ComplexMethod&lt;/code&gt; — cyclomatic complexity: 11&lt;/p&gt;

&lt;p&gt;In this context, the issue isn't formatting — it's structural complexity that no text-based tool can measure.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Detekt Works
&lt;/h2&gt;

&lt;p&gt;Detekt cannot analyze raw source code because it is just lines and keywords without structure to analyse.&lt;/p&gt;

&lt;p&gt;That's why detekt first parses and converts raw source code into an AST (Abstract Syntax Tree). The AST gives detekt a structured representation of your code as nodes — conditions, classes, methods, variables.&lt;/p&gt;

&lt;p&gt;The parsing creates a queryable structure the rules can traverse node by node and measure: count expressions, check names, depths, compare to thresholds.&lt;/p&gt;

&lt;p&gt;Each violation found by rules during node traversal becomes an issue. At the end of the process, detekt produces a report with all found issues. Reports are produced in many formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;HTML for humans&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SARIF for CI/code scanning&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Markdown for lightweight reporting&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Rules and Rule Sets
&lt;/h2&gt;

&lt;p&gt;Rules are grouped into rule sets. Each targets a specific category of issues.&lt;/p&gt;

&lt;p&gt;Common rule sets include complexity, style, performance, potential bugs and coroutines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complexity&lt;/strong&gt; is a rule set about complexity that can be found in the code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ComplexCondition&lt;/code&gt; checks if a condition has more than 3 expressions, to ensure simplicity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temperature&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;pression&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;weight&lt;/span&gt; &lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"this is the right combination"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt flags this as &lt;code&gt;ComplexCondition&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temperature&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;pression&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"this is the right combination"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt finds no issues.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Style&lt;/strong&gt; is a rule set about code style.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;FunctionNaming&lt;/code&gt; checks if a function name complies with the Kotlin style guide.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;IsTheCarNew&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt flags this as bad naming.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;isTheCarNew&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt finds no issues.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt; is a rule set about performance issues detectable from static analysis.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;UnnecessaryInitOnArray&lt;/code&gt; flags useless initialization of arrays.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;IntArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt flags this as unnecessary initialization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;IntArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt finds no issues.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Potential bugs&lt;/strong&gt; is a rule set about bugs that can be caught by looking at the code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EqualsAlwaysReturnsTrueOrFalse&lt;/code&gt; checks if an &lt;code&gt;equals&lt;/code&gt; method always returns &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isRunning&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;

&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;isRunning&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt flags this as &lt;code&gt;EqualsAlwaysReturnsTrueOrFalse&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;isCar&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;isRunning&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;

&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isCar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;isRunning&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;isRunning&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt finds no issues.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Coroutines&lt;/strong&gt; is a rule set about the correct use of coroutines.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GlobalCoroutineUsage&lt;/code&gt; flags coroutines launched with &lt;code&gt;GlobalScope&lt;/code&gt;, which bypasses structured concurrency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;GlobalScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;record&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;fetchLastRecordFromServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;withContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;displayLastRecord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt flags this as &lt;code&gt;GlobalCoroutineUsage&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;applicationScope&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CoroutineScope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SupervisorJob&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;Dispatchers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;applicationScope&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// your coroutine work here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Detekt finds no issues.&lt;/p&gt;




&lt;h2&gt;
  
  
  Extensibility
&lt;/h2&gt;

&lt;p&gt;Out of the box, detekt rules are useful. But custom rules are where detekt becomes a real engineering tool.&lt;/p&gt;

&lt;p&gt;Detekt lets you encode your team's architecture decisions as automated guardrails. This is done by creating custom rules.&lt;/p&gt;

&lt;p&gt;Here are 3 examples of architecture decisions you can encode with custom rules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;No ViewModel should exceed a certain complexity threshold&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Repository methods must return &lt;code&gt;Result&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No direct Retrofit usage outside the data layer&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see what those check at the AST level to act as guardrails.&lt;/p&gt;

&lt;p&gt;For the ViewModel rule, we go to the class node, check if it extends &lt;code&gt;ViewModel&lt;/code&gt;, then check cyclomatic complexity, raise an issue if above threshold. The threshold can be a parameter of the rule.&lt;/p&gt;

&lt;p&gt;For the Repository rule, we go to the class node, check if it contains the keyword "repository", iterate the methods and check return type, raise issue if not &lt;code&gt;Result&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For the Retrofit rule, we visit call expression nodes, check if the call references an API service interface, then verify the containing package. If the package is outside the data layer, raise an issue.&lt;/p&gt;

&lt;p&gt;For some detail about custom rule creation: extend the &lt;code&gt;Rule&lt;/code&gt; class, implement the visitor methods you need, register the custom rule via &lt;code&gt;RuleSetProvider&lt;/code&gt;, declare in &lt;code&gt;META-INF&lt;/code&gt;, activate in &lt;code&gt;detekt.yml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is what turns detekt from a linter into an architectural safety net.&lt;/p&gt;




&lt;h2&gt;
  
  
  Production-Ready Setup
&lt;/h2&gt;

&lt;p&gt;Let's set up detekt in a real Kotlin or Android project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Add the plugin
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"io.gitlab.arturbosch.detekt"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"1.23.8"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;repositories&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;mavenCentral&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quick note about the detekt plugin ID: a new plugin ID was added in version 2 (currently in alpha) — &lt;code&gt;dev.detekt&lt;/code&gt;. For this production-grade setup, use the stable ID above.&lt;/p&gt;

&lt;p&gt;This gives you tasks depending on your project variants. For Android developers, by default you get &lt;code&gt;detektDebug&lt;/code&gt; and &lt;code&gt;detektRelease&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Add configuration
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;detekt.yml&lt;/code&gt; file. This file controls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Enabled or disabled rules&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Thresholds, such as max function length&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Build failure conditions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Report formats&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start from the default config:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/detekt/detekt/blob/main/detekt-core/src/main/resources/default-detekt-config.yml" rel="noopener noreferrer"&gt;https://github.com/detekt/detekt/blob/main/detekt-core/src/main/resources/default-detekt-config.yml&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then customize minimally. A common mistake is over-configuring too early. Start strict on a few rules, then expand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Run analysis
&lt;/h3&gt;

&lt;p&gt;Detekt gives you multiple tasks depending on what level of analysis you need.&lt;/p&gt;

&lt;p&gt;You can run the analysis without type resolution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew detekt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also run the analysis with type resolution. Type resolution gives detekt one more capability — the ability to know exactly the type and symbols across your codebase. This is particularly useful when spotting bugs or code smells.&lt;/p&gt;

&lt;p&gt;Let's see an example. There is a rule called &lt;code&gt;UnnecessarySafeCall&lt;/code&gt; that detects when you use the safe call operator unnecessarily.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// getVersionFromDb() returns String, not String?&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getVersionFromDb&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.0.0"&lt;/span&gt;

&lt;span class="c1"&gt;// detekt without type resolution: silent&lt;/span&gt;
&lt;span class="c1"&gt;// detekt with type resolution: flags UnnecessarySafeCall&lt;/span&gt;
&lt;span class="nf"&gt;getVersionFromDb&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Version: $it"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run with type resolution, use &lt;code&gt;detektDebug&lt;/code&gt; or &lt;code&gt;detektRelease&lt;/code&gt; for Android projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3.1: Activate your baseline
&lt;/h3&gt;

&lt;p&gt;With detekt you can ignore legacy debt initially with a baseline file. Here is the command to generate one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./gradlew detektBaseline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's look at the format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;SmellBaseline&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;ManuallySuppressedIssues&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ID&amp;gt;&lt;/span&gt;CatchRuntimeException:Junk.kt$e: RuntimeException&lt;span class="nt"&gt;&amp;lt;/ID&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ManuallySuppressedIssues&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;CurrentIssues&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ID&amp;gt;&lt;/span&gt;NestedBlockDepth:Indentation.kt$Indentation$override fun procedure(node: ASTNode)&lt;span class="nt"&gt;&amp;lt;/ID&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ID&amp;gt;&lt;/span&gt;TooManyFunctions:LargeClass.kt$dev.detekt.rules.complexity.LargeClass.kt&lt;span class="nt"&gt;&amp;lt;/ID&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ID&amp;gt;&lt;/span&gt;ComplexMethod:DetektExtension.kt$DetektExtension$fun convertToArguments(): MutableList&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;String&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/ID&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/CurrentIssues&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/SmellBaseline&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The baseline saves all current issues in &lt;code&gt;baseline.xml&lt;/code&gt;, letting your team move forward while keeping the codebase clean from that point in time.&lt;/p&gt;

&lt;p&gt;The workflow to progressively shrink the list: remove one issue at a time from the baseline, fix it, run detekt again. If the issue no longer appears, it's resolved. If it does, keep fixing.&lt;/p&gt;

&lt;p&gt;Quick note on &lt;code&gt;ManuallySuppressedIssues&lt;/code&gt;: these are issues you voluntarily suppress with &lt;code&gt;@Suppress&lt;/code&gt; because you accept them based on your context. This tag helps detekt avoid false positives.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Fail the build when ready
&lt;/h3&gt;

&lt;p&gt;Once the configuration is stable, add the following to your Gradle project build file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;detekt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;buildUponDefaultConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="n"&gt;allRules&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;files&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"detekt.yml"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;ignoreFailures&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set &lt;code&gt;ignoreFailures = true&lt;/code&gt; during initial rollout so detekt reports issues without blocking the build. Once your baseline is stable and the team is ready, flip it to &lt;code&gt;false&lt;/code&gt; to enforce failures in CI.&lt;/p&gt;




&lt;h2&gt;
  
  
  What's Coming Next
&lt;/h2&gt;

&lt;p&gt;In Part 2, we'll go deeper into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Writing custom rules&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integrating detekt with CI/CD properly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Avoiding rule overload&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scaling detekt across large Android codebases&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pmd.github.io/2018/12/09/PMD-6.10.0/" rel="noopener noreferrer"&gt;PMD 6.10.0 release notes — Kotlin CPD support&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://pmd.github.io/2023/03/25/PMD-7.0.0-rc1/" rel="noopener noreferrer"&gt;PMD 7.0.0-rc1 release notes — experimental Kotlin support&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/gradle/gradle/issues/7028" rel="noopener noreferrer"&gt;Gradle issue #7028&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/detekt/detekt" rel="noopener noreferrer"&gt;detekt GitHub repository&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kotlin</category>
      <category>detekt</category>
      <category>staticanalysis</category>
    </item>
  </channel>
</rss>
