Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I resolve all references with Roslyn's OpenSolutionAsync?

Tags:

c#

roslyn

I'm trying to open RoslynLight.sln with OpenSolutionAsync then iterate through all the projects. For my purposes I need a semantic model and resolved references. Through a combination of this issue and this question, I've arrived at this partial solution:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.MSBuild;
using System.IO;

namespace OpenRoslyn
{
  class Program
  {
    static void Main(string[] args)
    {

      var msbw = MSBuildWorkspace.Create();
      var sln = msbw.OpenSolutionAsync(@"C:\Users\carr27\Documents\GitHub\roslyn\src\RoslynLight.sln").Result;
      //var proj = sln.Projects.First(x => x.Name == "CodeAnalysis.Desktop");
      var messages = new List<string>();
      foreach (var p in sln.Projects)
      {
        Console.WriteLine(p.FilePath);
        messages.Add(p.FilePath);
        var facadesDir = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\Facades\";
        var proj = p.AddMetadataReference(MetadataReference.CreateFromAssembly(typeof(object).Assembly));
        proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Runtime.dll"));
        proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Runtime.Extensions.dll"));
        proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.IO.dll"));
        proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Threading.Tasks.dll"));
        proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Text.Encoding.dll"));
        proj = proj.AddMetadataReference(MetadataReference.CreateFromFile(facadesDir + "System.Reflection.dll"));
        try
        {
          var cu = proj.GetCompilationAsync().Result;
          // here I would do useful work, but for know I just get diagnostics
          foreach (var e in cu.GetDiagnostics().Where(x => x.Severity == DiagnosticSeverity.Error))
          {
            Console.WriteLine("{0}: {1}", e.Location, e.GetMessage());
            messages.Add(String.Format("{0}: {1}", e.Location, e.GetMessage()));
          }
        }
        catch (AggregateException e)
        {
          foreach(var ie in e.InnerExceptions)
          {
            Console.WriteLine(ie.Message);
            messages.Add(ie.Message);
          }

        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            messages.Add(e.Message);
        }
      }
      File.WriteAllLines("log.txt", messages);
      Console.WriteLine("done.");
      Console.ReadKey();
    }
  }
}

The log for this program is too big for me to post, but the work around only works for certain projects. For example, rosyln\src\compilers\Core\Desktop\CodeAnalysis.Desktop.csproj has no errors, but roslyn\src\Compilers\CSharp\Portable\CSharpCodeAnalysis.csproj has:

None: Multiple assemblies with equivalent identity have been imported: 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7\System.Threading.Tasks.dll' and 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\Facades\System.Threading.Tasks.dll'. Remove one of the duplicate references.
None: Multiple assemblies with equivalent identity have been imported: 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7\System.Text.Encoding.dll' and 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\Facades\System.Text.Encoding.dll'. Remove one of the duplicate references.
None: Multiple assemblies with equivalent identity have been imported: 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7\System.Runtime.Extensions.dll' and 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\Facades\System.Runtime.Extensions.dll'. Remove one of the duplicate references.
None: Multiple assemblies with equivalent identity have been imported: 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7\System.Runtime.dll' and 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\Facades\System.Runtime.dll'. Remove one of the duplicate references.
None: Multiple assemblies with equivalent identity have been imported: 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7\System.Reflection.dll' and 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\Facades\System.Reflection.dll'. Remove one of the duplicate references.
None: Multiple assemblies with equivalent identity have been imported: 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.5\Profile\Profile7\System.IO.dll' and 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\Facades\System.IO.dll'. Remove one of the duplicate references.
SourceFile(C:\Users\carr27\Documents\GitHub\roslyn\src\Compilers\CSharp\Portable\BoundTree\UnboundLambda.cs[9068..9109)): The type 'ConcurrentDictionary<TKey, TValue>' exists in both 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' and 'System.Collections.Concurrent, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
SourceFile(C:\Users\carr27\Documents\GitHub\roslyn\src\Compilers\CSharp\Portable\BoundTree\UnboundLambda.cs[9203..9250)): The type 'ConcurrentDictionary<TKey, TValue>' exists in both 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' and 'System.Collections.Concurrent, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'

... and many others. It seems to me any way I could make this work for an arbitrary project/solution would be very hacky. Am I missing something?

like image 315
Scott Carr Avatar asked Apr 02 '15 14:04

Scott Carr


2 Answers

I'm looking at fixing this in the MSBuild targets, but in the meantime, the following workaround should address the issue. Instead of using:

MSBuildWorkspace.Create();

use:

MSBuildWorkspace.Create(new Dictionary<string, string> { { "CheckForSystemRuntimeDependency", "true" } });
like image 94
Kevin Pilch Avatar answered Nov 15 '22 17:11

Kevin Pilch


You only need to add the façade references if the project is targeting the "full" .NET framework. So if you look at the existing references first, if there are any references that come from Reference Assemblies\Microsoft.NETPortable\v4.5\Profile\... then you shouldn't need to add them.

like image 35
Jason Malinowski Avatar answered Nov 15 '22 17:11

Jason Malinowski