8

I have a c# solution that contains some class files. With Roslyn I am able to parse a solution to obtain a list of projects within the solution. From there, I can get the documents in each project. Then, I can get a list of every ClassDeclarationSyntax. This is the starting point.

        foreach (var v in _solution.Projects)
        {
            //Console.WriteLine(v.Name.ToString());
            foreach (var document in v.Documents)
            {
                SemanticModel model = document.GetSemanticModelAsync().Result;
                var classes = document.GetSyntaxRootAsync().Result.DescendantNodes().OfType<ClassDeclarationSyntax>();
                foreach(var cl in classes)
                {
// Starting around this point...
                    ClassDiagramClass cls = new ClassDiagramClass(cl, model);
                    diagramClasses.Add(cls);
                }
            }
        }

From these objects I want to be able to get the Namespace of the variables used within each class. See file 1 has a method "getBar()" that returns an object of type B.Bar. The namespace is important because it tells you which type of Bar is really being returned.

File1.cs

using B;
namespace A {
    public class foo(){
        public Bar getBar(){ return new Bar();}
    }
}

File2.cs

namespace B {
    public class Bar(){
    }
}

File3.cs

namespace C {
    public class Bar(){
    }
}

The issue is that I am not sure how to get to the Namespace value from where I am in the code right now. Any ideas?

Pangamma
  • 731
  • 12
  • 28

1 Answers1

10

The namespace is semantic information, so you need to get it from the semantic model:

model.GetTypeInfo(cl).Type.ContainingNamespace
SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Not sure about what you just mentioned as there seems to be a missing step between TypeInfo and ContainingNamespace (Maybe I am missing an extension?), but I AM currently using this code to get the namespace for the current class. The problem is that this only works for the object/classes defined within the document from which the SemanticModel was derived from. When you want to get the namespace for an object that is not defined within the current Document instance, it gets a bit trickier. – Pangamma Apr 06 '15 at 22:19
  • Hang on, @Slaks. I have a theory on how to solve this. It's a bit hacky, but it should work. If the Type has namespaces included within its naming string, assume the namespace is 100% accurate. If the type string has no periods in it, assume it needs to be matched to a namespace. Iterate through each of the "using" declarations at the top of the document and attempt to load each <"using"+typeNameString>. If any of those options can be loaded, you can assume you've found a match. I'll post the code in a bit if it works. – Pangamma Apr 06 '15 at 23:18
  • @Taylor: Oops; that should be `.Type`. – SLaks Apr 06 '15 at 23:54
  • 1
    @Taylor: The `SemanticModel` should have complete type information for every symbol in the document. If your symbol comes from elsewhere, there are other APIs. You do not need any of that hackery. – SLaks Apr 06 '15 at 23:56
  • probably going to accept your answer as you have certainly been the most helpful person with this. My proposed solution DID work, but I AM still curious about the other APIs you speak of. I'd love to use an established API instead of my own solution as my own solution does not work when finding a reference to the System....Exception class. Do you remember the names or links to the APIs you're talking about? – Pangamma Apr 08 '15 at 16:28
  • 1
    @Taylor: You're looking for `Compilation.GetTypeByMetadataName`. http://source.roslyn.io/#Microsoft.CodeAnalysis/Compilation/Compilation.cs,836 – SLaks Apr 08 '15 at 16:46
  • I use same code, but `model.GetTypeInfo(cl).Type` == `null`. Why could it be? `model` is get from `compillation` by `cl.SyntaxTree`. `compilation` is created by factory method `CSharpCompilation.Create` with trees as 1 of its arguments incuding `cl.SyntaxTree`. cs file containing `cl` node is the most easy - all its content is: `namespace Ns0{ class A{} }`. I have no idea, what could go wrong... – user1234567 Mar 03 '21 at 11:33
  • Some additional info to my prev.comment: it looks like `model.GetTypeInfo(cl)` returns `TypeInfo.None` in that my case – user1234567 Mar 03 '21 at 14:29