Skip to content
This repository has been archived by the owner on Dec 12, 2020. It is now read-only.

Enhance Walkthrough Troubleshooting Tipps #186

Open
ZeeOcho opened this issue Jan 1, 2020 · 2 comments
Open

Enhance Walkthrough Troubleshooting Tipps #186

ZeeOcho opened this issue Jan 1, 2020 · 2 comments

Comments

@ZeeOcho
Copy link

ZeeOcho commented Jan 1, 2020

I would like to propose to add some hints to the walkthrough that may make setup and troubleshooting easier. They are the result of me implementing my first code generator, so this can be considered user feedback :). I should note that I did not have any previous experience in Roslyn based code generation, so some of this might be obvious for people that used it before.

Following the example Code Generator was quite easy for me (I needed to do quite some updating of VS and Windows, but I got it running quite straight forward). I had some errors in my own implementation of my code generator and wasn't quite sure how to troubleshoot them. The following bits of information would have probably helped me with that.

  1. Each source file containing code generation attributes will result in corresponding .generated.cs - files in the /obj/ - Directory of the project. They contain the code generated from your generator.

  2. If your code generator throws an exception in the ICodeGenerator.GenerateAsync or IRichCodeGenerator.GenerateRichAsync, it will result in 2 errors in the build process. One is containing the type and text of the exception, the other will say (somewhat obscure) "MSB3073 The command "dotnet codegen "@obj\Debug\netstandard2.0\CodeGenTest1.csproj.dotnet-codegen.rsp"" exited with code 3 beendet." (translated from german, so the text might not be accurate.
    image

  3. You can output messages to the build log:

3.1 You can output messages to the build log by using the IProgress<Diagnostic> progress parameter, like this:

progress.Report(Diagnostic.Create(
    new DiagnosticDescriptor("CA1001", "Cannot apply attribute to non-partial class", "Make class partial", "Microsoft.Design", DiagnosticSeverity.Error, true)
    , Location.Create(applyToClass.SyntaxTree, applyToClass.Span)));

3.2 Or use the CodeGeneration.Roslyn.Logger extension methods like this:

Logger.Error("This message comes from Logger extension", "SOMECODE");

Giving you the following build log in VS:
image

  1. If you Console.WriteLine in your code generator, it will show up in your build output window in VS.
@amis92
Copy link
Collaborator

amis92 commented Jan 5, 2020

Thanks! Those are valuable insights, it's so nice of you to share them! I'll attempt to incorporate them when time allows.

@amis92 amis92 added this to the Backlog milestone Mar 26, 2020
@daiplusplus
Copy link

daiplusplus commented Apr 18, 2020

Another trick I'm using is to invoke System.Diagnostics.Debugger.Launch() inside my ICodeGenerator implementation's constructor - thus whenever I build my project, I get a debugger popup which then lets me set breakpoints in the GenerateAsync method.

This can probably be improved by only calling Launch() if a certain environment variable is set or .csproj property set.

public class DuplicateWithSuffixGenerator : ICodeGenerator
{
	private readonly string suffix;

	public DuplicateWithSuffixGenerator( AttributeData attributeData )
	{
		this.suffix = (string)attributeData.ConstructorArguments[0].Value;

		System.Diagnostics.Debugger.Launch();
		while( !System.Diagnostics.Debugger.IsAttached )
		{
			Thread.Sleep( 500 ); // eww, eww, eww
		}
	}

	public Task<SyntaxList<MemberDeclarationSyntax>> GenerateAsync( TransformationContext context, IProgress<Diagnostic> progress, CancellationToken cancellationToken )
	{
		// Our generator is applied to any class that our attribute is applied to.
		ClassDeclarationSyntax applyToClass = (ClassDeclarationSyntax)context.ProcessingNode;

		// Apply a suffix to the name of a copy of the class.
		ClassDeclarationSyntax copy = applyToClass.WithIdentifier(SyntaxFactory.Identifier(applyToClass.Identifier.ValueText + this.suffix));

		// Return our modified copy. It will be added to the user's project for compilation.
		SyntaxList<MemberDeclarationSyntax> results = SyntaxFactory.SingletonList<MemberDeclarationSyntax>(copy);

		return Task.FromResult( results );
	}
}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants