Project File Language Service
If a custom language defines a
ProjectFileType, it must also associate that file type with a PSI language type, which ReSharper can use to build a PSI tree of the file's contents. The
IProjectFileLanguageService interface provides this functionality, and can be considered as a bridge between the Project Model and the PSI.
The project file language service is implemented as a per-file type component. Given a
ProjectFileType, it is possible to retrieve that file type's project file language service, which exposes the custom language's
PsiLanguageType. This can be used as the key to retrieve all per-language components, and get access to the custom language's lexer and parser, to build a PSI tree.
IProjectFileLanguageService interface is as follows:
The members are as follows:
LanguageType- confusingly called
LanguageType, this is the singleton instance of the derived
ProjectFileTypeclass that represents the Project Model file type of this language.
IconIdof the icon used to represent this file. This is used whenever ReSharper needs to display the icon for a file of this type, such as in the Find Results tool window. See the section on icons for more details on icons.
GetPreprocessorDefines- retrieves a list of preprocessor symbols that are defined for the current project, as this affects the parsing of the PSI tree. This is typically only required for compiled languages in a project where the project itself has a specific language, e.g. a C# project.
The GetPsiLanguageType method
GetPsiLanguageType method returns the
PsiLanguageType derived instance that represents the custom language of the given project file. Generally speaking, this is very simple to implement, and involves returning the static instance of the PSI language type, after checking the
IProjectFile.LanguageType is the required
ProjectFileType (or a derived instance thereof). For example:
Note that we return
UnknownLanguage.Instance if the actual language instance isn't available. This can happen if the language feature has been disabled.
This method can be a bit more complex. For example, the
PSI source file properties
GetPsiProperties method returns an instance of
IPsiSourceFileProperties that defines how the given file should be handled by the PSI, such as if a PSI tree should be built for the file.
Typically, this can be an instance of, or derived from
DefaultPsiProjectFileProperties, which provides a default implementation, given an
IProjectFile and an
IPsiSourceFileProperties interface is as follows:
The interface members are:
trueif ReSharper should build a PSI tree of this file. The default implementation will return
ProjectFileTypeis a known language.
trueif the file is generated. ReSharper will build a PSI tree for the file, but won't run inspections. The default implementation defers to
GeneratedUtils.IsGeneratedFile, which verifies the file name and path against the masks in the Generated Code options page.
IsICacheParticipant- this is a flag to indicate if the caching subsystem should be notified whenever the file is changed. This is typically
trueif this file contributes to the semantic code model of the project. If
false, functionality such as inspections and rename is not available. Generally, this value matches
ShouldBuildPsi, but can be different for features such as "external sources" - decompiled or downloaded source files.
trueif the file is not a user-editable file. This is similar to
IsGeneratedFilebut does not indicate that the code is generated. Inspections and modifications are disabled when this value is
GetPreImportedNamespaces- returns a list of namespaces that are implicitly imported. For example,
.aspxpages can have namespaces imported by entries in the
string.Emptyif not required.
GetDefines- returns the pre-processor symbols defined for the project. Again, this comes from the project settings, and only makes sense for compiled languages, such as C#.
GetMixedLexerFactory method returns a factory that is used to create the lexer for a file of this type. Typically, this is just a call to the PSI language service's
However, if the file type is a "mixed" file, that is, it contains secondary PSI trees, such as an
MixedProjectFileLanguageService will provide a suitable implementation here. See the section on Secondary PSI files for more details.
Default base classes
ReSharper provides the
MixedProjectFileLanguageService abstract base classes that provide a good base implementation of
IProjectFileLanguageService. While many of the type members are virtual, the only abstract members that need implementing are:
MixedProjectFileLanguageServiceprovides a default implementation of this.
Custom PSI properties provider
Some languages also implement
IProjectFileCustomPsiPropertiesProvider, which is a per-file type component that will return a specific subclass of
This is also a bridge between the Project Model and the PSI, as it provides access to custom project properties, via the
GetCustomProperties<T> extension method on
IPsiSourceFile. For example, using this extension method on a C# file can retrieve the
ICSharpPsiSourceFileProperties interface, which provides a
WarningsAsErrors property. This allows PSI based inspections and analyses to set the severity level of a highlight.