Skip to content

Calculate cognitive complexity of Rust code

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
Notifications You must be signed in to change notification settings

rossmacarthur/complexity

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

complexity

Calculate cognitive complexity of Rust code.


Based on Cognitive Complexity by G. Ann Campbell.

Getting started

Add complexity to your Cargo.toml.

[dependencies]
complexity = "0.2"
syn = "1"

You'll need to bring the Complexity trait into scope, and probably some things from syn.

use complexity::Complexity;
use syn::{Expr, parse_quote};

Complexity of expressions and other syn types is as simple as calling .complexity() on an instance of that type.

let expr: Expr = parse_quote! {
    for element in iterable { // +1
        if something {        // +2 (nesting = 1)
            do_something();
        }
    }
};
assert_eq!(expr.complexity(), 3);

Examples

The implementation of cognitive complexity in this crate is heavily based on Cognitive Complexity by G. Ann Campbell. And reading it would be beneficial to understanding how the complexity index is calculated.

Loops and structures that introduce branching increment the complexity by one each. Some syntax structures introduce a "nesting" level which increases some expressions complexity by that nesting level in addition to their regular increment. In the example below we see how two nested loops and an if statement can produce quite a high complexity of 7.

use complexity::Complexity;
use syn::{ItemFn, parse_quote};

let func: ItemFn = parse_quote! {
    fn sum_of_primes(max: u64) -> u64 {
        let mut total = 0;
        'outer: for i in 1..=max {   // +1
            for j in 2..i {          // +2 (nesting = 1)
                if i % j == 0 {      // +3 (nesting = 2)
                    continue 'outer; // +1
                }
            }
            total += i;
        }
    }
};
assert_eq!(func.complexity(), 7);

But some structures are rewarded. Particularly a match statement, which only increases the complexity by one no matter how many branches there are. (It does increase the nesting level though.) In the example below we see how even though there are a lot of branches in the code (which would contribute a lot to a more traditional cyclomatic complexity measurement), the complexity is quite low at 1.

use complexity::Complexity;
use syn::{ItemFn, parse_quote};

let func: ItemFn = parse_quote! {
    fn get_words(number: u64) -> &str {
        match number {       // +1
            1 => "one",
            2 => "a couple",
            3 => "a few",
            _ => "lots",
        }
    }
};
assert_eq!(func.complexity(), 1);

An example is provided to calculate and nicely print out the cognitive complexity of each function and method in an entire Rust file. See examples/lint-files.rs. You can run it on Rust files like this:

cargo run --example lint-files -- src/

License

Licensed under either of

at your option.

About

Calculate cognitive complexity of Rust code

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published

Languages