0

I'm trying to analyze something like blah.SomeMethod(x => x.PropertyA) in a method call and get the class of 'x' and property referenced so I can go verify that property has an expected attribute attached. I want to analyze the first argument to the method call.

So I make a Roslyn visitor and give it a compilation/SemanticModel from the VS Project (in an existing solution) and find the method invocations like so:

var workspace = MSBuildWorkspace.Create();
workspace.LoadMetadataForReferencedProjects = true;
var solution = await workspace.OpenSolutionAsync(pathToSolution);
var project1 = solution.Projects.FirstOrDefault(proj => proj.Name == projectName);
var document1 = project1.Documents.Single(d => d.Name == documentFilename);
var tree = await document1.GetSyntaxTreeAsync();
var compilation = project1.GetCompilationAsync().Result;
Debug.Assert(compilation.ContainsSyntaxTree(tree));
var semanticModel = compilation.GetSemanticModel(tree);

public override void VisitInvocationExpression(InvocationExpressionSyntax node)
{
    string methodName = node.Expression.ToString();

    if (methodName.Contains("SomeMethod"))
    {
        // Analyze each parameter in the method call
        foreach (ArgumentSyntax argument in node.ArgumentList.Arguments)
        {
            // FIRST ARGUMENT HERE IS x => x.PropertyA.  I want to get the 
            // class and property names.

            // The below returns an object with properties: 
            //   CandidateReason: None
            //   CandidateSymbols: Length = 0
            //   Symbol: null
            //   Type: null
            var typeinfo = semanticModel.GetTypeInfo(argument.Expression);

            // node type info is empty, too, and its parent.
            var nodeTypeinfo = semanticModel.GetTypeInfo(node.Expression);
            var nodeParentTypeinfo = semanticModel.GetTypeInfo(node.Parent);

            ITypeSymbol parameterType = typeinfo.Type;
            if (parameterType = null)
            {
                // Always null, doesn't break.
                Debugger.Break();
            }
            //...
    }
}

As you see, the GetTypeInfo() always return None/NULL on the argument, the method (node), and the node's parent.

Even GetSymbolInfo() on all the above returns None/null as well.

I know the types are compiled as part of the project, so why can't Roslyn find anything? It's like the semantic model (from the project's compilation) contains nothing.

All I can imagine is that since some of the classes used are in a different project which is referenced by the project I'm compiling, the semantic model of the main project won't work at all?

Chris Bordeman
  • 255
  • 7
  • 19
  • Common debugging trick: if you call Compilation.GetDiagnostics() or SemanticModel.GetDiagnostics(), does your code build? It's a commonish problem that if your project didn't get references set up right or something then we don't have symbols to work with. – Jason Malinowski Aug 31 '23 at 00:35
  • @JasonMalinowski Will try that, thanks, though the project compiles fine in VS and it was loaded from the VS solution. I added the load code above. – Chris Bordeman Aug 31 '23 at 03:29
  • @JasonMalinowski So a ton of "System" stuff isn't found. Looking at my compilation code above, do you know how I would remedy this? Since it's got all the refs in the project itself, they should come along, especially .net framework 4.8, which it uses? – Chris Bordeman Aug 31 '23 at 03:35
  • Where did the Solution object come from? – Jason Malinowski Aug 31 '23 at 03:59
  • @JasonMalinowski Disk, see modified code. I went ahead an compiled all the projects in order using this post https://stackoverflow.com/questions/28389794/compilation-fails-with-sln-file-loaded-with-roslyn-but-compiles-in-visual-studi just in case, but the errors about missing "System" namespace thing are still there. – Chris Bordeman Aug 31 '23 at 04:34
  • But you're using MSBuildWorkspace? MSBuildWorkspace has a WorkspaceFailed event that is raised on some loading errors; is that triggered in this case? – Jason Malinowski Aug 31 '23 at 04:39
  • Basically, if you're getting lots of missing system and such, I think that means your projects didn't load with references properly, and as a result you're missing all sorts of stuff. The compiler tries to work with missing references and such, but if the compiler doesn't even know what System.Object is...you won't have a good time! – Jason Malinowski Aug 31 '23 at 04:41
  • I'm not missing references. The projects build fine in VS. That workspace surfaced some slightly weird multi-targeting messages we have and ignore, but have never been an issue. When compiled this way, some projects compile fine, then one doesn't. – Chris Bordeman Aug 31 '23 at 05:23
  • 1
    "The projects build fine in VS" and "they successfully loaded in MSBuildWorkspace" are two different things, unfortunately. I'm currently working to make that be far more reliable, but that's the current status. – Jason Malinowski Sep 01 '23 at 20:27
  • 1
    And to explain a bit further: MSBuildWorkspace under the covers invokes a special build, but there's certain caveats today: if your projects are .NET Core and your app is a .NET Framework app (or vice versa), or if you are a .NET Framework app and you don't have certain binding redirects, or you didn't use MSBuildLocator right... – Jason Malinowski Sep 01 '23 at 20:30

0 Answers0