0

I'm trying to retrieve some type's namespace with Roslyn API, but my code is not working with external assemblies (types from NuGet packages, or from another external assembly):

var typeInfo = semanticModel.GetTypeInfo(typeSyntax);
var isFromSource = typeInfo.Type.Locations.Length > 0;

if (isFromSource)
{
    var symbolInfo = semanticModel.GetSymbolInfo(typeSyntax);

    //type's namespace:
    return symbolInfo.Symbol.ContainingNamespace.ToString();
}
else
{
    //Type is from some external assembly
    return "";
}

How can i return the type's namespace in this case?

EDIT: I'm retrieving solution's documents with:

using (var ws = MSBuildWorkspace.Create())
{
    var solution = await ws.OpenSolutionAsync(solutionPath);

    return solution.Projects.SelectMany(p => p.Documents);
}

2 Answers2

0

Are you sure there are no compilation errors when processing the syntax and the type is correctly resolved?

The ContainingNamespace property should provide the namespace also for the types from external assemblies as long as the type can be resolved.

In case it helps, you can find here a snippet which displays the namespace for an external type (RestClient class is from RestSharp nuget package):

using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using RestSharp;

namespace Playground
{
    public static class Program
    {
        public static void Main()
        {
            const string code =
@"using RestSharp;

namespace Playground
{
    public class Foo
    {
        public void Bar(RestClient restClient)
        {
        }
    }
}";
            var tree = CSharpSyntaxTree.ParseText(code);
            var compilation = CreateCompilation(tree);
            var semanticModel = compilation.GetSemanticModel(tree);
            var syntaxNode = GetParameterTypeSyntaxNode(tree);

            Console.WriteLine(GetNamespace(syntaxNode, semanticModel));
        }

        private static TypeSyntax GetParameterTypeSyntaxNode(SyntaxTree tree) =>
            tree.GetRoot()
                .DescendantNodes()
                .OfType<MethodDeclarationSyntax>()
                .First()
                .ParameterList
                .Parameters
                .First()
                .Type;

        private static INamespaceSymbol GetNamespace(SyntaxNode node, SemanticModel semanticModel) =>
            semanticModel.GetTypeInfo(node).Type?.ContainingNamespace;

        private static CSharpCompilation CreateCompilation(SyntaxTree tree) =>
            CSharpCompilation
                .Create("HiThere", options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
                .AddReferences(MetadataReference.CreateFromFile(typeof(string).Assembly.Location))
                .AddReferences(MetadataReference.CreateFromFile(typeof(RestClient).Assembly.Location))
                .AddSyntaxTrees(tree);
    }
}
Costin
  • 770
  • 7
  • 19
  • Thanks for the answer! I'm retrieving all documents through workspace's "open solution" method; I dont know wich nuggets will be loaded (and for consequence, also don't know nuget's locations). How could i proceed? (i've just updated the question with my code to retrieve all documents) – rafaatsouza Jun 27 '20 at 15:43
  • i've just made a test, opening a solution that point to .NET Framework 4.6.1, and with that solution, my code works. Is there some issue with .NET Core projects analysis with Roslyn? – rafaatsouza Jun 27 '20 at 16:49
  • Presumably, the solution will have already all the references correctly set so you don't need to bother with nuget locations. What is important for this to work is that the nuget restore has run before the analysis. If the assemblies are not on disk, the type cannot be correctly determined. – Costin Jun 27 '20 at 17:58
  • Have you tried to get the project compilation (project.GetCompilationAsync()) and look for any errors by calling GetDiagnostics()? This can provide valuable information. – Costin Jun 27 '20 at 18:03
  • I've run the nuget restore on the pointed solution; now, i run my code and "workspace" variable gets the following error after the "open solution" method: Msbuild failed when processing the file '[...].csproj' with message: C:\Program Files\dotnet\sdk\3.1.301\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.ConflictResolution.targets: (39, 5): The "ResolvePackageFileConflicts" task failed unexpectedly. System.IO.FileNotFoundException: Could not load file or assembly 'NuGet.Versioning, Version=5.6.0.5, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified. – rafaatsouza Jun 27 '20 at 18:27
  • Just a info: this particular solution it's working, i'm able to run it. – rafaatsouza Jun 27 '20 at 18:31
  • And if you try to rebuild the solution (the one you try to load) from command line it will compile successfully? – Costin Jun 28 '20 at 08:17
  • 1
    i've just accepted your answer, i think it clarifies the specific question about the namespace retrieval for external types; for this specific error i'm receiving with .NET Core project analysis i've created [another question](https://stackoverflow.com/questions/62625114/roslyn-error-only-with-net-core-resolvepackagefileconflicts-task-failed-unex). Thanks! – rafaatsouza Jun 28 '20 at 16:14
  • I don't really know why that happens on .net core. I will try to get a look when I have some time. – Costin Jun 28 '20 at 16:42
0

here context is GeneratorExecutionContext, which is we get it from the Source Generators Execute method parameter

var @namespace = context
            .Compilation?
            .GetSemanticModel(type.SyntaxTree)?
            .GetSymbolInfo(type)
            .Symbol?
            .ContainingNamespace?
            .ToString();