Static Extension Methods are not returned by the Roslyn CompletionService
Asked Answered
C

2

6

If using System.Linq; is present and System.Linq is among the referenced assemblies, I expect Completions on an int[] array to return LINQ extension methods, e.g. Select<>(...), Where<>(...), etc. In fact I am only getting public methods and properties of the int[] type. Here is the full code:

static void Main(string[] args)
    {
        string code = @"using System;
        using System.Linq;

       namespace RoslynCompletionTests
       {
             public static class MyTestClass1
             {
                   public static void Print()
                   {
                          int[] array = {1,2,3,4,5,6};

                          var result = array.Select(i => new { I = i }).Select(v => v.I);
                   }
             }
       }";
        var host = MefHostServices.Create(MefHostServices.DefaultAssemblies);
        
        Type[] types =
        {
            typeof(object),
            typeof(Enumerable),
            typeof(IEnumerable),
            typeof(Console),
            typeof(Assembly),
            typeof(List<>),
            typeof(Type)
        };

        ImmutableArray<string> imports = types.Select(x => x.Namespace).Distinct().ToImmutableArray();

        ImmutableArray<MetadataReference> references =
            types.Select(t => MetadataReference.CreateFromFile(t.Assembly.Location) as MetadataReference)
                 .ToImmutableArray();

        AdhocWorkspace workspace = new AdhocWorkspace(host, "Custom");

        string name = "MyTestProj";

        ProjectId id = ProjectId.CreateNewId(name);

        ParseOptions parseOptions = new CSharpParseOptions();

        CompilationOptions compilationOptions =
            new CSharpCompilationOptions
            (
                OutputKind.DynamicallyLinkedLibrary,
                usings: imports,
                allowUnsafe: true);

        ProjectInfo projInfo =
            ProjectInfo.Create
            (
                id,
                VersionStamp.Create(),
                name,
                name,
                LanguageNames.CSharp,
                parseOptions: parseOptions,
                compilationOptions: compilationOptions,
                metadataReferences: references);

        Project proj = workspace.AddProject(projInfo);

        SourceText text = SourceText.From(code);

        Document doc = proj.AddDocument("MyDoc.cs", text);

        SemanticModel semanticModel = doc.GetSemanticModelAsync().Result;

        CompletionService completionService = CompletionService.GetService(doc);

        string strToFind = "array.";
        int idx = text.ToString().IndexOf(strToFind) + strToFind.Length;

        var results = completionService.GetCompletionsAsync(doc, idx).Result;
    }

Am I doing something wrong?

Champion answered 17/1, 2020 at 17:7 Comment(0)
C
5

It turned out I had to add the references to some assemblies that form the MetadataReferences:

var assemblies = types.Select(t => t.Assembly).Concat(new[]
{
     Assembly.Load("System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"),
     typeof(Microsoft.CSharp.RuntimeBinder.Binder).Assembly,
});

after that everything started to work.

Champion answered 17/1, 2020 at 20:20 Comment(2)
This did not work for me (.NET Core 6.0). See workaround post.Cerell
It did work for me (.NET Core 3.1). But all I had to add was this one: MetadataReference.CreateFromFile(System.Reflection.Assembly.Load("System.Runtime").Location),Rarebit
C
0

I believe that this is a bug in the CSharpCompilation class.

Workaround: in your code string, use:

var result = System.Linq.Enumerable.Select.Select(System.Linq.Enumerable.Select(array, i => new { I = i }), v => v.I);

...and yes, you do have to fully qualify System.Linq.Enumerable. Adding it as a using does not work.

Yuck.

Cerell answered 10/8, 2022 at 1:30 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.