Is there a way to enable "Implicit Usings" feature when compiling code with .NET Compiler SDK?

520 views Asked by At

The "ImplicitUsings" feature allows code to omit usings statements for standard namespaces. I need to analyze a random source file(s) for which I may not know an appropriate set of includes. In C# 10 a standard set of namespaces could be included implicitly, as described in the help topic. Is there a way to use the standard namespaces when creating a compilation?

using System.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

var sourceText = "class C{" +
    "public void M(){" +
    " Console.Write(123);" +
    "}}";
var syntaxTree = CSharpSyntaxTree.ParseText(sourceText);

var coreReferences =
    ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES"))
    .Split(Path.PathSeparator)
    .Select(p => MetadataReference.CreateFromFile(p));
var compilation = CSharpCompilation.Create("MyAnalysis")
    .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
    .AddReferences(coreReferences)
    .AddSyntaxTrees(syntaxTree);

var diagnostics = compilation.GetDiagnostics();
Debug.Assert(diagnostics.Length == 0);
// diagnostics = "error CS0103: The name 'Console' does not exist in the current context"

To clarify the above example, I'm compiling the source in the sourceText variable. The diagnostics variable contains the error that Console does not exist. If I add "using System" in the sourceText above, the code compiles without the error. Is there a way to enable the Implicit Usings feature so that compilation resolves symbols from standard namespaces?

2

There are 2 answers

3
Blindy On

Not implicit usings, but you can add usings to your compilation externally by using the WithUsings method of the CSharpCompilationOptions class.

0
Mark Meyerovich On

Based on suggestions I'm pursuing a possible solution by creating a global usings file(s) corresponding to specific known SDK(s). Will probably look up SDK in the project file or use a default. For example, for Microsoft.NET.Sdk I created the following file (Microsoft.NET.Sdk.usings.cs):

global using System;
global using System.Collections.Generic;
global using System.IO;
global using System.Linq;
global using System.Net.Http;
global using System.Threading;
global using System.Threading.Tasks;

There is a document describing default namespaces for standard SDK(s). Then I can load it and parse as an additional syntax tree getting rid of the compilation error. There are warnings about unnecessary using directives. The complete code is this:

using System.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

var sourceText = "class C{" +
    "public void M(){" +
    " Console.Write(123);" +
    "}}";
var syntaxTree = CSharpSyntaxTree.ParseText(sourceText);

var globalUsings = File.ReadAllText("Microsoft.NET.Sdk.usings.cs");
var usingsTree = CSharpSyntaxTree.ParseText(globalUsings);

var coreReferences =
    ((string)AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES"))
    .Split(Path.PathSeparator)
    .Select(p => MetadataReference.CreateFromFile(p));
var compilation = CSharpCompilation.Create("MyAnalysis")
    .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
    .AddReferences(coreReferences)
    .AddSyntaxTrees(usingsTree, syntaxTree);

var diagnostics = compilation.GetDiagnostics();
Debug.Assert(!diagnostics.Any(d => d.Severity == DiagnosticSeverity.Error));