1

I'm learning how to write Roslyn analyzers. As a toy example I created one which warn if you have assigned a property but not assigned its companion Specified property. (This is how xsd.exe generates classes for XML-schema with optional value types)

c.Prop = 1;
c.PropSpecified = true;

The aim is to show a warning if the second line is missing and offer to add it as a code fix.

Creating the analyzer was pretty straight forward and the Visual Studio template works fine with unit tests etc. The analyzer just iterates all property assignments and checks if the containing type has a property with suffix "Specified". Only special is object initializers which aren't assignments.

Also generating a C# code fix was easy:

  • clone the existing assignment
  • add "Specified" to the name
  • change the value to "true"
  • insert the new assignment after the original assignment.

Only complication is inserting does not work if the original assignment's parent only allows a single statement, like "if". Could not find a way to detect if multiple statements is supported so I just call "InsertNodeAfter" and if I get a InvalidOperationException, I create a "BlockSyntax" with original and new assignment. Then replace the original assignment with the block. Works fine in all cases I have come up with.

When it comes to a code fix for VB.Net it is a completely different story. The C# syntax tree generates correct code and even formats it for you if you add the format annotation. The VB.Net syntax tree seem to just output characters relying on "Trivia" to create and format correct code.

For example:

  • Add a new assignment when the parent is "SingleLineIf" will generate code like

If True Then x.Prop = 1 x.PropSpecified = True

which does not compile (":" is missing and must be manually added as trivia)

  • Creating an "EndBlock" (when converting a single line lambda to multiple line)
var endBlock = SyntaxFactory.EndBlockStatement(endKind, singleLineLambda.SubOrFunctionHeader.SubOrFunctionKeyword)

will generate code EndSub instead of End Sub (need space as trivia)

  • In C# I can create a "true" literal with SyntaxFactory.TrueLiteralExpression(). With VB.Net the same method requires a "token" argument. I have read the documentation many times but can't figure out what kind of token it wants me to pass in (or why). I changed it to SyntaxFactory.ParseToken("True")

My question is if I am missing something fundamental in Roslyn VB.Net code generation? Are there a set of helpers somewhere which will add the necessary trivia to get compilable code?

Tried to search for VB.Net code fixes but could not find any examples except ones just doing something trivial like replacing text.

adrianm
  • 14,468
  • 5
  • 55
  • 102

0 Answers0