Skip to content

Commit

Permalink
Merge pull request #1225 from neuecc/master
Browse files Browse the repository at this point in the history
Merge v2.2 into v2.3
  • Loading branch information
AArnott committed Apr 17, 2021
2 parents 8ca7fc2 + ff4ce58 commit 27230c7
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 28 deletions.
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -1546,7 +1546,7 @@ Check in your `.config\dotnet-tools.json` file. On another machine you can "rest
Once you have the tool installed, simply invoke using `dotnet mpc` within your repo:

```
dotnet mpc -h
dotnet mpc --help
```

Alternatively, you can download mpc from the [releases][Releases] page, that includes platform native binaries (that don't require a separate dotnet runtime).
Expand All @@ -1555,7 +1555,7 @@ Alternatively, you can download mpc from the [releases][Releases] page, that inc
Usage: mpc [options...]
Options:
-i, -input <String> Input path of analyze csproj or directory, if input multiple csproj split with ','. (Required)
-i, -input <String> Input path to MSBuild project file or the directory containing Unity source files. (Required)
-o, -output <String> Output file path(.cs) or directory(multiple generate file). (Required)
-c, -conditionalSymbol <String> Conditional compiler symbols, split with ','. (Default: null)
-r, -resolverName <String> Set resolver name. (Default: GeneratedResolver)
Expand Down
3 changes: 3 additions & 0 deletions src/MessagePack.GeneratorCore/CodeAnalysis/TypeCollector.cs
Expand Up @@ -534,6 +534,9 @@ private void CollectGeneric(INamedTypeSymbol type)
// NOTE: It is used to register formatters from nested generic type.
// However, closed generic types such as `Foo<string>` are not registered as a formatter.
GetObjectInfo(type);

// Collect generic type definition, that is not collected when it is defined outside target project.
CollectCore(type.OriginalDefinition);
}

// Collect substituted types for the type parameters (e.g. Bar in Foo<Bar>)
Expand Down
Expand Up @@ -43,7 +43,7 @@ public enum MyEnum
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down
105 changes: 91 additions & 14 deletions tests/MessagePack.Generator.Tests/GenerateGenericsFormatterTest.cs
Expand Up @@ -53,7 +53,7 @@ public enum MyEnum
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -100,7 +100,7 @@ public class MyObject
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -148,7 +148,7 @@ public class Wrapper<T>
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -213,7 +213,7 @@ public class MyInnerGenericObject<T>
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -297,7 +297,7 @@ public class MyInnerGenericObject<T>
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -365,7 +365,7 @@ public class MyGenericObject<T>
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -434,7 +434,7 @@ public class MyObjectNested
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -503,7 +503,7 @@ public class MyObjectNested
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -558,7 +558,7 @@ public class MyGenericObject<T>
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -607,7 +607,7 @@ public class MyGenericObject<T>
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -664,7 +664,7 @@ public class MyGenericClass<T> {}
public interface IMyInterface {}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -722,7 +722,7 @@ public class MyGenericObject<T>
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -781,7 +781,7 @@ public class MyGenericObject<T1, T2, T3, T4>
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -855,7 +855,7 @@ public class MyGenericObject<T1, T2>
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
Expand Down Expand Up @@ -883,5 +883,82 @@ public class MyGenericObject<T1, T2>
formatterType.TypeParameters[1].ConstraintTypes.Should().BeEmpty();
formatterType.TypeParameters[1].ReferenceTypeConstraintNullableAnnotation.Should().Be(NullableAnnotation.None);
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task Generics_Defined_In_ReferencedProject(bool isSingleFileOutput)
{
using var tempWorkarea = TemporaryProjectWorkarea.Create();
var defineContents = @"
using System;
using System.Collections.Generic;
using MessagePack;
namespace TempProject
{
[MessagePackObject]
public class MyGenericObject<T>
{
[Key(0)]
public T Content { get; set; }
}
}
";
tempWorkarea.AddFileToReferencedProject("MyGenericObject.cs", defineContents);

var usageContents = @"
using System;
using System.Collections.Generic;
using MessagePack;
namespace TempProject
{
[MessagePackObject]
public class MyObject
{
[Key(0)]
public MyGenericObject<int> Value { get; set; }
}
[MessagePackObject]
public class MyObjectNested
{
[Key(0)]
public MyGenericObject<MyGenericObject<int>> Value { get; set; }
}
}
";
tempWorkarea.AddFileToTargetProject("MyObject.cs", usageContents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);
await compiler.GenerateFileAsync(
tempWorkarea.GetOutputCompilation().Compilation,
isSingleFileOutput ? Path.Combine(tempWorkarea.OutputDirectory, "Generated.cs") : tempWorkarea.OutputDirectory,
"TempProjectResolver",
"TempProject.Generated",
false,
string.Empty,
Array.Empty<string>());

var compilation = tempWorkarea.GetOutputCompilation();
compilation.Compilation.GetDiagnostics().Where(x => x.WarningLevel == 0).Should().BeEmpty();

var symbols = compilation.GetNamedTypeSymbolsFromGenerated();

var types = symbols.Select(x => x.ToDisplayString()).ToArray();
types.Should().Contain("TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<T>");

var formatters = symbols.SelectMany(x => x.Interfaces).Select(x => x.ToDisplayString()).ToArray();
formatters.Should().Contain("MessagePack.Formatters.IMessagePackFormatter<TempProject.MyGenericObject<T>>");

compilation.GetResolverKnownFormatterTypes().Should().Contain(new[]
{
"TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<global::TempProject.MyGenericObject<int>>",
"TempProject.Generated.Formatters.TempProject.MyGenericObjectFormatter<int>",
"TempProject.Generated.Formatters.TempProject.MyObjectFormatter",
"TempProject.Generated.Formatters.TempProject.MyObjectNestedFormatter",
});
}
}
}
Expand Up @@ -56,7 +56,7 @@ public class Bar
}
}
";
tempWorkarea.AddFileToProject("MyMessagePackObject.cs", contents);
tempWorkarea.AddFileToTargetProject("MyMessagePackObject.cs", contents);

var compiler = new MessagePackCompiler.CodeGenerator(testOutputHelper.WriteLine, CancellationToken.None);

Expand Down
77 changes: 67 additions & 10 deletions tests/MessagePack.Generator.Tests/TemporaryProjectWorkarea.cs
Expand Up @@ -20,12 +20,23 @@ namespace MessagePack.Generator.Tests
public class TemporaryProjectWorkarea : IDisposable
{
private readonly string tempDirPath;
private readonly string csprojFileName = "TempProject.csproj";
private readonly string targetCsprojFileName = "TempTargetProject.csproj";
private readonly string referencedCsprojFileName = "TempReferencedProject.csproj";
private readonly bool cleanOnDisposing;

public string CsProjectPath { get; }
/// <summary>
/// Gets Generator target csproj file path.
/// </summary>
public string TargetCsProjectPath { get; }

public string ProjectDirectory { get; }
/// <summary>
/// Gets csproj file path Referenced from TargetProject.
/// </summary>
public string ReferencedCsProjectPath { get; }

public string TargetProjectDirectory { get; }

public string ReferencedProjectDirectory { get; }

public string OutputDirectory { get; }

Expand All @@ -39,17 +50,33 @@ private TemporaryProjectWorkarea(bool cleanOnDisposing)
this.cleanOnDisposing = cleanOnDisposing;
this.tempDirPath = Path.Combine(Path.GetTempPath(), $"MessagePack.Generator.Tests-{Guid.NewGuid()}");

ProjectDirectory = Path.Combine(tempDirPath, "Project");
TargetProjectDirectory = Path.Combine(tempDirPath, "TargetProject");
ReferencedProjectDirectory = Path.Combine(tempDirPath, "ReferencedProject");
OutputDirectory = Path.Combine(tempDirPath, "Output");

Directory.CreateDirectory(ProjectDirectory);
Directory.CreateDirectory(TargetProjectDirectory);
Directory.CreateDirectory(ReferencedProjectDirectory);
Directory.CreateDirectory(OutputDirectory);

var solutionRootDir = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "../../../.."));
var messagePackProjectDir = Path.Combine(solutionRootDir, "src/MessagePack/MessagePack.csproj");
var annotationsProjectDir = Path.Combine(solutionRootDir, "src/MessagePack.Annotations/MessagePack.Annotations.csproj");

CsProjectPath = Path.Combine(ProjectDirectory, csprojFileName);
ReferencedCsProjectPath = Path.Combine(ReferencedProjectDirectory, referencedCsprojFileName);
var referencedCsprojContents = @"
<Project Sdk=""Microsoft.NET.Sdk"">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include=""" + annotationsProjectDir + @""" />
</ItemGroup>
</Project>
";
AddFileToReferencedProject(referencedCsprojFileName, referencedCsprojContents);

TargetCsProjectPath = Path.Combine(TargetProjectDirectory, targetCsprojFileName);
var csprojContents = @"
<Project Sdk=""Microsoft.NET.Sdk"">
<PropertyGroup>
Expand All @@ -59,26 +86,56 @@ private TemporaryProjectWorkarea(bool cleanOnDisposing)
<ItemGroup>
<ProjectReference Include=""" + messagePackProjectDir + @""" />
<ProjectReference Include=""" + annotationsProjectDir + @""" />
<ProjectReference Include=""" + ReferencedCsProjectPath + @""" />
</ItemGroup>
</Project>
";
AddFileToProject(csprojFileName, csprojContents);
AddFileToTargetProject(targetCsprojFileName, csprojContents);
}

/// <summary>
/// Add file to Generator target project.
/// </summary>
public void AddFileToTargetProject(string fileName, string contents)
{
File.WriteAllText(Path.Combine(TargetProjectDirectory, fileName), contents.Trim());
}

public void AddFileToProject(string fileName, string contents)
/// <summary>
/// Add file to project, referenced by Generator target project.
/// </summary>
public void AddFileToReferencedProject(string fileName, string contents)
{
File.WriteAllText(Path.Combine(ProjectDirectory, fileName), contents.Trim());
File.WriteAllText(Path.Combine(ReferencedProjectDirectory, fileName), contents.Trim());
}

public OutputCompilation GetOutputCompilation()
{
var refAsmDir = Path.GetDirectoryName(typeof(object).Assembly.Location);

var referenceCompilation = CSharpCompilation.Create(Guid.NewGuid().ToString())
.AddSyntaxTrees(
Directory.EnumerateFiles(ReferencedProjectDirectory, "*.cs", SearchOption.AllDirectories)
.Select(x => CSharpSyntaxTree.ParseText(File.ReadAllText(x), CSharpParseOptions.Default, x)))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Private.CoreLib.dll")))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Runtime.Extensions.dll")))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Collections.dll")))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Linq.dll")))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Console.dll")))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Runtime.dll")))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Memory.dll")))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "netstandard.dll")))
.AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location))
.AddReferences(MetadataReference.CreateFromFile(typeof(MessagePack.MessagePackObjectAttribute).Assembly.Location))
.AddReferences(MetadataReference.CreateFromFile(typeof(IMessagePackFormatter<>).Assembly.Location))
.WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

var compilation = CSharpCompilation.Create(Guid.NewGuid().ToString())
.AddSyntaxTrees(
Directory.EnumerateFiles(ProjectDirectory, "*.cs", SearchOption.AllDirectories)
Directory.EnumerateFiles(TargetProjectDirectory, "*.cs", SearchOption.AllDirectories)
.Concat(Directory.EnumerateFiles(OutputDirectory, "*.cs", SearchOption.AllDirectories))
.Select(x => CSharpSyntaxTree.ParseText(File.ReadAllText(x), CSharpParseOptions.Default, x)))
.AddReferences(referenceCompilation.ToMetadataReference())
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Private.CoreLib.dll")))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Runtime.Extensions.dll")))
.AddReferences(MetadataReference.CreateFromFile(Path.Combine(refAsmDir, "System.Collections.dll")))
Expand Down

0 comments on commit 27230c7

Please sign in to comment.