ReSharper allows suppressing configurable highlights with specially formatted comments, such as:
Similarly, highlights relating to compiler warnings are not shown if the warnings are disabled in project settings, or via a
#pragma directive. Highlights are also not shown in generated files, or code regions that should be treated like generated code, as specified in the Generated Code options page.
ReSharper will display all highlights that the daemon stage process returns for a specific file. It is up to the daemon stage process itself to perform the appropriate filtering, based on the file's language and requirements. The daemon stage can use the
FilteringHighlightingConsumer class to perform the filtering as the results are collected during analysis.
IDaemonStageProcess.Execute method expects a
DaemonStageResult that contains a list of highlights to apply. To make it easier to capture this list, ReSharper provides a couple of implementations of the
IHighlightingConsumer interface. This interface provides context, such as access to settings, as well as a method to consume a highlight. They also return the list of highlights to be used in
DaemonStageResult. Typically, a daemon process will create one of these classes and pass it to the code doing the actual analysis, which will add highlights as it works.
The default implementation
DefaultHighlightingConsumer is a simple class, and captures all highlights passed to it. This is useful for languages where filtering is not appropriate - perhaps the language doesn't support comments, or have compiler warnings.
FilteringHighlightingConsumer class will check that the highlight should be shown before it's added to the list. The class will, in priority order:
Filter out any highlights with a severity of
Always include highlights with a severity of
Filter out all other highlights for non-user files (such as decompiled files).
Include highlights that correspond to compiler errors.
Filter out all highlights in a generated file, or that are located in a generated region.
Filter out compiler warnings that have been disabled via
Filter highlights by specially formatted comments.
A typical daemon stage process
Execute method that wanted to take advantage of
FilteringHighlightingConsumer would look like this:
This creates a new instance of
FilteringHighlightingConsumer, passing in the daemon stage, the current settings store and the file that will be processed. The consumer is then used to collect highlights, in this case via the
MyRecursiveElementProcessor class that is being called for all nodes in the syntax tree. This is all there is to it. Highlights are now appropriately filtered.
Any daemon stage process deriving from
CSharpIncrementalDaemonStageProcessBase will automatically get this functionality.
Working with custom languages
As long as a daemon stage process is for an existing language, there is no need to worry about how
FilteringHighlightingConsumer gets the information required to correctly filter highlights. Adding a custom language would usually require adding some new per-language services that
FilteringHighlightingConsumer will use if available.
FilteringHighlightingConsumer class will filter out all highlights (apart from compiler errors and info highlights) that are in generated files or regions of a file that are marked as generated. A file is considered to be a generated file if it's
IPsiSourceFile.Properties.IsGeneratedFile property returns
These file properties usually come from the current project, but can also be set via the Generated Code options page, by directory, file name or file name mask. It can also be programmatically overridden by implementing
A generated code region is provided by implementing an instance of "IFileStructureIndex".
File structure explorers
Generated regions, comment regions and compiler warning/pragma regions are discovered by implementations of
IFileStructureExplorer. These classes will process a file looking for comments, regions (as in
#region) and pragma directives that describe ares of code that should have highlights filtered.
ReSharper ships with one implementation per language, but it is possible to have more than one for a particular language. Each implementation should be marked with the
IFileStructureExplorer.Run method will generate an instance of a class that derives from
IFileStructure that lists regions of generated code, as well as block ranges for comments, and pragmas. ReSharper provides the
FileStructureWithRegionsBase classes to provide a lot of functionality. A derived class will implement
Run, and walk the file's syntax tree. If it encounters a comment node, it can pass the node and the comment text to the
FileStructureBase.ProcessComment method, which will parse the comment text and add a generated code region, if appropriate. Similarly, preprocessor directives such as
#pragma can pass the tree node, a list of compiler IDs and a flag to indicate if the warnings are being enabled or disabled. Finally, if the class derives from
FileStructureWithRegionBase, it can call
ProcessEndRegion to handle C# style
#region nodes. The text for matching region names comes from settings -
Compiler errors and warnings
FilteringHighlightingConsumer class will also filter out applicable compiler and error warnings. Highlights are checked for equivalent compiler IDs. If they exist, and the highlight has a severity of error, then the highlight is always displayed, regardless of regions.
Warnings are treated slightly differently. If a highlight has a compiled ID, but is a warning, it is not automatically filtered out. If the highlight is an instance of
HighlightingInfoWithOverrides and either
OverriddenAttributeId is set, the highlight is always shown.
Otherwise, the per-language
ICompilerWarningPreProcessor class is used, if it exists. This will check the compiler IDs for the file, usually by checking project settings such as current warning level - for example, a highlighting that represents a level 4 warning when the project is set to level 3 will be suppressed. It will also look to see if the warning should be upgraded to an error, if the "treat warnings as errors" project setting is enabled.
ReSharper uses the
CompilerIDs property of the
[RegisterConfigurableSeverity] assembly attribute to specify compiler IDs for a highlight. This value can be a single ID, or a comma separated list of IDs. ReSharper will also use the
[CompiledIdForLanguage] assembly attribute to set up a mapping between a highlight ID, a language and a compiler warning ID.