Skip to content

Commit

Permalink
Ability to compile using generator output from original build (#38)
Browse files Browse the repository at this point in the history
* netstandard2.0

* Basic generated file embedding

* Lots of progress here. Still some failing tests to work out

* export is working

* more

---------

Co-authored-by: Jared Parsons <[email protected]>
  • Loading branch information
jaredpar and Jared Parsons committed Jun 22, 2023
1 parent b3a8f8d commit adaa7ac
Show file tree
Hide file tree
Showing 19 changed files with 376 additions and 78 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"dotnet-test-explorer.testProjectPath": "**/*UnitTests.csproj",
"dotnet.defaultSolution": "BasicCompilerLogger.sln",
"dotnet.defaultSolution": "BasicCompilerLog.sln",
"cSpell.words": [
"appconfig",
"binlog",
Expand Down
2 changes: 1 addition & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"type": "process",
"args": [
"build",
"${workspaceFolder}/BasicCompilerLogger.sln",
"${workspaceFolder}/BasicCompilerLog.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
Expand Down
4 changes: 4 additions & 0 deletions src/Basic.CompilerLog.UnitTests/BasicAnalyzerHostTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ public void Supported()
{
Assert.True(BasicAnalyzerHost.IsSupported(BasicAnalyzerKind.Default));
Assert.True(BasicAnalyzerHost.IsSupported(BasicAnalyzerKind.OnDisk));
Assert.True(BasicAnalyzerHost.IsSupported(BasicAnalyzerKind.None));
#if NETCOREAPP
Assert.True(BasicAnalyzerHost.IsSupported(BasicAnalyzerKind.InMemory));
#else
Assert.False(BasicAnalyzerHost.IsSupported(BasicAnalyzerKind.InMemory));
#endif

// To make sure this test is updated every time a new value is added
Assert.Equal(4, Enum.GetValues(typeof(BasicAnalyzerKind)).Length);
}
}
32 changes: 32 additions & 0 deletions src/Basic.CompilerLog.UnitTests/CompilerLogReaderTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Basic.CompilerLog.Util;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization;
Expand Down Expand Up @@ -258,4 +259,35 @@ public void EmitToMemory()
}
}
}

[Fact]
public void NoAnalyzersGeneratedFilesInRaw()
{
using var reader = CompilerLogReader.Create(Fixture.ConsoleComplogPath, BasicAnalyzerHostOptions.None);
var (_, data) = reader.ReadRawCompilationData(0);
Assert.Equal(1, data.Contents.Count(x => x.Kind == RawContentKind.GeneratedText));
}

[Fact]
public void NoAnalyzerGeneratedFilesShouldBeFirst()
{
using var reader = CompilerLogReader.Create(Fixture.ConsoleComplogPath, BasicAnalyzerHostOptions.None);
var data = reader.ReadCompilationData(0);
var tree = data.Compilation.SyntaxTrees.First();
var decls = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>().ToList();
Assert.True(decls.Count >= 2);
Assert.Equal("Util", decls[0].Identifier.Text);
Assert.Equal("GetRegex_0", decls[1].Identifier.Text);
}

[Fact]
public void NoAnalyzerShouldHaveNoAnalyzers()
{
using var reader = CompilerLogReader.Create(Fixture.ConsoleComplogPath, BasicAnalyzerHostOptions.None);
var data = reader.ReadCompilationData(0);
var compilation1 = data.Compilation;
var compilation2 = data.GetCompilationAfterGenerators();
Assert.Same(compilation1, compilation2);
Assert.Empty(data.AnalyzerReferences);
}
}
51 changes: 47 additions & 4 deletions src/Basic.CompilerLog.UnitTests/ExportUtilTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public ExportUtilTests(ITestOutputHelper testOutputHelper, CompilerLogFixture fi
Fixture = fixture;
}

private void TestExport(int expectedCount)
private void TestExport(int expectedCount, Action<string>? callback = null)
{
using var scratchDir = new TempDir();
var binlogFilePath = Path.Combine(RootDirectory, "msbuild.binlog");
Expand All @@ -34,18 +34,18 @@ private void TestExport(int expectedCount)
// ensures our builds below don't succeed because old files are being referenced
Root.EmptyDirectory();

TestExport(compilerLogFilePath, expectedCount);
TestExport(compilerLogFilePath, expectedCount, callback: callback);
}

private void TestExport(string compilerLogFilePath, int expectedCount)
private void TestExport(string compilerLogFilePath, int expectedCount, bool includeAnalyzers = true, Action<string>? callback = null)
{
using var reader = CompilerLogReader.Create(compilerLogFilePath);
#if NETCOREAPP
var sdkDirs = DotnetUtil.GetSdkDirectories();
#else
var sdkDirs = DotnetUtil.GetSdkDirectories(@"c:\Program Files\dotnet");
#endif
var exportUtil = new ExportUtil(reader);
var exportUtil = new ExportUtil(reader, includeAnalyzers);
var count = 0;
foreach (var compilerCall in reader.ReadAllCompilerCalls())
{
Expand All @@ -66,6 +66,8 @@ private void TestExport(string compilerLogFilePath, int expectedCount)
{
Assert.False(line.Contains(tempDir.DirectoryPath, StringComparison.OrdinalIgnoreCase), $"Has full path: {line}");
}

callback?.Invoke(tempDir.DirectoryPath);
}
Assert.Equal(expectedCount, count);
}
Expand All @@ -82,6 +84,47 @@ public void ClassLib()
TestExport(Fixture.ClassLibComplogPath, 1);
}

/// <summary>
/// Make sure that generated files are put into the generated directory
/// </summary>
[Fact]
public void GeneratedText()
{
TestExport(Fixture.ConsoleComplogPath, 1, callback: tempPath =>
{
var generatedPath = Path.Combine(tempPath, "generated");
var files = Directory.GetFiles(generatedPath, "*.cs", SearchOption.AllDirectories);
Assert.NotEmpty(files);
});
}

/// <summary>
/// Make sure the rsp file has the expected structure when we exclude analyzers from the
/// export.
/// </summary>
[Fact]
public void GeneratedTextExcludeAnalyzers()
{
TestExport(Fixture.ConsoleComplogPath, 1, includeAnalyzers: false, callback: tempPath =>
{
var rspPath = Path.Combine(tempPath, "build.rsp");
var foundPath = false;
foreach (var line in File.ReadAllLines(rspPath))
{
Assert.DoesNotContain("/analyzer:", line);
if (line.Contains("RegexGenerator.g.cs") && !line.StartsWith("/"))
{
foundPath = true;
}
}
Assert.True(foundPath);
var analyzers = Directory.GetFiles(Path.Combine(tempPath, "analyzers"), "*.dll", SearchOption.AllDirectories).ToList();
Assert.Equal(7, analyzers.Count);
});
}

[Fact]
public void ConsoleMultiTarget()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.Util/Basic.CompilerLog.Util.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net7.0;net472</TargetFrameworks>
<TargetFrameworks>net7.0;net472;netstandard2.0</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Packable>true</Packable>
Expand Down
13 changes: 10 additions & 3 deletions src/Basic.CompilerLog.Util/BasicAnalyzerHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public readonly struct BasicAnalyzerHostOptions
{
public static BasicAnalyzerHostOptions Default { get; } = new BasicAnalyzerHostOptions(BasicAnalyzerKind.Default, cacheable: true);

public static BasicAnalyzerHostOptions None { get; } = new BasicAnalyzerHostOptions(BasicAnalyzerKind.None, cacheable: true);

public static BasicAnalyzerKind RuntimeDefaultKind
{
get
Expand All @@ -34,7 +36,6 @@ public static BasicAnalyzerKind RuntimeDefaultKind

}


public BasicAnalyzerKind Kind { get; }

/// <summary>
Expand Down Expand Up @@ -114,6 +115,12 @@ public enum BasicAnalyzerKind
/// side effect <see cref="AnalyzerFileReference"/> instances.
/// </summary>
OnDisk = 2,

/// <summary>
/// Analyzers and generators are not loaded at all. The original generated files
/// will be loaded directly into the resulting <see cref="Compilation" />.
/// </summary>
None = 3,
}

/// <summary>
Expand Down Expand Up @@ -161,7 +168,7 @@ public void Dispose()
}
}

public abstract void DisposeCore();
protected abstract void DisposeCore();

protected void CheckDisposed()
{
Expand All @@ -176,7 +183,7 @@ public static bool IsSupported(BasicAnalyzerKind kind)
#if NETCOREAPP
return true;
#else
return kind is BasicAnalyzerKind.OnDisk or BasicAnalyzerKind.Default;
return kind is BasicAnalyzerKind.OnDisk or BasicAnalyzerKind.Default or BasicAnalyzerKind.None;
#endif
}
}
Expand Down
26 changes: 26 additions & 0 deletions src/Basic.CompilerLog.Util/CommonUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
#if NETCOREAPP
using System.Runtime.Loader;
#endif
Expand Down Expand Up @@ -38,4 +39,29 @@ internal static AssemblyLoadContext GetAssemblyLoadContext(AssemblyLoadContext?
}

#endif

internal static string GetAssemblyFileName(CommandLineArguments arguments)
{
if (arguments.OutputFileName is not null)
{
return arguments.OutputFileName;
}

string name = arguments.CompilationName ?? "app";
return Path.GetExtension(name) switch
{
".exe" => name,
".dll" => name,
".netmodule" => name,
_ => $"{name}{GetStandardAssemblyExtension()}"
};

string GetStandardAssemblyExtension() => arguments.CompilationOptions.OutputKind switch
{
OutputKind.NetModule => ".netmodule",
OutputKind.ConsoleApplication => ".exe",
OutputKind.WindowsApplication => ".exe",
_ => ".dll"
};
}
}
27 changes: 1 addition & 26 deletions src/Basic.CompilerLog.Util/CompilationData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ private void EnsureAnalyzersLoaded()
public EmitDiskResult EmitToDisk(string directory, CancellationToken cancellationToken = default)
{
var compilation = GetCompilationAfterGenerators(out var diagnostics, cancellationToken);
var assemblyName = GetAssemblyFileName();
var assemblyName = CommonUtil.GetAssemblyFileName(_commandLineArguments);
string assemblyFilePath = Path.Combine(directory, assemblyName);
Stream? peStream = null;
Stream? pdbStream = null;
Expand Down Expand Up @@ -232,31 +232,6 @@ public EmitMemoryResult EmitToMemory(CancellationToken cancellationToken = defau
diagnostics);
}

private string GetAssemblyFileName()
{
if (_commandLineArguments.OutputFileName is not null)
{
return _commandLineArguments.OutputFileName;
}

string name = Compilation.AssemblyName ?? "app";
return Path.GetExtension(name) switch
{
".exe" => name,
".dll" => name,
".netmodule" => name,
_ => $"{name}{GetStandardAssemblyExtension()}"
};
}

private string GetStandardAssemblyExtension() => CompilationOptions.OutputKind switch
{
OutputKind.NetModule => ".netmodule",
OutputKind.ConsoleApplication => ".exe",
OutputKind.WindowsApplication => ".exe",
_ => ".dll"
};

private bool IncludePdbStream() =>
EmitOptions.DebugInformationFormat != DebugInformationFormat.Embedded &&
!EmitOptions.EmitMetadataOnly;
Expand Down
4 changes: 4 additions & 0 deletions src/Basic.CompilerLog.Util/CompilerCall.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@ internal CompilerCall(string projectFilePath, CompilerCallKind kind, string? tar
Arguments = arguments;
Index = index;
}

public string GetDiagnosticName() => string.IsNullOrEmpty(TargetFramework)
? ProjectFileName
: $"{ProjectFileName} ({TargetFramework})";
}
Loading

0 comments on commit adaa7ac

Please sign in to comment.