Skip to content

Commit

Permalink
Fix link round tripping (#159)
Browse files Browse the repository at this point in the history
closes #158
  • Loading branch information
jaredpar authored Sep 25, 2024
1 parent fcf9a82 commit 779b25b
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 10 deletions.
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.UnitTests/BinaryLogReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public void ReadCommandLineArgumentsOwnership()
var compilerCall = reader.ReadAllCompilerCalls().First();
Assert.NotNull(reader.ReadCommandLineArguments(compilerCall));

compilerCall = compilerCall.ChangeOwner(null);
compilerCall = compilerCall.WithOwner(null);
Assert.Throws<ArgumentException>(() => reader.ReadCommandLineArguments(compilerCall));
}

Expand Down
22 changes: 22 additions & 0 deletions src/Basic.CompilerLog.UnitTests/CompilerCallTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

using Basic.CompilerLog.Util;
using Xunit;

namespace Basic.CompilerLog.UnitTests;

public class CompilerCallTests
{
[Fact]
public void GetDiagnosticNameNoTargetFramework()
{
var compilerCall = new CompilerCall(
compilerFilePath: null,
"test.csproj",
CompilerCallKind.Regular,
targetFramework: null,
isCSharp: true,
arguments: new (() => []));
Assert.Null(compilerCall.TargetFramework);
Assert.Equal(compilerCall.ProjectFileName, compilerCall.GetDiagnosticName());
}
}
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.UnitTests/CompilerLogBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public void AddMissingFile()
using var binlogStream = new FileStream(Fixture.ConsoleWithDiagnosticsBinaryLogPath, FileMode.Open, FileAccess.Read, FileShare.Read);

var compilerCall = BinaryLogUtil.ReadAllCompilerCalls(binlogStream).First(x => x.IsCSharp);
compilerCall = compilerCall.ChangeArguments(["/sourcelink:does-not-exist.txt"]);
compilerCall = compilerCall.WithArguments(["/sourcelink:does-not-exist.txt"]);
Assert.Throws<Exception>(() => builder.AddFromDisk(compilerCall, BinaryLogUtil.ReadCommandLineArgumentsUnsafe(compilerCall)));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private CompilerLogReader ConvertConsoleArgs(Func<IReadOnlyCollection<string>, I
ConvertConsole(x =>
{
var args = func(x.GetArguments());
return x.ChangeArguments(args);
return x.WithArguments(args);
}, basicAnalyzerKind);

[Fact]
Expand Down
2 changes: 1 addition & 1 deletion src/Basic.CompilerLog.UnitTests/CompilerLogReaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ public void ReadCompilerCallWrongOwner()
{
using var reader = CompilerLogReader.Create(Fixture.Console.Value.CompilerLogPath);
var compilerCall = reader.ReadCompilerCall(0);
compilerCall = compilerCall.ChangeOwner(null);
compilerCall = compilerCall.WithOwner(null);
Assert.Throws<ArgumentException>(() => reader.ReadCompilationData(compilerCall));
}

Expand Down
50 changes: 49 additions & 1 deletion src/Basic.CompilerLog.UnitTests/ExportUtilTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Basic.CompilerLog.Util;
using Basic.Reference.Assemblies;
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
Expand Down Expand Up @@ -45,6 +46,11 @@ private void TestExport(string compilerLogFilePath, int? expectedCount, bool inc
internal static void TestExport(ITestOutputHelper testOutputHelper, string compilerLogFilePath, int? expectedCount, bool includeAnalyzers = true, Action<string>? verifyExportCallback = null, bool runBuild = true)
{
using var reader = CompilerLogReader.Create(compilerLogFilePath);
TestExport(testOutputHelper, reader, expectedCount, includeAnalyzers, verifyExportCallback, runBuild);
}

internal static void TestExport(ITestOutputHelper testOutputHelper, CompilerLogReader reader, int? expectedCount, bool includeAnalyzers = true, Action<string>? verifyExportCallback = null, bool runBuild = true)
{
#if NET
var sdkDirs = SdkUtil.GetSdkDirectories();
#else
Expand All @@ -65,7 +71,7 @@ internal static void TestExport(ITestOutputHelper testOutputHelper, string compi
var buildResult = RunBuildCmd(tempDir.DirectoryPath);
testOutputHelper.WriteLine(buildResult.StandardOut);
testOutputHelper.WriteLine(buildResult.StandardError);
Assert.True(buildResult.Succeeded, $"Cannot build {Path.GetFileName(compilerLogFilePath)}");
Assert.True(buildResult.Succeeded, $"Cannot build {compilerCall.ProjectFileName}");
}

// Ensure that full paths aren't getting written out to the RSP file. That makes the
Expand Down Expand Up @@ -182,6 +188,48 @@ public void ConsoleWithRuleset()
}, runBuild: false);
}

/// <summary>
/// Make sure that we can round trip a /link argument. That is a reference that we are embedding
/// interop types for.
/// </summary>
[Fact]
public void ConsoleWithLink()
{
var piaInfo = LibraryUtil.GetSimplePia();
var linkFilePath = Root.NewFile(piaInfo.FileName, piaInfo.Image);

using var reader = CreateReader(builder =>
{
using var binlogReader = BinaryLogReader.Create(Fixture.Console.Value.BinaryLogPath!);
var compilerCall = binlogReader.ReadAllCompilerCalls().Single();
string[] args =
[
.. compilerCall.GetArguments(),
$"/link:{linkFilePath}"
];
compilerCall = compilerCall.WithArguments(args);
var commandLineArgs = binlogReader.ReadCommandLineArguments(compilerCall);
Assert.True(commandLineArgs.MetadataReferences.Any(x => x.Properties.EmbedInteropTypes));
builder.AddFromDisk(compilerCall, commandLineArgs);
});

TestExport(TestOutputHelper, reader, expectedCount: 1, verifyExportCallback: tempPath =>
{
var rspPath = Path.Combine(tempPath, "build.rsp");
var foundPath = false;
foreach (var line in File.ReadAllLines(rspPath))
{
if (line.StartsWith("/link:", StringComparison.Ordinal))
{
foundPath = true;
Assert.Equal($@"/link:""ref{Path.DirectorySeparatorChar}{piaInfo.FileName}""", line);
}
}
Assert.True(foundPath);
}, runBuild: true);
}

[Fact]
public void StrongNameKey()
{
Expand Down
4 changes: 2 additions & 2 deletions src/Basic.CompilerLog.UnitTests/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ internal static void ForEach<T>(this IEnumerable<T> enumerable, Action<T> action
}
}

internal static CompilerCall ChangeArguments(this CompilerCall compilerCall, IReadOnlyCollection<string> arguments)
internal static CompilerCall WithArguments(this CompilerCall compilerCall, IReadOnlyCollection<string> arguments)
{
return new CompilerCall(
compilerCall.CompilerFilePath,
Expand All @@ -51,7 +51,7 @@ internal static CompilerCall ChangeArguments(this CompilerCall compilerCall, IRe
compilerCall.OwnerState);
}

internal static CompilerCall ChangeOwner(this CompilerCall compilerCall, object? ownerState)
internal static CompilerCall WithOwner(this CompilerCall compilerCall, object? ownerState)
{
var args = compilerCall.GetArguments();
return new CompilerCall(
Expand Down
70 changes: 70 additions & 0 deletions src/Basic.CompilerLog.UnitTests/LibraryUtil.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@

using System.Text;
using Basic.Reference.Assemblies;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;

namespace Basic.CompilerLog.UnitTests;

/// <summary>
/// Class that builds helper libraries that are useful in tests
/// </summary>
internal static class LibraryUtil
{
internal static (string FileName, MemoryStream Image) GetSimplePia()
{
var content1 = """
using System.Runtime.InteropServices;

[Guid("E8E4B023-7408-4A71-B3F6-ADEDE0A8FE11")]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface ICalculator
{
[DispId(1)] // COM method identifiers
int Add(int x, int y);

[DispId(2)]
int Subtract(int x, int y);
}

""";

var content2 = """
using System.Reflection;
using System.Runtime.InteropServices;

[assembly: ComVisible(true)]
[assembly: Guid("12345678-90AB-CDEF-1234-567890ABCDEF")]
[assembly: PrimaryInteropAssembly(1, 0)]
""";

var compilation = CSharpCompilation.Create(
"SimplePia",
[ CSharpSyntaxTree.ParseText(content1), CSharpSyntaxTree.ParseText(content2) ],
Net60.References.All,
new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

var peStream = new MemoryStream();
var emitResult = compilation.Emit(peStream);
if (!emitResult.Success)
{
throw new Exception(GetMessage(emitResult.Diagnostics));
}

peStream.Position = 0;
return ("SimplePia.dll", peStream);

string GetMessage(IEnumerable<Diagnostic> diagnostics)
{
var builder = new StringBuilder();
builder.AppendLine("Compilation failed with the following errors:");
foreach (var d in diagnostics)
{
builder.AppendLine(d.ToString());
}
return builder.ToString();
}

}

}
8 changes: 8 additions & 0 deletions src/Basic.CompilerLog.UnitTests/TempDir.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ public string NewFile(string fileName, string content)
return filePath;
}

public string NewFile(string fileName, Stream content)
{
var filePath = Path.Combine(DirectoryPath, fileName);
using var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
content.CopyTo(fileStream);
return filePath;
}

public string NewDirectory(string? name = null)
{
name ??= Guid.NewGuid().ToString();
Expand Down
13 changes: 10 additions & 3 deletions src/Basic.CompilerLog.Util/ExportUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,13 @@ void WriteBuildCmd(string sdkDir, string cmdFileName)

List<string> ProcessRsp()
{
var lines = new List<string>();
var arguments = compilerCall.GetArguments();
var lines = new List<string>(capacity: arguments.Count);

// compiler options aren't case sensitive
var comparison = StringComparison.OrdinalIgnoreCase;

foreach (var line in compilerCall.GetArguments())
foreach (var line in arguments)
{
// The only non-options are source files and those are rewritten by other
// methods and added to commandLineList
Expand All @@ -196,7 +197,8 @@ List<string> ProcessRsp()
span.StartsWith("resource", comparison) ||
span.StartsWith("linkresource", comparison) ||
span.StartsWith("ruleset", comparison) ||
span.StartsWith("keyfile", comparison))
span.StartsWith("keyfile", comparison) ||
span.StartsWith("link", comparison))
{
continue;
}
Expand Down Expand Up @@ -250,6 +252,11 @@ void WriteReferences()
commandLineList.Add(arg);
}
}
else if (tuple.EmbedInteropTypes)
{
var arg = $@"/link:""{PathUtil.RemovePathStart(filePath, destinationDir)}""";
commandLineList.Add(arg);
}
else
{
var arg = $@"/reference:""{PathUtil.RemovePathStart(filePath, destinationDir)}""";
Expand Down

0 comments on commit 779b25b

Please sign in to comment.