1

In order to execute some logic with a source generator on some files (image files more precisely) based on the folders structure of the targeted/referencing project, I need to get the path/directory of the targeted/referencing project.

First approach

namespace SourceGen
{
    [Generator]
    public class Class1 : IIncrementalGenerator
    {
        public void Initialize(IncrementalGeneratorInitializationContext context)
        {
            var projDirectory = context.AnalyzerConfigOptionsProvider
                           .Select((x, _) => x.GlobalOptions
                           .TryGetValue("build_property.MSBuildProjectDirectory", out var projectDirectory) ? projectDirectory : null);

            File.AppendAllText("\\" + "log.txt", projDirectory );
        }
    }
}

I am logging to a file for debugging purposes (to check the property value I am reading in this case) since I can't find another way to debug this kind of project.

In the log file I get, since IncrementalValueProvider<string>.ToString() returns the type and not whatever value is there:

Microsoft.CodeAnalysis.IncrementalValueProvider`1[System.string].

Second approach

following https://stackoverflow.com/a/66548212:

var mainSyntaxTree = context.CompilationProvider.Select((x, _) => x.SyntaxTrees.First(x => x.HasCompilationUnitRoot));
var directory = Path.GetDirectoryName(mainSyntaxTree.Select((x, _) => x.FilePath);

The same issue Path.GetDirectoryName() is complaining that the provided parameter is of type IncrementalValueProvider<string> while expecting a string. Not sure how can I get a useful string value (FilePath) out of the type IncrementalValueProvider<string>.

Third approach

This time the log file was not written/created at all:

var provider = context.AnalyzerConfigOptionsProvider.Select((x, _) =>
       {
        x.GlobalOptions.TryGetValue("build_property.MSBuildProjectDirectory", out var projectDirectory);
       File.AppendAllText("\\" + "log.txt", "testing" + projectDirectory);
       return projectDirectory;
       });

Docs: https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.cookbook.md

What am I missing to make this work?

1 Answer 1

0

The third approach is close; the return type is IncrementalValueProvider not the value itself. Then you need to combine this provider with another. I do it like this:

var someInfo = context.AnalyzerConfigOptionsProvider
    .Select(static (ctx, _) => { 
        if(ctx.GlobalOptions.TryGetValue("build_property.someInfo", out var info))
        {
            return info;
        }
        return defaultInfo;
    });

var dataFromAttribute = context.SyntaxProvider
    .ForAttributeWithMetadataName(
        "MyAttribute",
        predicate: static (s, _) => s is ClassDeclarationSyntax { AttributeLists.Count: > 0  },
        transform: static (ctx, _) => GetAttributeData(ctx.SemanticModel, ctx.TargetNode))
    .Where(static m => m is not null);

var attributeDataEnhancedWithInfo = dataFromAttribute .Combine(someInfo ).Select((pair, _) => {
    pair.Left!.Info = pair.Right;

    return pair. Left!});
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.