Skip to content

Add EventSource event method generation #107176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ public enum EventActivityOptions
Recursive = 4,
Detachable = 8,
}
[AttributeUsage(System.AttributeTargets.Class)]
public sealed class GeneratedEventSourceEventAttribute : Attribute
{
}

[System.AttributeUsageAttribute(System.AttributeTargets.Method)]
public sealed partial class EventAttribute : System.Attribute
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

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

namespace System.Diagnostics.Tracing.Tests.GenerateTest
{
[ExcludeFromCodeCoverage]
internal static class Baselines
{
public static SourceText GetBaselineNode(string fileName)
{
var text = GetBaseline(fileName);
return SourceText.From(text, Encoding.UTF8);
}

public static SyntaxTree GetBaselineTree(string fileName)
{
var sourceText = GetBaselineNode(fileName);
return CSharpSyntaxTree.ParseText(sourceText, path: fileName);
}

public static string GetBaseline(string fileName)
{
using (var stream = typeof(Baselines).Assembly.GetManifestResourceStream($"System.Diagnostics.Tracing.Tests.GenerateTest.Baselines.{fileName}"))
{
if (stream == null)
{
throw new ArgumentException($"No base line file {fileName}");
}
return new StreamReader(stream).ReadToEnd();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// <auto-generated/>
namespace evev
{
internal unsafe partial class TestEventSource
{
public partial void Event0()
{
WriteEvent(1);
OnEvent0();
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0();

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// <auto-generated/>
namespace evev
{
internal unsafe partial class TestEventSource
{
public partial void Event0(int arg0)
{
global::System.Diagnostics.Tracing.EventSource.EventData* datas = stackalloc global::System.Diagnostics.Tracing.EventSource.EventData[1];
datas[0] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)(&arg0),
Size = sizeof(int)
};
WriteEventCore(1, 1, datas);
OnEvent0(arg0);
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0(int arg0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// <auto-generated/>
namespace evev
{
internal unsafe partial class TestEventSource
{
public partial void Event0(int arg0, double arg1)
{
global::System.Diagnostics.Tracing.EventSource.EventData* datas = stackalloc global::System.Diagnostics.Tracing.EventSource.EventData[2];
datas[0] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)(&arg0),
Size = sizeof(int)
};
datas[1] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)(&arg1),
Size = sizeof(double)
};
WriteEventCore(1, 2, datas);
OnEvent0(arg0, arg1);
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0(int arg0, double arg1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// <auto-generated/>
namespace evev
{
internal unsafe partial class TestEventSource
{
public partial void Event0(string arg0)
{
global::System.Diagnostics.Tracing.EventSource.EventData* datas = stackalloc global::System.Diagnostics.Tracing.EventSource.EventData[1];
arg0 ??= System.String.Empty;
datas[0] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref global::System.Runtime.InteropServices.MemoryMarshal.GetReference(global::System.MemoryExtensions.AsSpan(arg0))),
Size = (arg0.Length + 1) * sizeof(char)
};
WriteEventCore(1, 1, datas);
OnEvent0(arg0);
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0(string arg0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// <auto-generated/>
namespace evev
{
internal unsafe partial class TestEventSource
{
public partial void Event0(string arg0, string arg1)
{
global::System.Diagnostics.Tracing.EventSource.EventData* datas = stackalloc global::System.Diagnostics.Tracing.EventSource.EventData[2];
arg0 ??= System.String.Empty;
datas[0] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref global::System.Runtime.InteropServices.MemoryMarshal.GetReference(global::System.MemoryExtensions.AsSpan(arg0))),
Size = (arg0.Length + 1) * sizeof(char)
};
arg1 ??= System.String.Empty;
datas[1] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref global::System.Runtime.InteropServices.MemoryMarshal.GetReference(global::System.MemoryExtensions.AsSpan(arg1))),
Size = (arg1.Length + 1) * sizeof(char)
};
WriteEventCore(1, 2, datas);
OnEvent0(arg0, arg1);
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0(string arg0, string arg1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// <auto-generated/>
internal unsafe partial class TestEventSource
{
public partial void Event0()
{
WriteEvent(1);
OnEvent0();
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// <auto-generated/>
internal unsafe partial class TestEventSource
{
public partial void Event0(int arg0)
{
global::System.Diagnostics.Tracing.EventSource.EventData* datas = stackalloc global::System.Diagnostics.Tracing.EventSource.EventData[1];
datas[0] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)(&arg0),
Size = sizeof(int)
};
WriteEventCore(1, 1, datas);
OnEvent0(arg0);
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0(int arg0);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// <auto-generated/>
internal unsafe partial class TestEventSource
{
public partial void Event0(int arg0, double arg1)
{
global::System.Diagnostics.Tracing.EventSource.EventData* datas = stackalloc global::System.Diagnostics.Tracing.EventSource.EventData[2];
datas[0] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)(&arg0),
Size = sizeof(int)
};
datas[1] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)(&arg1),
Size = sizeof(double)
};
WriteEventCore(1, 2, datas);
OnEvent0(arg0, arg1);
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0(int arg0, double arg1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// <auto-generated/>
internal unsafe partial class TestEventSource
{
public partial void Event0(string arg0)
{
global::System.Diagnostics.Tracing.EventSource.EventData* datas = stackalloc global::System.Diagnostics.Tracing.EventSource.EventData[1];
arg0 ??= System.String.Empty;
datas[0] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref global::System.Runtime.InteropServices.MemoryMarshal.GetReference(global::System.MemoryExtensions.AsSpan(arg0))),
Size = (arg0.Length + 1) * sizeof(char)
};
WriteEventCore(1, 1, datas);
OnEvent0(arg0);
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0(string arg0);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// <auto-generated/>
internal unsafe partial class TestEventSource
{
public partial void Event0(string arg0, string arg1)
{
global::System.Diagnostics.Tracing.EventSource.EventData* datas = stackalloc global::System.Diagnostics.Tracing.EventSource.EventData[2];
arg0 ??= System.String.Empty;
datas[0] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref global::System.Runtime.InteropServices.MemoryMarshal.GetReference(global::System.MemoryExtensions.AsSpan(arg0))),
Size = (arg0.Length + 1) * sizeof(char)
};
arg1 ??= System.String.Empty;
datas[1] = new global::System.Diagnostics.Tracing.EventSource.EventData
{
DataPointer = (nint)global::System.Runtime.CompilerServices.Unsafe.AsPointer(ref global::System.Runtime.InteropServices.MemoryMarshal.GetReference(global::System.MemoryExtensions.AsSpan(arg1))),
Size = (arg1.Length + 1) * sizeof(char)
};
WriteEventCore(1, 2, datas);
OnEvent0(arg0, arg1);
}

[global::System.Diagnostics.Tracing.NonEventAttribute]
partial void OnEvent0(string arg0, string arg1);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Generators;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Xunit;

namespace System.Diagnostics.Tracing.Tests.GenerateTest
{
[ExcludeFromCodeCoverage]
internal static class Compiler
{
private static readonly CSharpCompilationOptions compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, allowUnsafe: true, nullableContextOptions: NullableContextOptions.Enable);

private static readonly MetadataReference[] metadataReferences = new[]
{
MetadataReference.CreateFromFile(typeof(Attribute).GetTypeInfo().Assembly.Location),
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(ActivitySource).Assembly.Location)
}.Concat(AppDomain.CurrentDomain.GetAssemblies().Where(x =>
{
try
{
return !string.IsNullOrEmpty(x.Location);
}
catch (Exception)
{
return false;
}
}).Select(x => MetadataReference.CreateFromFile(x.Location))).ToArray();

public static Compilation CreateCompilation(string source)
=> CSharpCompilation.Create("compilation",
new[] { CSharpSyntaxTree.ParseText(source) },
metadataReferences,
compilationOptions);

public static ImmutableArray<Diagnostic> GetDiagnostics(string code)
{
var compiler = CreateCompilation(code);

GeneratorDriver driver = CSharpGeneratorDriver.Create(new EventSourceEventGenerator());
driver = driver.RunGeneratorsAndUpdateCompilation(compiler, out _, out var diagnostics);
if (diagnostics.Length==0)
{
return compiler.GetDiagnostics();
}
return diagnostics;
}

public static GeneratorDriverRunResult CheckGenerated(string code, int willGeneratedFile)
{
var compiler = CreateCompilation(code);

GeneratorDriver driver = CSharpGeneratorDriver.Create(new EventSourceEventGenerator());
driver = driver.RunGeneratorsAndUpdateCompilation(compiler, out var outputCompilation, out var diagnostics);

Assert.True(diagnostics.IsEmpty); // there were no diagnostics created by the generators
Assert.True(outputCompilation.GetDiagnostics().IsEmpty, string.Join("\n", outputCompilation.GetDiagnostics().Select(x => x.ToString()))); // verify the compilation with the added source has no diagnostics

GeneratorDriverRunResult runResult = driver.GetRunResult();

Assert.Equal(willGeneratedFile, runResult.GeneratedTrees.Length);
Assert.True(runResult.Diagnostics.IsEmpty);

return runResult;
}

public static void CheckGeneratedSingle(string code, string baseLineFileName)
{
var result = CheckGenerated(code, 1);

var syntaxTree = Baselines.GetBaselineTree(baseLineFileName);
GeneratorRunResult generatorResult = result.Results[0];
Assert.NotNull(syntaxTree);
Assert.NotNull(generatorResult.GeneratedSources[0].SourceText);
Assert.True(generatorResult.GeneratedSources[0].SyntaxTree.IsEquivalentTo(syntaxTree),$"Expect:[{syntaxTree}]\nActual:[{generatorResult.GeneratedSources[0].SyntaxTree}]");
}

public static void CheckGeneratedMore(string code, List<(Type sourceGenerateType, string hitName, string baseLineFileName)> equals)
{
var result = CheckGenerated(code, equals.Count);

foreach (var item in equals)
{
var gen = result.Results.FirstOrDefault(x => x.Generator.GetGeneratorType() == item.sourceGenerateType);

if (gen.Generator == null)
{
Assert.Fail($"Can't find {item.sourceGenerateType} generated result");
}

var baseLine = Baselines.GetBaselineNode(item.baseLineFileName);

var fi = gen.GeneratedSources.FirstOrDefault(x => x.HintName == item.hitName);

if (fi.HintName != item.hitName)
{
Assert.Fail($"Can't find {item.sourceGenerateType} hitName {item.hitName} file");
}

Assert.True(fi.SourceText.ContentEquals(baseLine));
}
}
}
}
Loading
Loading