Code Inspections
The IntelliJ Platform provides tools designed for static code analysis called code inspections, which help the user maintain and clean up code without actually executing it. Custom code inspections can be implemented as IntelliJ Platform plugins. An example of the plugin approach is the comparing_string_references_inspection code sample.
See the Inspections topic in UI Guidelines on naming, writing description, and message texts for inspections.
Creating an Inspection Plugin
The comparing_string_references_inspection code sample adds a new inspection to the Java | Probable Bugs group in the Inspections list. The inspection reports when the ==
or !=
operator is used between String expressions.
It illustrates the components for a custom inspection plugin:
Describing an inspection in the plugin configuration file.
Implementing a local inspection class to inspect Java code in the editor.
Creating a visitor to traverse the PSI tree of the Java file being edited, inspecting for problematic syntax.
Implementing a quick fix class to correct syntax problems by altering the PSI tree as needed. Quick fixes are displayed to the user like intentions.
Writing an HTML description of the inspection for display in the inspection preferences panel.
Creating a test for the implemented inspection and quick fix.
Although the code sample illustrates implementations of these components, it is often useful to see examples of inspections implemented in the IntelliJ Community code base. To identify a given inspection's implementation classes, try to find an inspection by name or by UI texts. Consider also searching for existing implementations in IntelliJ Platform Explorer.
Creating an Inspection
The comparing_string_references_inspection code sample reports when the ==
or !=
operators are used between String expressions. The user can apply a quick fix to change a==b
to a.equals(b)
, or a!=b
to !a.equals(b)
.
The details of the comparing_string_references_inspection
implementation illustrate the components of an inspection plugin.
Plugin Configuration File
The comparing_string_references_inspection
is described as a com.intellij.localInspection
extension point in the comparing_string_references_inspection
plugin configuration (plugin.xml
) file.
There exist two types of inspection extensions:
The
com.intellij.localInspection
extension point is used for inspections that operate on one file at a time, and also operate "on-the-fly" as the user edits the file.The
com.intellij.globalInspection
extension point is used for inspections that operate across multiple files, and the associated fix might, for example, refactor code between files.
The minimum inspection setup must declare the implementationClass
and language
attribute (unless the inspection works on any supported language). As shown in the comparing_string_references_inspection
plugin configuration file, other attributes can be defined in the localInspection
element, either with or without localization. In most cases, it is simplest to define the attributes in the plugin configuration file because the underlying parent classes handle most of the class responsibilities based on the configuration file description.
If required, inspections can define all the attribute information (except implementationClass
) by overriding methods in the inspection implementation class (not recommended in general).
Inspection Implementation Java Class
Inspection implementations for Java files, like ComparingStringReferencesInspection
, are often based on the Java class AbstractBaseJavaLocalInspectionTool
. The AbstractBaseJavaLocalInspectionTool
base class offers methods to inspect Java classes, fields, and methods.
More generally, localInspection
types are based on the class LocalInspectionTool
. Examining the class hierarchy for LocalInspectionTool
shows that the IntelliJ Platform provides many child inspection classes for a variety of languages and frameworks. One of these classes is a good basis for a new inspection implementation, but a bespoke implementation can also be based directly on LocalInspectionTool
.
The primary responsibilities of the inspection implementation class are to provide:
A
PsiElementVisitor
object to traverse the PSI tree of the file being inspected.A
LocalQuickFix
class to fix an identified problem (optional).An options panel to be displayed in the Inspections settings dialog (optional). See Inspection Options for more details.
The overridden ComparingStringReferencesInspection
methods are discussed in the sections below.
Visitor Implementation Class
The visitor class evaluates whether elements of the file's PSI tree are of interest to an inspection.
The ComparingStringReferencesInspection.buildVisitor()
method creates an anonymous visitor class based on JavaElementVisitor
to traverse the PSI tree of the Java file being edited, inspecting for suspect syntax. The anonymous class overrides visitBinaryExpression()
, which checks if a PsiBinaryExpression
's operator is ==
or !=
, and if both operand types are String
.
Quick Fix Implementation
The quick fix class acts much like an intention, allowing the user to invoke it on the PsiElement
(or TextRange
) highlighted by the inspection.
The ComparingStringReferencesInspection
implementation uses the nested class ReplaceWithEqualsQuickFix
to implement a quick fix based on LocalQuickFix
. The ReplaceWithEqualsQuickFix
class allows the user to change the use of a == b
and a != b
expression to a.equals(b)
and !a.equals(b)
respectively.
The heavy lifting is done in ReplaceWithEqualsQuickFix.applyFix()
, which manipulates the PSI tree to convert the expressions. The change to the PSI tree is accomplished by the usual approach to modification:
Getting a
PsiElementFactory
.Creating a new
PsiMethodCallExpression
.Substituting the original left and right operands into the new
PsiMethodCallExpression
.Replacing the original binary expression with the
PsiMethodCallExpression
.
Inspection Description
The inspection description is an HTML file. The description is displayed in the upper right panel of the Inspections settings dialog when an inspection is selected from the list.
See the Inspections topic in UI Guidelines on important guidelines for writing the description.
Implicit in using LocalInspectionTool
in the class hierarchy of the inspection implementation means following some conventions.
The inspection description file is expected to be located under $RESOURCES_ROOT_DIRECTORY$/inspectionDescriptions/. If the inspection description file is to be located elsewhere, override
getDescriptionUrl()
in the inspection implementation class.The name of the description file is expected to be the inspection $SHORT_NAME$.html as provided by the inspection description, or the inspection implementation class. If a short name is not provided, the IntelliJ Platform computes one by removing
Inspection
suffix from the implementation class name.
Code Snippets
Using the following HTML structure, the description can embed code snippets that will be displayed with syntax highlighting:
The language will be set according to the inspection's registration language
attribute. If required (e.g., when targeting UAST), it can be specified explicitly via <code lang="LanguageID">...</code>
.
Settings Link
To open related settings directly from the inspection description, add a link with settings://$CONFIGURABLE_ID$
, optionally followed by ?$SEARCH_STRING$
to pre-select UI element:
Inspection Test
The comparing_string_references_inspection
code sample provides a test for the inspection. See the Testing Overview section for general information about plugin testing.
The comparing_string_references_inspection
test is based on the UsefulTestCase
class, part of the JUnit framework APIs. This class handles much of the underlying boilerplate for tests.
By convention, the folder test/testData/ contains the test files. The folder contains pairs of files for each test using the name convention ∗.java and ∗.after.java, e.g., Eq.java/Eq.after.java.
The comparing_string_references_inspection
tests run the inspection on the ∗.java files, apply the quick fix, and compare the results with the respective ∗.after.java files containing expected results.
Running the Comparing String References Inspection Code Sample
The comparing_string_references_inspection code sample adds a new inspection to the Java | Probable Bugs group in the Inspections configuration.
See Code Samples on how to set up and run the plugin.
How does it work?
The plugin inspects your code opened in the IntelliJ IDEA editor. The plugin highlights the code fragments where two String
expressions are compared by ==
or !=
and proposes to replace this code fragment with .equals()
:
In this example, the str1
and str2
are variables of the String type. Invoking SDK: Use equals() will result in transforming expression to the form visible in the preview popup (code fragment on the right).