Skip to content

Repository files navigation

Rough Analyzer

A lightweight, extensible static analysis tool for the Kotlin programming language, built as a Gradle plugin. This project was developed as part of a diploma thesis at the School of Computing, Union University.

Motivation

While powerful tools like Detekt offer a comprehensive suite of static analysis rules, they can sometimes have a steep learning curve for teams that need to implement highly specific, domain-centric rules.

Rough Analyzer aims to fill that gap. It provides a simple, transparent, and easily extensible framework that empowers development teams to quickly implement their own coding standards without the overhead of a complex, industrial-grade tool. It serves as both a practical utility and an educational resource for understanding the application of compiler theory concepts, such as Abstract Syntax Tree (AST) traversal.

Features

Rough Analyzer ships with a set of fundamental rules to help improve code quality and reduce technical debt:

  • Long Function Rule: Flags functions that exceed a configurable line count.
  • Cyclomatic Complexity Rule: Calculates and flags functions with high cyclomatic complexity.
  • Magic Number Rule: Detects hardcoded numerical literals ("magic numbers").
  • Println Usage Rule: Discourages the use of println and print in production code.

Example Output

Here is a sample output when running Rough Analyzer on a real-world Android project. The report is clear, actionable, and helps pinpoint exact locations of code quality issues.

> ./gradlew roughAnalyzer

Analysis finished. Found 329 issues:

/app/src/main/java/com/raf/catalist/cats/quiz/QuizQuestionScreen.kt
  Function 'CongratulationsScreen' is too long (118 lines). Maximum allowed is 80. - [long-function]
    at /app/src/main/java/com/raf/catalist/cats/quiz/QuizQuestionScreen.kt:384:5

  Magic number '150' found. Extract it to a named constant. - [magic-number]
    at /app/src/main/java/com/raf/catalist/cats/quiz/QuizQuestionScreen.kt:401:23

/app/src/main/java/com/raf/catalist/users/details/UserDetailsEditScreen.kt
  Cyclomatic complexity of function 'UserEdit' is 16 (threshold is 15). - [cyclomatic-complexity]
    at /app/src/main/java/com/raf/catalist/users/details/UserDetailsEditScreen.kt:86:5

/app/src/main/java/com/raf/catalist/cats/repository/BreedsRepository.kt
  Magic number '10' found. Extract it to a named constant. - [magic-number]
    at /app/src/main/java/com/raf/catalist/cats/repository/BreedsRepository.kt:63:59

---
Total issues found: 329
329 warnings

Setup and Usage

As a Gradle plugin, Rough Analyzer is designed to be integrated directly into your build process.

Step 1: Publish the Plugin Locally

Before using it in another project, you need to publish the analyzer to your local Maven repository. Clone this repository and run:

./gradlew publishToMavenLocal

Step 2: Configure Your Target Project

In the Kotlin/Gradle project you want to analyze, make the following changes:

  1. In your settings.gradle.kts file, add mavenLocal() to the pluginManagement repositories block. This tells Gradle to look for plugins on your local machine.

    pluginManagement {
        repositories {
            mavenLocal() // Add this line
            google()
            mavenCentral()
            gradlePluginPortal()
        }
    }
  2. In your module's build.gradle.kts file (e.g., app/build.gradle.kts for Android), apply the plugin.

    plugins {
        // ... your other plugins
        id("rs.raf.student.rough-analyzer") version "1.0-SNAPSHOT"
    }

Step 3: Run the Analysis

After syncing your project, you can run the analysis by executing the roughAnalyzer task from your terminal:

./gradlew roughAnalyzer

Configuration

You can customize Rough Analyzer's behavior in two ways:

1. Specifying the Source Directory

By default, Rough Analyzer looks for Kotlin files in src/main/kotlin. This is fine for pure JVM projects, but Android projects typically place Kotlin files in src/main/java.

You can easily configure this in your module's build.gradle.kts:

// In app/build.gradle.kts
plugins {
    id("rs.raf.student.rough-analyzer") version "1.0-SNAPSHOT"
    // ...
}

// Add this block to point to the correct directory
roughAnalyzerConfig {
    sourceDir.set("src/main/java")
}

android {
    // ...
}

2. Configuring Rules with rough-analyzer.yml

To enable/disable rules and set custom thresholds, create a file named rough-analyzer.yml in the root directory of your project. If this file is not found, default values will be used.

Here is an example configuration tailored for a Jetpack Compose project, which often has longer functions:

# rough-analyzer.yml

longFunction:
  active: true
  # Compose functions can be longer, so we are more generous
  threshold: 80

cyclomaticComplexity:
  active: true
  # UI logic can sometimes justify higher complexity
  threshold: 15

magicNumber:
  active: true

printlnUsage:
  active: false # Disable this rule for a project still in heavy development

How It Works

Rough Analyzer's architecture is built on a few key principles:

  • Kotlin Compiler API: It uses the org.jetbrains.kotlin:kotlin-compiler-embeddable library to parse Kotlin source code into a Program Structure Interface (PSI) tree, which is a concrete implementation of an Abstract Syntax Tree (AST). This provides a rich, semantically-aware representation of the code.
  • Visitor Pattern: Each rule is implemented as a KtTreeVisitorVoid, which traverses the PSI tree. This pattern cleanly separates the analysis logic (the "operations") from the code structure (the "elements").
  • Modularity: The core AnalyzerEngine is completely decoupled from the rules themselves. It operates on a List<Rule>, making it trivial to add new rules without modifying the engine, adhering to the Open/Closed Principle.

About

A lightweight, extensible static analysis tool for Kotlin. Diploma thesis project.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages