Structured trivia are an interesting corner case within Roslyn. Take a look at the following syntax tree representing a simple program with regions.
Typically the terminals of a Roslyn syntax tree are pieces of trivia. However, in the above program we can see that a
RegionDirectiveTrivia has a child
RegionDirectiveTriviaSyntax syntax node.
Well, why don’t we try getting access to these syntax nodes? Originally, I tried the following:
Oddly enough (to me, at least), neither of these approaches worked and both returned nothing. They also didn’t throw or indicate any error on my part. Thankfully @Pilchie pointed out that
DescendantNodes has a couple of optional arguments.
Func<SyntaxNode, bool> descendIntoChildren -A function that decides whether or not we should descend into the children of a given node. We could use this to avoid descending into nodes we know we don’t care about.
bool descendIntoTrivia– A simple boolean that signals if we’d like to descend into the children of trivia when searching for nodes.
In our case, we’d like to search for syntax nodes within trivia, so we’ll signal that.
This time, everything works as we’d expect and we get access to our
RegionDirectiveTriviaSyntax node as expected.
So why does Roslyn avoid descending into trivia by default? My guess is performance. Most consumers of Roslyn will be looking for nodes such as methods, properties, and fields. None of these are contained within syntax trivia so it would be a waste of CPU cycles to consider their children.
This is something to be aware of when working with structured trivia and something that’s not immediately obvious.