Better C++ Syntax Highlighting - Part 2: Enums
Enums are a great starting point as their declarations are simple and their usage easy to follow. Consider the following example:
The AST for this snippet looks like this:
Enum Declarations
Enums are represented by two node types in the AST: an EnumDecl node for the declaration itself, and an EnumConstantDecl node for each enum constant.
From the EnumDecl node above, we can infer that Level is declared as an enum class, and that it’s underlying type is an int.
If we had explicitly set this to a type like unsigned char or std::uint8_t, this would be also reflected in the AST.
We’ll set up visitors for both EnumDecl and EnumConstantDecl nodes:
The implementation of VisitEnumDecl looks like this:
This inserts an enum-name annotation for every enum declaration.
The return value of a visitor function indicates whether we want AST traversal to continue.
Since we are interested in traversing all the nodes of the AST, this will always be true.
As mentioned in the previous post in this series, the SourceManager class maps AST nodes back to their source locations within the translation unit.
The isInMainFile() check ensures that the node originates from the “main” file we are annotating - the one provided to runToolOnCodeWithArgs.
This prevents annotations from being applied to external headers, and is a recurring pattern in every visitor we will implement.
The visitor for EnumConstantDecl nodes is nearly identical, except that it inserts an enum-value annotation instead of enum-name:
With both visitors implemented, our tool produces the following output:
This is a good start, but it’s not yet complete.
The references to Error on line 6 and 12 are not declarations, so we’ll need a new visitor to annotate these.
Enum References
References to enum values are captured by DeclRefExpr nodes, which represent expressions that refer to previously declared variables, functions, and types.
This is confirmed by line 21 of the AST, which represents the Level::Error reference in main():
We’ll add a new visitor for DeclRefExpr nodes:
The implementation of VisitDeclRefExpr is very similar to the VisitEnumDecl and VisitEnumConstantDecl visitor functions:
We use getDecl() to retrieve information about the underlying declaration being referenced.
If it’s an EnumConstantDecl, we insert an enum-value annotation for the node.
With this visitor implemented, we are able to annotate references to enum constants as well:
Styling
The final step is to add definitions for the enum-name and enum-value CSS styles:
We’ve configured the first (of many!) visitors to handle enum declarations and references to enum constants, and established some common patterns that we’ll use throughout this series. In the <LocalLink text={“next post”} to={“Better C++ Syntax Highlighting - Part 3: Namespaces”}>, we’ll expand our tool to annotate namespaces. Thanks for reading!