5

I have 2 test projects in solution.
First project ("VDoc") declare VDocQuery type.
Second project ("VDocQueryTest" ) calls VDocQuery constructor.
I get 2 VDocQuery's ITypeSymbol's (one from each project), compare it, but get false result.

Steps:
1. Get first ITypeSymbol (from VDoc project with SemanticModel.LookupNamespacesAndTypes() method).
2. Get second ITypeSymbol from VDocQueryTest project (from ObjectCreationExpressionSyntax.GetTypeInfo().Type)
3. Compare it with ITypeSymbol.Equals(ITypeSymbol).

I expected true result, but get false result.

Question: How to correctly compare ITypeSymbols from different projects within one solution?

Code example:

class Program
{
    static void Main(string[] args)
    {
        string solutionPath = @"..\..\..\StaticAnalysis.sln";

        MSBuildWorkspace workspace = MSBuildWorkspace.Create();
        Solution solution = workspace.OpenSolutionAsync(solutionPath).Result;

        var vdocProject = FindProjectByName("VDoc", solution);
        SemanticModel semanticModel = vdocProject.Documents.First().GetSemanticModelAsync().Result;
        var nsVDocQueryFunctionalTest = (INamespaceOrTypeSymbol)semanticModel.LookupNamespacesAndTypes(0, null, "VDocQueryFunctionalTest").First();
        var tVDocQuery = (ITypeSymbol)semanticModel.LookupNamespacesAndTypes(0, nsVDocQueryFunctionalTest, "VDocQuery").First();

        TypeInfo ti = GetFromVDocRef(solution);
        bool result1 = ti.Type.Equals(tVDocQuery); // false, expected = true?

        //these 2 lines added after Jason Malinowski answer
        var sVDocQuerySource = SymbolFinder.FindSourceDefinitionAsync(ti.Type, solution).Result;
        bool result2 = sVDocQuerySource.Equals(tVDocQuery); // false, expected = true?

       //this line solved the problem, thanks to @Tamas
       bool result3 = ti.Type.DeclaringSyntaxReferences.FirstOrDefault()?.Equals(tVDocQuery.DeclaringSyntaxReferences.FirstOrDefault()) ?? false;
    }

    private static TypeInfo GetFromVDocRef(Solution solution)
    {
        var vdocQueryTestProject = FindProjectByName("VDocQueryTest", solution);
        var vdocQueryTestProjectSemanticModel = vdocQueryTestProject.Documents.First().GetSemanticModelAsync().Result;
        var compilationUnit = (CompilationUnitSyntax)vdocQueryTestProject.Documents.First().GetSyntaxRootAsync().Result;
        var ns = (NamespaceDeclarationSyntax)compilationUnit.Members[0];
        var cls = (ClassDeclarationSyntax)ns.Members[0];
        var method = (MethodDeclarationSyntax)cls.Members[0];
        var stat = (ExpressionStatementSyntax)method.Body.Statements[0];
        var newExpr = (ObjectCreationExpressionSyntax)stat.Expression;
        var ti = vdocQueryTestProjectSemanticModel.GetTypeInfo(newExpr);
        return ti;
    }

    static Project FindProjectByName(string projectName, Solution solution)
    {
        var project = solution.Projects.SingleOrDefault(p => p.Name == projectName);
        return project;
    }
}

VDocQuery.cs:

using System.Collections.Generic;

namespace VDocQueryFunctionalTest
{
    public class VDocQuery
    {
        public VDocQuery()
        {
        }

        public void AddFields(string docType, params string[] fields)
        {
        }

        public List<VDoc> Execute()
        {
            return null;
        }
    }
}

VDocQueryUse.cs:

using VDocQueryFunctionalTest;

namespace VDocQueryTest
{
    static class VDocQueryUse
    {
        public static void VDocQueryUseTest()
        {
            new VDocQuery();
        }
    }
}
Alex Sedow
  • 357
  • 2
  • 17
  • I just tried your original solution, and @Jason's modification, and both of them work correctly. In both cases the types are equivalent. Which version of Roslyn are you using? Can you share somehow your project settings and references? – Tamas Nov 13 '15 at 07:33
  • @Tamas, VS2015 Community Edition + Microsoft.Code.Analysis 1.0.0.0 (get it with nuget). I can send minimal solution. Firstly, I tryed to create minimal solution from zero, but can't reproduce the problem. So, on second try I copy real solution and remove all unnecessary code - problem is reproduced. – Alex Sedow Nov 13 '15 at 08:19

2 Answers2

3

I could reproduce your problem by using different target frameworks in the two projects. Set the same target framework for both projects and then your original solution will find the matching types.

If you can't change the target frameworks, then you could still compare the ITypeSymbol.DeclaringSyntaxReferences.

Tamas
  • 6,260
  • 19
  • 30
  • frameworks are the same - .NET Framework 4.5.2. Previously framework was 4.5. But I changed it few days before run the test. Comparison with ISymbol.DeclaringSyntaxReferences is works! Thank you. – Alex Sedow Nov 13 '15 at 18:48
1

When you have the reference to the type in your VDocQueryTest project, take the ISymbol and pass it to SymbolFinder.FindSourceDefinitionAsync(). This will realize it's a symbol from metadata coming from the other project and then hand you the metadata symbol in that project. From there, you can do .Equals().

Jason Malinowski
  • 18,148
  • 1
  • 38
  • 55
  • I added 2 lines of code in example, result is the same - false :( var sVDocQuerySource = SymbolFinder.FindSourceDefinitionAsync(ti.Type, solution).Result; bool result2 = sVDocQuerySource.Equals(tVDocQuery); – Alex Sedow Nov 12 '15 at 22:27
  • This is great. I had no success in trying to match a symbol BaseSymbol (naming aside) with a set of symbols that I had before running into this. – Daniel Mendonça Mar 29 '17 at 08:27