TLDR; An overview of Static Analysis and some IntelliJ IDE plugins which can help you improve your coding process.
Static Analysis is the automated analysis of source code without executing the application.
When the analysis is performed during program execution then it is known as Dynamic Analysis.
Static Analysis is often used to detect:
- Security vulnerabilities.
- Performance issues.
- Non-compliance with standards.
- Use of out of date programming constructs.
The basic concept common to all Static Analysis tools is searching source code to identify specific coding patterns that have some sort of warning or information associated with them.
This could be as simple as "JUnit 5 test classes do not need to be 'public'". Or something complex to identify like "Untrusted String input being used in an SQL execution statement".
Static Analysis tools vary in how they implement this functionality.
- source code parsing technology to create an Abstract Syntax Tree (AST),
- text Regular Expression matching,
- a combination of the above.
Regular Expression matching on text is very flexible, easy to write rules to match, but can often lead to a lot of false positives and the matching rules are ignorant of the surrounding code context.
AST matching treats the source code as program code, and not just files filled with text, this allows for more specific, contextual matching and can reduce the number of false positives reported against the code.
Static Analysis is often performed during the Continous Integration (CI) process to generate a report of compliance issues which can be reviewed to receive an objective view of the code-base over time.
Some people use Static Analysis as an objective measure of their code quality by configuring the static analysis tool to only measure specific parts of the code, and only report on a subset of rules.
The objectivity is provided by the rules used since these do not vary in their evaluation of code over time. Clearly, the combination of rules used and their configuration is a subjective decision and different teams choose to use different rules at different times.
Having the Static Analysis performed in CI is useful but might delay the feedback to the programmer. Programmers don't receive feedback when coding, they receive feedback later when the code is run through the Static Analysis tool. Another side-effect of running the Static Analysis in CI is that the results are easier to ignore.
To help make teams pay more attention to the results from Static Analysis it is usually possible to configure a threshold metric in the build process to fail the build if the metric is exceeded e.g. a number of rules triggered.
To receive feedback faster, there are many IDE plugins that run the Static Analysis rules in the IDE on demand, or periodically as the code changes.
The rule violations can then be seen in the IDE as the programmer is writing code, and to make the rules harder to ignore, the violations can often be configured to render as underlined code in the editor.
I personally find this a useful way to improve my coding, particularly when working with a new library that is covered by the Static Analysis tool. Although it can be 'noisy' with false positives, or rules you are not interested in. But this is solved by taking the extra step to configure the Static Analysis tool to ignore certain rules.
With most Static Analysis tools, the fixing of the rule is left to the programmer, so they have to understand the cause of the rule violation and how to fix it.
Very few static analysis tools also include the ability to fix the violations because the fix is so often contextual to the team and the technology used and their agreed coding styles.
False confidence in the quality of the rules may arise when the Static Analysis tools come with default rules, it is tempting to believe that they cover all the issues that a programmer might encounter, and all the circumstances that rule should apply. Sometimes the circumstances in which a rule should apply can be subtle and may not be easy to detect.
The hope is that by using a Static Analysis tool, and researching the rules and violations in more detail, that programmers will develop the skill to detect and avoid the issue in the context of their specific domain.
When the domain requires contextual rules, the Static Analysis tools may not have any rules that match your domain or library, and additionally, the tools can often be difficult to configure and expand.
None of these 'annoyances' are insurmountable:
- false positives
- lack of fixes
- configuration to ignore rules
- adding context-specific rules
But they are often used as excuses to avoid using the Static Analysis tools in the first place, which is a pity because the use of Static Analysis can be enormously useful, as a way to:
- highlight better approaches to junior developers
- gain fast feedback on clear coding violations
- identify obscure issues that the programmer has not encountered before
- reinforce that the programmer has adopted a good coding approach (when no violations are reported)
As an individual contributor to a project, I like to use Static Analysis tools that run from within the IDE so that I receive fast feedback on my code.
This supplements any pull request review process, and CI integration that a project may have.
I try to identify tools that will give me an edge, and improve my individual workflow.
When tools run in the IDE, because they tend to share the same basic GUI and configuration approach, it can be tempting to view them interchangeably.
The tools may have overlapping functionality or rule sets but to gain maximum advantage I install multiple tools to take advantage of their strengths.
The Static Analysis IDE tools I actively use when coding are:
- the inbuilt IntelliJ Inspections - common coding patterns
- SpotBugs - common errors
- SonarLint - common usage patterns
- CheckStyle - common style patterns
- Sensei from Secure Code Warrior - custom rule creation
I use them all because they work well together to augment and supplement each other.
If you use IntelliJ then you are already using their Inspections.
These are Static Analysis rules which are flagged in the IDE. Some of them also have QuickFix options to rewrite the code to address the issue.
The rules are configurable on and off, and to choose the error level used to highlight it in the IDE.
There are a lot of good IntelliJ Inspections. I know that because I read through them while writing this. I use the IntelliJ Inspections as the defaults and haven't configured them, but to gain full value from the Inspections you should read through them, identify those relevant to your coding style, and configure the warning level so that you notice them in the code.
The great thing about the IntelliJ Inspections is that they come free with the IDE and they help build the muscle memory of:
- noticing warnings and errors in the source as you write code
- hovering the mouse over flagged code to learn the rule violations
alt+enterto apply a QuickFix for the issue
The SpotBugs IntelliJ plugin uses Static Analysis to try and alert you to bugs in your code.
SpotBugs can be configured from the IntelliJ Preferences to scan your code, the actual rules used can be found in the Detector tab.
I tend to use SpotBugs after I've written and reviewed my code, then I'll run the 'Analyze Project Files Including Test Sources'.
This does help me identify bugs, dead code, and obvious optimizations. It also forces me to research some of the flagged violations to help me decide what to do.
SpotBugs will find issues but does not offer any QuickFix actions to attempt to resolve the issues.
SpotBugs is easy to configure and I find it to be a useful objective second opinion to consult in my IDE.
The SonarLint plugin.
SonarLint can be configured from the IntelliJ Preferences to select which rules the code is validated against.
By default, SonarLint runs in realtime and shows issues for the current code that you are editing.
SonarLint does not offer quick fixes but the documentation associated with the violation reports is usually clear and well documented.
I've found SonarLint to be useful in the past for alerting me to new Java features that I was aware of in the newer versions of Java.
The CheckStyle plugin offers a mix of formatting and code-quality rules.
The CheckStyle plugin comes bundled with 'Sun Checks' and 'Google Checks'.
The definitions of these can be easily found online.
CheckStyle adds the most value when a project has spent the time creating its own ruleset. Then the IDE plugin can be configured to use that ruleset and programmers can perform a scan, prior to committing the code to CI.
CheckStyle is very often used as a build failing plugin for CI processes when the number of CheckStyle violations exceeds a threshold.
Sensei uses Static Analysis based on an Abstract Syntax Tree (AST) for matching code and for creating QuickFixes, this allows for very specific identification of code with issues.
The AST allows QuickFixes associated with a recipe to understand the surrounding code e.g. when adding a new class into the code, any import for that class will only be added to the source file once, and not for each replacement.
Sensei was created to make it easy to build custom matching rules which may not exist, or which would be hard to configure, in other tools.
Rather than amend a configuration file, all the configuration can be performed in the GUI. When creating new recipes the GUI makes it easy to see which code the recipe matches. And when defining the QuickFixes the before and after state of the code can be compared immediately. This makes it easier to create very contextual recipes i.e. unique to teams, or technology, and even individual programmers.
I use Sensei in combination with other Static Analysis tools e.g. most Static Analysis tools will find issues, but not fix them. A common use case for Sensei is to replicate the other tool's matching search in Sensei, and expand it with a Quick Fix. This has the benefit that the custom fix applied already meets the coding standards for your project.
I periodically find myself creating Sensei recipes that already exist in the IntelliJ Intensions set because the Intension report doesn't quite match the context I've created or because the QuickFix provided by IntelliJ doesn't match the code pattern I want to use.
I augment the existing tools, rather than attempt to fully replace them.
Sensei can also be very useful when you identify a contextual variant of a common rule e.g. if you are using an SQL library not supported by the Static Analysis tool, but the common SQL rules in the Static Analysis engine still apply, then you can create library-specific variants of those rules using Sensei.
Sensei does not come out of the box with a lot of generic recipes like the Static Analysis tools mentioned, its strength is in making it easy to create new recipes, complete with QuickFixes configured to match your specific coding style and use-cases.
NOTE: we are working on a public repository of recipes to cover generic use-cases, and you can find it here.
I tend to pick tools that work together, are configurable, and easy to expand to meet my specific context. I've used Static Analysis tools in the IDE for years to help me identify issues, and learn more about the programming languages and libraries I use.
I use all of the tools mentioned in combination:
- IntelliJ Intentions helps flag common code issues out the box, often with associated QuickFixes.
- SpotBugs finds simple bugs I might have missed and alerts me to performance issues.
- SonarLint identifies Java features I was unaware of and prompts me to additional ways of modelling my code.
- CheckStyle helps me conform to an agreed coding style that is also enforced during CI.
- Sensei helps me create QuickFixes to augment common scenarios found by Static Analysis tools and create specific project or technology recipes that can be hard to configure in another tool.
You can install Sensei from within IntelliJ using "Preferences \ Plugins" (Mac) or "Settings \ Plugins" (Windows) then just search for "sensei secure code". Or install from the Jetbrains Marketplace Online