Composite Node Types
The interior nodes of the tree have a node type that typically derives from
CompositeNodeType. ReSharper doesn't have any strict requirements for the node type of an interior tree node, unless the custom language implements tree node caching, in which case, the node type must implement the
ICompositeNodeType.Create returns an implementation of
ITreeNode that uses ReSharper's own base classes. The
Create method is only used by the parser (via the
TreeElementFactory.CreateCompositeElement static method) to create an
ITreeNode from a known node type.
If a custom language is using ReSharper's base
ITreeNode classes, it should also use
CompositeNodeType as the base class for all interior tree node types. This base class has no additional functionality over
NodeType, and simply provides an abstract method to create the
CompositeElement base tree node instance.
Composite node type hierarchies
The class hierarchy for composite node types is very flat. A custom language should create its own composite node type base class. It adds no functionality, but acts as a common base class for all derived composite node types for the language. For example, CSS creates
The base class simply takes in a string identifier, such as
"ID_SELECTOR", used only for diagnostics and testing, and an index to uniquely identify the node type within the language. This index must not clash with any existing indexes used for that language - token or composite node types.
All composite node types of the custom language should be created as derived classes of this language-specific composite node type. The only extra functionality required in these derived classes is to provide an implementation for the
Create method, by creating an
ITreeNode that represents that tree node. For example:
See the section on Creating Node Types for an explanation of the private nested class structure.
Create method will create an
ITreeNode instance. There is no need to pass any parameters - the position of the element is implied by its predecessor nodes (and cached and invalidated if the tree is altered). Given the start and end offset, it's possible to get the total text for the node and all associated child nodes.
There is also no need to pass details about the content of the node, as this information is made available via child nodes. For example, a node that represents a C# assignment operation will have children that represents the left hand side identifier, the equals sign and the right hand side expression. The left hand side node can have further child nodes to expose qualifications (
this.value = …) or can be a leaf node that exposes the identifier directly.