public override Compilation Rewrite(CompilationRewriterContext context) { var compilation = context.Compilation; // Transform compilation return(compilation); }
public override Compilation Rewrite(CompilationRewriterContext context) { var compilation = context.Compilation; foreach (var syntaxTree in compilation.SyntaxTrees) { var methods = syntaxTree.FindMethodsAndCtors().ToList(); if (methods.Count > 0) { var newRoot = syntaxTree.GetRoot().ReplaceNodes(syntaxTree.FindMethodsAndCtors(), (originalNode, _) => RewriteMethodWithNullGuard(originalNode)); context.ExportRewrittenDocument(syntaxTree, newRoot); compilation = compilation.ReplaceSyntaxTree(syntaxTree, newRoot.SyntaxTree); } } return(compilation); }
public override Compilation Rewrite(CompilationRewriterContext context) => Rewrite(context.Compilation, context.ReportDiagnostic);
public override Compilation Rewrite(CompilationRewriterContext context) { var compilation = context.Compilation; // Look for Emtry{pomt var tokenSrc = new CancellationTokenSource(); var symbol = compilation.GetEntryPoint(tokenSrc.Token); if (symbol == null) { context.ReportDiagnostic(Diagnostic.Create(ThisDescriptor, Location.None, "Main entry point not found")); return(compilation); } // Fetch the method var syntaxReference = symbol.DeclaringSyntaxReferences.First(); var mainTree = syntaxReference.SyntaxTree; var root = mainTree.GetRoot(); var originalMethod = (MethodDeclarationSyntax)syntaxReference.GetSyntax(); var newMethod = originalMethod; SyntaxNode firstLocationNode = null; // Transform ExpressionBody into simple Body if (originalMethod.Body == null && originalMethod.ExpressionBody != null) { // Remove trailing ; of the expression body method var newSemiColonToken = Token(originalMethod.SemicolonToken.LeadingTrivia, SyntaxKind.None, originalMethod.SemicolonToken.TrailingTrivia); // Transform Expression body into a simple body firstLocationNode = originalMethod.ExpressionBody.Expression; newMethod = originalMethod.WithSemicolonToken(newSemiColonToken).WithExpressionBody(null).WithBody(Block(SingletonList <StatementSyntax>(ExpressionStatement(originalMethod.ExpressionBody.Expression)))); } else if (originalMethod.Body != null) { firstLocationNode = originalMethod.Body.Statements.FirstOrDefault(); } if (newMethod.Body == null) { context.ReportDiagnostic(Diagnostic.Create(ThisDescriptor, Location.None, "Main entry point empty")); return(compilation); } // Calculate the line of the first statement int nextLine = 0; if (firstLocationNode != null) { nextLine = firstLocationNode.GetLocation().GetLineSpan().StartLinePosition.Line + 1; } else { // Otherwise take whatever trailing trivia the body has var trailingTrivia = newMethod.Body.GetTrailingTrivia(); if (trailingTrivia.Count > 0) { nextLine = trailingTrivia[0].GetLocation().GetLineSpan().StartLinePosition.Line + 1; } else { // TODO: No line found? } } // Create the following code (done with https://roslynquoter.azurewebsites.net) //#line hidden //System.Console.WriteLine("Hello World from Conan!"); //#line 9 // TODO: Check if the following code is the most optimal way to manipulate efficiently the Compilation/Syntaxtrees var helloWorldFromConan = ExpressionStatement( InvocationExpression( MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, IdentifierName(Identifier("System")), IdentifierName("Console")), IdentifierName("WriteLine"))) .WithArgumentList( ArgumentList( SingletonSeparatedList( Argument( LiteralExpression( SyntaxKind.StringLiteralExpression, Literal("Hello World from Conan!"))))))) // #line number .WithTrailingTrivia(TriviaList(Trivia(LineDirectiveTrivia(Literal(nextLine), true)))) .NormalizeWhitespace(); // #line default var leadingTrivias = newMethod.GetLeadingTrivia(); leadingTrivias = leadingTrivias.Insert(0, LineDirectiveHidden()); leadingTrivias = leadingTrivias.Insert(0, CarriageReturnLineFeed); newMethod = newMethod.WithLeadingTrivia(leadingTrivias); var statements = newMethod.Body.Statements; statements = statements.Insert(0, helloWorldFromConan); newMethod = newMethod.WithBody(newMethod.Body.WithStatements(statements)); var newRoot = root.ReplaceNode(originalMethod, newMethod); // Replace the syntax tree compilation = compilation.ReplaceSyntaxTree(mainTree, newRoot.SyntaxTree); // Just store the file on the disk (but it is not used by the debugger, as we are directly working on the original file) var newMainFile = context.GetOutputFilePath("NewMain"); System.IO.File.WriteAllText(newMainFile, newRoot.ToFullString()); context.ReportDiagnostic(Diagnostic.Create(ThisDescriptor, Location.None, $"Main method successfuly modified by the HelloWorld Conan Plugin (See modified file at: {newMainFile})")); return(compilation); }
/// <summary> /// Convienient method used to log information in the output window. /// </summary> public static void ReportDiagnostic(this CompilationRewriterContext context, object message) => context.ReportDiagnostic(Diagnostic.Create(ThisDescriptor, Location.None, message));
/// <summary> /// Store the rewritten document on the disk for debugging purpose only, /// as we are directly working on the original file. /// </summary> public static void ExportRewrittenDocument(this CompilationRewriterContext context, SyntaxTree syntaxTree, SyntaxNode rootNode) { var newMainFile = context.GetOutputFilePath("Conan." + Path.GetFileNameWithoutExtension(syntaxTree.FilePath)); File.WriteAllText(newMainFile, rootNode.ToFullString()); }