Reputation: 2488
I am using Roslyn to generate a big amount of code (about 60k lines).
The problem comes when I use Formatter.Format()
to format the whitespace. The actual formatting takes way too long (~60k lines in ~200s
).
Used code.
public string GenerateCode()
{
var workspace = new AdhocWorkspace();
OptionSet options = workspace.Options;
options = options.WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInMethods, true);
options = options.WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInProperties, true);
CompilationUnitSyntax compilationUnit = CreateCompilationUnit();// this method builds the syntax tree.
SyntaxNode formattedNode = Formatter.Format(compilationUnit, workspace, options);
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
formattedNode.WriteTo(writer);
}
return sb.ToString();
}
I came to a realization, that a human readable formatting is not essential (still would be nice). I stopped formatting the code but then the generated code is actually unable to compile. That is because some keywords don't have the necessary whitespace around them. For example "publicstaticclassMyClass".
I tried different options of the Formatter
but none were sufficient.
Then I was looking for an alternative "minimal" formatter. To my knowledge, there isn't any.
Finally, I managed to solve this by putting extra whitespace in the identifiers themselves.
var className = "MyClass";
SyntaxFactory.ClassDeclaration(" " + className)
.AddModifiers(
// Using explicit identifier with extra whitespace
SF.Identifier(" public "),
SF.Identifier(" static "));
// Instead of the SyntaxKind enum
//SF.Token(SyntaxKind.PublicKeyword),
//SF.Token(SyntaxKind.StaticKeyword));
And for the code generation.
public string GenerateCode()
{
var workspace = new AdhocWorkspace();
CompilationUnitSyntax compilationUnit = CreateCompilationUnit(); // this method builds the syntax tree.
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
compilationUnit.WriteTo(writer);
}
return sb.ToString();
}
This way the generation is much faster (~60k lines in ~2s
Not really lines since it is not formatted but it is the same amount of code). Although this works, it seems kinda hacky. Another solution might be to create an alternative Formatter
but that is a task i don't wish to undertake.
Did anyone come up with a better solution? Is there some way to use the Formatter
more efficiently?
Note: The time measurements provided include the time of building the syntax tree and several other procedures. In both cases the formatting is about 98% of the measured time. So it is still possible to use them for comparison.
Upvotes: 2
Views: 1494
Reputation: 2468
The "minimal formatter" you're looking for is the .NormalizeWhitespace()
method.
It's not suitable for code you intend humans to maintain, but I'm assuming that shouldn't be an issue since you're dealing with a 60k line file!
Upvotes: 1