Merge branch 'master' into fsharp-async-task-support

This commit is contained in:
Ben Adams 2021-01-03 16:55:03 +00:00 committed by GitHub
commit 5dd50f12da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 212 additions and 90 deletions

2
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,2 @@
github: [benaadams]

11
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "nuget" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "daily"

41
.github/workflows/pull-request.yaml vendored Normal file
View File

@ -0,0 +1,41 @@
name: Demystifier PR Build
on: pull_request
jobs:
build:
name: "Build for PR"
runs-on: ${{ matrix.os }}
env:
DOTNET_NOLOGO: true
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-18.04, macOS-latest]
config: [Debug, Release]
steps:
- name: Clone source
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Install .NET Core SDK 2.1
uses: actions/setup-dotnet@v1
with:
dotnet-version: '2.1.x'
- name: Install .NET Core SDK 3.1
uses: actions/setup-dotnet@v1
with:
dotnet-version: '3.1.x'
- name: Install .NET SDK 5.0
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.x'
- name: Get .NET information
run: dotnet --info
- name: "Test"
run: dotnet test -c ${{ matrix.config }}

View File

@ -1,32 +0,0 @@
image: Visual Studio 2017
branches:
only:
- master
skip_branch_with_pr: true
skip_tags: true
skip_commits:
files:
- BUILDING.md
- CONTRIBUTING.md
- ISSUE_TEMPLATE.md
- LICENCE
- README.md
nuget:
disable_publish_on_pr: true
build_script:
- ps: .\build.ps1 -target appveyor
test: off
deploy: off
artifacts:
- path: artifacts/build
- path: artifacts/packages
- path: artifacts/test

View File

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework> <TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -11,6 +11,7 @@
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<IncludeSource>true</IncludeSource> <IncludeSource>true</IncludeSource>
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
@ -21,12 +22,13 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.0.25" PrivateAssets="all" /> <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" PrivateAssets="all" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" PrivateAssets="all" />
<PackageReference Include="System.Reflection.Metadata"> <PackageReference Include="System.Reflection.Metadata">
<Version>1.6.0</Version> <Version>5.0.0</Version>
</PackageReference> </PackageReference>
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.3" Condition="'$(TargetFramework)' != 'netstandard2.1'" /> <PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.4" Condition="'$(TargetFramework)' != 'netstandard2.1'" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
</ItemGroup> </ItemGroup>
<ItemGroup Label="TestInternalsVisibleTo"> <ItemGroup Label="TestInternalsVisibleTo">

View File

@ -53,7 +53,7 @@ namespace System.Diagnostics
var method = frame.GetMethod(); var method = frame.GetMethod();
// Always show last stackFrame // Always show last stackFrame
if (!ShowInStackTrace(method) && i < stackFrames.Length - 1) if (method != null && !ShowInStackTrace(method) && i < stackFrames.Length - 1)
{ {
continue; continue;
} }
@ -62,7 +62,7 @@ namespace System.Diagnostics
var row = frame.GetFileLineNumber(); var row = frame.GetFileLineNumber();
var column = frame.GetFileColumnNumber(); var column = frame.GetFileColumnNumber();
var ilOffset = frame.GetILOffset(); var ilOffset = frame.GetILOffset();
if (string.IsNullOrEmpty(fileName) && ilOffset >= 0) if (method != null && string.IsNullOrEmpty(fileName) && ilOffset >= 0)
{ {
// .NET Framework and older versions of mono don't support portable PDBs // .NET Framework and older versions of mono don't support portable PDBs
// so we read it manually to get file name and line information // so we read it manually to get file name and line information
@ -636,6 +636,18 @@ namespace System.Diagnostics
{ {
Debug.Assert(method != null); Debug.Assert(method != null);
// Since .NET 5:
// https://github.com/dotnet/runtime/blob/7c18d4d6488dab82124d475d1199def01d1d252c/src/libraries/System.Private.CoreLib/src/System/Diagnostics/StackTrace.cs#L348-L361
if ((method.MethodImplementationFlags & MethodImplAttributes.AggressiveInlining) != 0)
{
// Aggressive Inlines won't normally show in the StackTrace; however for Tier0 Jit and
// cross-assembly AoT/R2R these inlines will be blocked until Tier1 Jit re-Jits
// them when they will inline. We don't show them in the StackTrace to bring consistency
// between this first-pass asm and fully optimized asm.
return false;
}
// Since .NET Core 2:
if (StackTraceHiddenAttributeType != null) if (StackTraceHiddenAttributeType != null)
{ {
// Don't show any methods marked with the StackTraceHiddenAttribute // Don't show any methods marked with the StackTraceHiddenAttribute
@ -653,6 +665,17 @@ namespace System.Diagnostics
return true; return true;
} }
// Since .NET Core 2:
if (StackTraceHiddenAttributeType != null)
{
// Don't show any methods marked with the StackTraceHiddenAttribute
// https://github.com/dotnet/coreclr/pull/14652
if (IsStackTraceHidden(type))
{
return false;
}
}
if (type == typeof(Task<>) && method.Name == "InnerInvoke") if (type == typeof(Task<>) && method.Name == "InnerInvoke")
{ {
return false; return false;
@ -661,8 +684,13 @@ namespace System.Diagnostics
{ {
return false; return false;
} }
if (type == typeof(Task)) if (type == typeof(Task) || type.DeclaringType == typeof(Task))
{ {
if (method.Name.Contains(".cctor"))
{
return false;
}
switch (method.Name) switch (method.Name)
{ {
case "ExecuteWithThreadLocal": case "ExecuteWithThreadLocal":
@ -670,15 +698,24 @@ namespace System.Diagnostics
case "ExecutionContextCallback": case "ExecutionContextCallback":
case "ExecuteEntry": case "ExecuteEntry":
case "InnerInvoke": case "InnerInvoke":
case "ExecuteEntryUnsafe":
case "ExecuteFromThreadPool":
case "s_ecCallback":
return false; return false;
} }
} }
if (type == typeof(ExecutionContext)) if (type == typeof(ExecutionContext))
{ {
if (method.Name.Contains(".cctor"))
{
return false;
}
switch (method.Name) switch (method.Name)
{ {
case "RunInternal": case "RunInternal":
case "Run": case "Run":
case "RunFromThreadPoolDispatchLoop":
return false; return false;
} }
} }
@ -706,44 +743,33 @@ namespace System.Diagnostics
} }
} }
if (StackTraceHiddenAttributeType != null) // Fallbacks for runtime pre-StackTraceHiddenAttribute
if (type == typeof(ExceptionDispatchInfo) && method.Name == "Throw")
{ {
// Don't show any types marked with the StackTraceHiddenAttribute return false;
// https://github.com/dotnet/coreclr/pull/14652 }
if (IsStackTraceHidden(type))
if (type == typeof(TaskAwaiter) ||
type == typeof(TaskAwaiter<>) ||
type == typeof(ValueTaskAwaiter) ||
type == typeof(ValueTaskAwaiter<>) ||
type == typeof(ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter) ||
type == typeof(ConfiguredValueTaskAwaitable<>.ConfiguredValueTaskAwaiter) ||
type == typeof(ConfiguredTaskAwaitable.ConfiguredTaskAwaiter) ||
type == typeof(ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter))
{
switch (method.Name)
{ {
return false; case "HandleNonSuccessAndDebuggerNotification":
case "ThrowForNonSuccess":
case "ValidateEnd":
case "GetResult":
return false;
} }
} }
else else if (type.FullName == "System.ThrowHelper")
{ {
// Fallbacks for runtime pre-StackTraceHiddenAttribute return false;
if (type == typeof(ExceptionDispatchInfo) && method.Name == "Throw")
{
return false;
}
else if (type == typeof(TaskAwaiter) ||
type == typeof(TaskAwaiter<>) ||
type == typeof(ValueTaskAwaiter) ||
type == typeof(ValueTaskAwaiter<>) ||
type == typeof(ConfiguredValueTaskAwaitable.ConfiguredValueTaskAwaiter) ||
type == typeof(ConfiguredValueTaskAwaitable<>.ConfiguredValueTaskAwaiter) ||
type == typeof(ConfiguredTaskAwaitable.ConfiguredTaskAwaiter) ||
type == typeof(ConfiguredTaskAwaitable<>.ConfiguredTaskAwaiter))
{
switch (method.Name)
{
case "HandleNonSuccessAndDebuggerNotification":
case "ThrowForNonSuccess":
case "ValidateEnd":
case "GetResult":
return false;
}
}
else if (type.FullName == "System.ThrowHelper")
{
return false;
}
} }
return true; return true;

View File

@ -69,9 +69,8 @@ namespace System.Diagnostics
} }
var genericPartIndex = type.Name.IndexOf('`'); var genericPartIndex = type.Name.IndexOf('`');
Debug.Assert(genericPartIndex >= 0);
return type.Name.Substring(0, genericPartIndex); return (genericPartIndex >= 0) ? type.Name.Substring(0, genericPartIndex) : type.Name;
} }
private static void ProcessType(StringBuilder builder, Type type, DisplayNameOptions options) private static void ProcessType(StringBuilder builder, Type type, DisplayNameOptions options)

View File

@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0"> <Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp2.1;netcoreapp2.0;net462</TargetFrameworks> <TargetFrameworks>netcoreapp2.1;netcoreapp3.1;net462;net5.0</TargetFrameworks>
<Configuration>Release</Configuration> <Configuration>Release</Configuration>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\Ben.Demystifier\Ben.Demystifier.csproj" /> <ProjectReference Include="..\..\src\Ben.Demystifier\Ben.Demystifier.csproj" />
<PackageReference Include="BenchmarkDotNet" Version="0.10.12" /> <PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -2,11 +2,14 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using BenchmarkDotNet.Attributes; using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Jobs; using BenchmarkDotNet.Jobs;
namespace Ben.Demystifier.Benchmarks namespace Ben.Demystifier.Benchmarks
{ {
[ClrJob, CoreJob] [SimpleJob(RuntimeMoniker.Net48)]
[SimpleJob(RuntimeMoniker.NetCoreApp21)]
[SimpleJob(RuntimeMoniker.NetCoreApp31)]
[SimpleJob(RuntimeMoniker.NetCoreApp50)]
[Config(typeof(Config))] [Config(typeof(Config))]
public class ExceptionTests public class ExceptionTests
{ {

View File

@ -43,6 +43,6 @@ namespace Ben.Demystifier.Benchmarks
internal class Config : ManualConfig internal class Config : ManualConfig
{ {
public Config() => Add(new MemoryDiagnoser()); public Config() => AddDiagnoser(MemoryDiagnoser.Default);
} }
} }

View File

@ -37,14 +37,28 @@ namespace Ben.Demystifier.Test
var trace = string.Join("", stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries) var trace = string.Join("", stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
// Remove items that vary between test runners // Remove items that vary between test runners
.Where(s => .Where(s =>
s != " at Task Ben.Demystifier.Test.DynamicCompilation.DoesNotPreventStackTrace()+() => { }" && (s != " at Task Ben.Demystifier.Test.DynamicCompilation.DoesNotPreventStackTrace()+() => { }" &&
!s.Contains("System.Threading.Tasks.Task.WaitAll") !s.Contains("System.Threading.Tasks.Task.WaitAll"))
) )
.Skip(1) .Skip(1)
.ToArray()) .ToArray())
// Remove Full framework back arrow // Remove Full framework back arrow
.Replace("<---", ""); .Replace("<---", "");
#if NET5_0 || NETCOREAPP3_1
var expected = string.Join("", new[] {
" ---> System.ArgumentException: Value does not fall within the expected range.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw1()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }",
" --- End of inner exception stack trace ---",
" at void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()",
" ---> (Inner Exception #1) System.NullReferenceException: Object reference not set to an instance of an object.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw2()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }",
" ---> (Inner Exception #2) System.InvalidOperationException: Operation is not valid due to the current state of the object.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw3()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }"
});
#else
var expected = string.Join("", new[] { var expected = string.Join("", new[] {
" at async Task Ben.Demystifier.Test.AggregateException.Throw1()", " at async Task Ben.Demystifier.Test.AggregateException.Throw1()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }", " at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }",
@ -59,7 +73,7 @@ namespace Ben.Demystifier.Test
"---> (Inner Exception #2) System.InvalidOperationException: Operation is not valid due to the current state of the object.", "---> (Inner Exception #2) System.InvalidOperationException: Operation is not valid due to the current state of the object.",
" at async Task Ben.Demystifier.Test.AggregateException.Throw3()", " at async Task Ben.Demystifier.Test.AggregateException.Throw3()",
" at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }"}); " at async void Ben.Demystifier.Test.AggregateException.DemystifiesAggregateExceptions()+(?) => { }"});
#endif
Assert.Equal(expected, trace); Assert.Equal(expected, trace);
} }

View File

@ -1,16 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>netcoreapp2.1;netcoreapp2.0;net46</TargetFrameworks> <TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">netcoreapp2.1;netcoreapp3.1;net46;net5.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT'">netcoreapp2.1;netcoreapp3.1;net5.0</TargetFrameworks>
<SignAssembly>true</SignAssembly> <SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\..\src\Ben.Demystifier\key.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\..\src\Ben.Demystifier\key.snk</AssemblyOriginatorKeyFile>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="System.ValueTuple" Version="4.4.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.3.1" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -44,6 +44,7 @@ namespace Ben.Demystifier.Test
s != " at void System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, object state)" && s != " at void System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, object state)" &&
s != " at Task Ben.Demystifier.Test.DynamicCompilation.DoesNotPreventStackTrace()+() => { }" s != " at Task Ben.Demystifier.Test.DynamicCompilation.DoesNotPreventStackTrace()+() => { }"
) )
.Select(s => Regex.Replace(s, "lambda_method[0-9]+\\(", "lambda_method("))
.ToArray(); .ToArray();
Assert.Equal( Assert.Equal(

View File

@ -31,13 +31,24 @@ namespace Ben.Demystifier.Test
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace); stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
var trace = stackTrace.Split(new[]{Environment.NewLine}, StringSplitOptions.None); var trace = stackTrace.Split(new[]{Environment.NewLine}, StringSplitOptions.None);
#if NETCOREAPP3_1 || NET5_0
Assert.Equal( Assert.Equal(
new[] { new[] {
"System.Exception: Exception of type 'System.Exception' was thrown. ---> System.Exception: Exception of type 'System.Exception' was thrown.", "System.Exception: Exception of type 'System.Exception' was thrown.",
" ---> System.Exception: Exception of type 'System.Exception' was thrown.",
" at Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()+() => { }", " at Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()+() => { }",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()", " at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()",
" --- End of inner exception stack trace ---"}, " --- End of inner exception stack trace ---"},
trace); trace);
#else
Assert.Equal(
new[] {
"System.Exception: Exception of type 'System.Exception' was thrown. ---> System.Exception: Exception of type 'System.Exception' was thrown.",
" at Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()+() => { }",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()",
" --- End of inner exception stack trace ---"},
trace);
#endif
// Act // Act
try try
@ -54,6 +65,18 @@ namespace Ben.Demystifier.Test
stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace); stackTrace = LineEndingsHelper.RemoveLineEndings(stackTrace);
trace = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None); trace = stackTrace.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
#if NETCOREAPP3_1 || NET5_0
Assert.Equal(
new[] {
"System.Exception: Exception of type 'System.Exception' was thrown.",
" ---> System.Exception: Exception of type 'System.Exception' was thrown.",
" at Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()+() => { }",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()",
" --- End of inner exception stack trace ---",
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()"
},
trace);
#else
Assert.Equal( Assert.Equal(
new[] { new[] {
"System.Exception: Exception of type 'System.Exception' was thrown. ---> System.Exception: Exception of type 'System.Exception' was thrown.", "System.Exception: Exception of type 'System.Exception' was thrown. ---> System.Exception: Exception of type 'System.Exception' was thrown.",
@ -63,6 +86,7 @@ namespace Ben.Demystifier.Test
" at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()" " at async Task Ben.Demystifier.Test.NonThrownException.DoesNotPreventThrowStackTrace()"
}, },
trace); trace);
#endif
} }
[Fact] [Fact]

View File

@ -0,0 +1,29 @@
using System;
using System.Diagnostics;
using Xunit;
namespace Ben.Demystifier.Test
{
public class TypeNameTests
{
[Fact]
public void NestedGenericTypes()
{
try
{
Throw(new Generic<(int, string)>.Nested());
}
catch (Exception ex)
{
var text = ex.ToStringDemystified();
}
}
public void Throw(Generic<(int a, string b)>.Nested nested)
{
throw null;
}
}
public class Generic<T> { public struct Nested { } }
}

View File

@ -1,5 +1,5 @@
{ {
"version": "0.1.4", "version": "0.2.0",
"publicReleaseRefSpec": [ "publicReleaseRefSpec": [
"^refs/heads/master$", // we release out of master "^refs/heads/master$", // we release out of master
"^refs/heads/dev$", // we release out of develop "^refs/heads/dev$", // we release out of develop