IntelliJ Platform Plugin SDK Help

Inspection Options

Some code inspections provide configuration options that affect their behavior. For example, Java | Code style issues | 'size() == 0' can be replaced with isEmpty(), allows ignoring classes from the defined list or expressions, which would be replaced with !isEmpty().

Currently, there are two ways of providing the inspection options:

Declarative Inspection Options

Declarative API allows to:

  • delegate component rendering to the platform and make all the inspection options UI consistent and compliant with the UI Guidelines

  • optimize checking whether the inspection contains any options

  • manipulate options in places other than inspection panels (e.g., in quick fixes)

  • render options in contexts other than IntelliJ Platform-based IDEs

Providing the inspection options is achieved by implementing InspectionProfileEntry.getOptionsPane(), which returns an OptPane object describing available configuration possibilities. Note that InspectionProfileEntry is a parent of inspection base classes like LocalInspectionTool and GlobalInspectionTool.

Building the inspection options is achieved by using a DSL-like facade, which contains methods for creating option controls and binding them to the fields declared in an inspection class.

Building the options for Java | Code style issues | 'size() == 0' can be replaced with 'isEmpty()' is implemented as follows:

public OrderedSet<String> ignoredTypes = new OrderedSet<>(); public boolean ignoreNegations = false; @Override public @NotNull OptPane getOptionsPane() { return pane( stringList( "ignoredTypes", message("options.label.ignored.classes"), new JavaClassValidator()), checkbox( "ignoreNegations", message("")) ); }

The above example builds a form with two options (see SizeReplaceableByIsEmptyInspection for the full implementation context):

  • List of strings, which are validated for being Java classes. The provided list is bound to the ignoredTypes field in the inspection class.

  • Checkbox, which value is bound to the boolean ignoreNegations field in the inspection class.

The OptPane class exposes methods for building fields of other types, e.g., number or dropdown fields.

Note that the bind identifiers passed as a first string argument of methods creating form controls contain injected references that resolve to the bound fields. It enables resolving and other resolve-related features available, making it easy to rename fields and minimizing the risk of introducing typos resulting in bugs, as unresolved references will be highlighted as errors.

Custom Options Binding Protocol

The default way of binding option form values to fields may be insufficient in more advanced cases. It is possible to customize the way of binding options by providing a custom OptionController from InspectionProfileEntry.getOptionController() method.

Consider the Properties files | Inconsistent resource bundle global inspection, from bundled Properties plugin in IntelliJ IDEA, which reports several types of inconsistencies in .properties files. The inspection allows enabling or disabling reporting specific issue types, which are reported by providers implementing a dedicated interface. Information about enabled providers is stored in a map where the key is a provider ID. The options panel and value binding are implemented in the following way (see InconsistentResourceBundleInspection for the full implementation context):

private NotNullLazyValue<InconsistentResourceBundleInspectionProvider[]> myProviders = ...; private Map<String, Boolean> mySettings = new LinkedHashMap<>(); @Override public @NotNull OptPane getOptionsPane() { return new OptPane( myProviders.getValue(), provider -> checkbox(provider.getName(), provider.getPresentableName()))); } @Override public @NotNull OptionController getOptionController() { return OptionController.of( (bindId) -> ContainerUtil.getOrElse(mySettings, bindId, true), (bindId, value) -> { boolean boolValue = (Boolean)value; if (boolValue) { mySettings.remove(bindId); } else { mySettings.put(bindId, false); } }); }

Option controls panel is built based on providers’ IDs and presentable names. This implementation doesn't need to be changed regardless of removing or adding new providers in the future.

Reading and writing options in the map is achieved by registering a custom controller with getter and setter logic provided to the OptionController.of() method.

It's possible to compose several option controllers into the hierarchy based on the bindId prefix. It may be useful when some inspections have common configuration options and store the configuration in dedicated objects. See OptComponent.prefix() and OptionController.onPrefix() methods for more details and example implementation: MissingJavadocInspection.

Non-Profile Inspection Options

Sometimes, inspections use options that are rendered in a non-standard way, or are shared with other inspections or other IDE features. Such a shared configuration can be implemented as a persistent component and not have a single owner. It is still convenient to be able to configure these options from the inspection panel.

An example of such a case is the Java | Probable bugs | Nullability problems | @NotNull/@Nullable problems inspection, which contains the Configure Annotations… button that opens the Nullable/NotNull Configuration dialog.

Custom Swing controls can be provided by implementing CustomComponentExtensionWithSwingRenderer and registering the implementation in the com.intellij.inspectionCustomComponent extension point. Please note that this API is still in experimental state and may be changed without preserving backward compatibility.

Example: JavaInspectionButtons providing buttons for configuring options in custom dialogs

UI-Based Inspection Options

UI-based inspection options are provided by implementing a configuration panel using Swing components and returning it from InspectionProfileEntry.createOptionsPanel() method. It returns the panel with option components that bind the provided values to the inspection class fields or other properties, similarly as in the declarative approach. Note that since version 2023.1, this method is ignored if InspectionProfileEntry.getOptionPane() returns a non-empty panel.

Example: SizeReplaceableByIsEmptyInspection in version 2022.3, implemented using the UI-approach

For simple customization requirements, see also:

Last modified: 13 June 2024