Enabled Nullable Reference Types (#136)
This commit is contained in:
parent
42b64441a1
commit
d3195acac0
@ -1,10 +1,14 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<LangVersion>latest</LangVersion>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(TargetFramework)' != 'netstandard2.0' and !$(TargetFramework.StartsWith('netcoreapp2')) and !$(TargetFramework.StartsWith('net4'))">
|
||||
<DefineConstants>$(DefineConstants);HAS_ASYNC_ENUMERATOR</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nullable" Version="1.3.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
|
||||
<ContinuousIntegrationBuild>true</ContinuousIntegrationBuild>
|
||||
</PropertyGroup>
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
<IncludeSource>true</IncludeSource>
|
||||
<DebugType>embedded</DebugType>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@ -7,9 +7,9 @@ namespace System.Diagnostics
|
||||
{
|
||||
public class EnhancedStackFrame : StackFrame
|
||||
{
|
||||
private string _fileName;
|
||||
private int _lineNumber;
|
||||
private int _colNumber;
|
||||
private readonly string? _fileName;
|
||||
private readonly int _lineNumber;
|
||||
private readonly int _colNumber;
|
||||
|
||||
public StackFrame StackFrame { get; }
|
||||
|
||||
@ -21,7 +21,7 @@ namespace System.Diagnostics
|
||||
|
||||
public ResolvedMethod MethodInfo { get; }
|
||||
|
||||
internal EnhancedStackFrame(StackFrame stackFrame, ResolvedMethod methodInfo, string fileName, int lineNumber, int colNumber)
|
||||
internal EnhancedStackFrame(StackFrame stackFrame, ResolvedMethod methodInfo, string? fileName, int lineNumber, int colNumber)
|
||||
: base(fileName, lineNumber, colNumber)
|
||||
{
|
||||
StackFrame = stackFrame;
|
||||
@ -32,7 +32,7 @@ namespace System.Diagnostics
|
||||
_colNumber = colNumber;
|
||||
}
|
||||
|
||||
internal bool IsEquivalent(ResolvedMethod methodInfo, string fileName, int lineNumber, int colNumber)
|
||||
internal bool IsEquivalent(ResolvedMethod methodInfo, string? fileName, int lineNumber, int colNumber)
|
||||
{
|
||||
return _lineNumber == lineNumber &&
|
||||
_colNumber == colNumber &&
|
||||
@ -59,7 +59,7 @@ namespace System.Diagnostics
|
||||
/// This information is typically extracted from the debugging symbols for the executable.
|
||||
/// </summary>
|
||||
/// <returns>The file name, or null if the file name cannot be determined.</returns>
|
||||
public override string GetFileName() => _fileName;
|
||||
public override string? GetFileName() => _fileName;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the offset from the start of the Microsoft intermediate language (MSIL)
|
||||
|
||||
@ -44,8 +44,8 @@ namespace System.Diagnostics
|
||||
return frames;
|
||||
}
|
||||
|
||||
EnhancedStackFrame lastFrame = null;
|
||||
PortablePdbReader portablePdbReader = null;
|
||||
EnhancedStackFrame? lastFrame = null;
|
||||
PortablePdbReader? portablePdbReader = null;
|
||||
try
|
||||
{
|
||||
for (var i = 0; i < stackFrames.Length; i++)
|
||||
@ -70,6 +70,12 @@ namespace System.Diagnostics
|
||||
(portablePdbReader ??= new PortablePdbReader()).PopulateStackFrame(frame, method, frame.GetILOffset(), out fileName, out row, out column);
|
||||
}
|
||||
|
||||
if (method is null)
|
||||
{
|
||||
// Method can't be null
|
||||
continue;
|
||||
}
|
||||
|
||||
var resolvedMethod = GetMethodDisplayString(method);
|
||||
if (lastFrame?.IsEquivalent(resolvedMethod, fileName, row, column) ?? false)
|
||||
{
|
||||
@ -85,11 +91,7 @@ namespace System.Diagnostics
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (portablePdbReader is not null)
|
||||
{
|
||||
portablePdbReader.Dispose();
|
||||
}
|
||||
|
||||
portablePdbReader?.Dispose();
|
||||
}
|
||||
|
||||
return frames;
|
||||
@ -97,12 +99,6 @@ namespace System.Diagnostics
|
||||
|
||||
public static ResolvedMethod GetMethodDisplayString(MethodBase originMethod)
|
||||
{
|
||||
// Special case: no method available
|
||||
if (originMethod == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var method = originMethod;
|
||||
|
||||
var methodDisplayInfo = new ResolvedMethod
|
||||
@ -174,7 +170,7 @@ namespace System.Diagnostics
|
||||
if (value is Delegate d)
|
||||
{
|
||||
if (ReferenceEquals(d.Method, originMethod) &&
|
||||
d.Target.ToString() == originMethod.DeclaringType.ToString())
|
||||
d.Target.ToString() == originMethod.DeclaringType?.ToString())
|
||||
{
|
||||
methodDisplayInfo.Name = field.Name;
|
||||
methodDisplayInfo.IsLambda = false;
|
||||
@ -208,11 +204,10 @@ namespace System.Diagnostics
|
||||
}
|
||||
else if (mi.ReturnType != null)
|
||||
{
|
||||
methodDisplayInfo.ReturnParameter = new ResolvedParameter
|
||||
methodDisplayInfo.ReturnParameter = new ResolvedParameter(mi.ReturnType)
|
||||
{
|
||||
Prefix = "",
|
||||
Name = "",
|
||||
ResolvedType = mi.ReturnType,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -278,7 +273,7 @@ namespace System.Diagnostics
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryResolveGeneratedName(ref MethodBase method, out Type type, out string methodName, out string subMethodName, out GeneratedNameKind kind, out int? ordinal)
|
||||
private static bool TryResolveGeneratedName(ref MethodBase method, out Type? type, out string methodName, out string? subMethodName, out GeneratedNameKind kind, out int? ordinal)
|
||||
{
|
||||
kind = GeneratedNameKind.None;
|
||||
type = method.DeclaringType;
|
||||
@ -364,15 +359,18 @@ namespace System.Diagnostics
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TryResolveSourceMethod(IEnumerable<MethodBase> candidateMethods, GeneratedNameKind kind, string matchHint, ref MethodBase method, ref Type type, out int? ordinal)
|
||||
private static bool TryResolveSourceMethod(IEnumerable<MethodBase> candidateMethods, GeneratedNameKind kind, string? matchHint, ref MethodBase method, ref Type type, out int? ordinal)
|
||||
{
|
||||
ordinal = null;
|
||||
foreach (var candidateMethod in candidateMethods)
|
||||
{
|
||||
var methodBody = candidateMethod.GetMethodBody();
|
||||
if (candidateMethod.GetMethodBody() is not { } methodBody)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (kind == GeneratedNameKind.LambdaMethod)
|
||||
{
|
||||
foreach (var v in EnumerableIList.Create(methodBody?.LocalVariables))
|
||||
foreach (var v in EnumerableIList.Create(methodBody.LocalVariables))
|
||||
{
|
||||
if (v.LocalType == type)
|
||||
{
|
||||
@ -387,14 +385,13 @@ namespace System.Diagnostics
|
||||
|
||||
try
|
||||
{
|
||||
var rawIL = methodBody?.GetILAsByteArray();
|
||||
if (rawIL == null) continue;
|
||||
var reader = new ILReader(rawIL);
|
||||
var rawIl = methodBody.GetILAsByteArray();
|
||||
var reader = new ILReader(rawIl);
|
||||
while (reader.Read(candidateMethod))
|
||||
{
|
||||
if (reader.Operand is MethodBase mb)
|
||||
{
|
||||
if (method == mb || (matchHint != null && method.Name.Contains(matchHint)))
|
||||
if (method == mb || matchHint != null && method.Name.Contains(matchHint))
|
||||
{
|
||||
if (kind == GeneratedNameKind.LambdaMethod)
|
||||
{
|
||||
@ -462,7 +459,7 @@ namespace System.Diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
static string GetMatchHint(GeneratedNameKind kind, MethodBase method)
|
||||
static string? GetMatchHint(GeneratedNameKind kind, MethodBase method)
|
||||
{
|
||||
var methodName = method.Name;
|
||||
|
||||
@ -590,28 +587,25 @@ namespace System.Diagnostics
|
||||
}
|
||||
}
|
||||
|
||||
if (parameterType.IsByRef)
|
||||
if (parameterType.IsByRef && parameterType.GetElementType() is {} elementType)
|
||||
{
|
||||
parameterType = parameterType.GetElementType();
|
||||
parameterType = elementType;
|
||||
}
|
||||
|
||||
return new ResolvedParameter
|
||||
return new ResolvedParameter(parameterType)
|
||||
{
|
||||
Prefix = prefix,
|
||||
Name = parameter.Name,
|
||||
ResolvedType = parameterType,
|
||||
IsDynamicType = parameter.IsDefined(typeof(DynamicAttribute), false)
|
||||
};
|
||||
}
|
||||
|
||||
private static ResolvedParameter GetValueTupleParameter(IList<string> tupleNames, string prefix, string name, Type parameterType)
|
||||
{
|
||||
return new ValueTupleResolvedParameter
|
||||
return new ValueTupleResolvedParameter(parameterType, tupleNames)
|
||||
{
|
||||
TupleNames = tupleNames,
|
||||
Prefix = prefix,
|
||||
Name = name,
|
||||
ResolvedType = parameterType
|
||||
};
|
||||
}
|
||||
|
||||
@ -650,8 +644,6 @@ namespace System.Diagnostics
|
||||
|
||||
private static bool ShowInStackTrace(MethodBase method)
|
||||
{
|
||||
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)
|
||||
|
||||
@ -101,12 +101,13 @@ namespace System.Diagnostics
|
||||
|
||||
sb.Append(" at ");
|
||||
frame.MethodInfo.Append(sb);
|
||||
|
||||
var filePath = frame.GetFileName();
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
|
||||
if (frame.GetFileName() is {} fileName
|
||||
// IsNullOrEmpty alone wasn't enough to disable the null warning
|
||||
&& !string.IsNullOrEmpty(fileName))
|
||||
{
|
||||
sb.Append(" in ");
|
||||
sb.Append(TryGetFullPath(filePath));
|
||||
sb.Append(TryGetFullPath(fileName));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -24,7 +24,7 @@ namespace System.Collections.Generic.Enumerable
|
||||
}
|
||||
|
||||
public void Dispose() { }
|
||||
object IEnumerator.Current => Current;
|
||||
object? IEnumerator.Current => Current;
|
||||
public void Reset() => _index = -1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,7 @@ namespace System.Diagnostics.Internal
|
||||
|
||||
public OpCode OpCode { get; private set; }
|
||||
public int MetadataToken { get; private set; }
|
||||
public MemberInfo Operand { get; private set; }
|
||||
public MemberInfo? Operand { get; private set; }
|
||||
|
||||
public bool Read(MethodBase methodInfo)
|
||||
{
|
||||
@ -38,7 +38,7 @@ namespace System.Diagnostics.Internal
|
||||
return doubleByteOpCode[ReadByte()];
|
||||
}
|
||||
|
||||
MemberInfo ReadOperand(OpCode code, MethodBase methodInfo)
|
||||
MemberInfo? ReadOperand(OpCode code, MethodBase methodInfo)
|
||||
{
|
||||
MetadataToken = 0;
|
||||
int inlineLength;
|
||||
@ -46,12 +46,12 @@ namespace System.Diagnostics.Internal
|
||||
{
|
||||
case OperandType.InlineMethod:
|
||||
MetadataToken = ReadInt();
|
||||
Type[] methodArgs = null;
|
||||
Type[]? methodArgs = null;
|
||||
if (methodInfo.GetType() != typeof(ConstructorInfo) && !methodInfo.GetType().IsSubclassOf(typeof(ConstructorInfo)))
|
||||
{
|
||||
methodArgs = methodInfo.GetGenericArguments();
|
||||
}
|
||||
Type[] typeArgs = null;
|
||||
Type[]? typeArgs = null;
|
||||
if (methodInfo.DeclaringType != null)
|
||||
{
|
||||
typeArgs = methodInfo.DeclaringType.GetGenericArguments();
|
||||
|
||||
@ -68,13 +68,13 @@ namespace System.Diagnostics.Internal
|
||||
}
|
||||
}
|
||||
|
||||
private MetadataReader GetMetadataReader(string assemblyPath)
|
||||
private MetadataReader? GetMetadataReader(string assemblyPath)
|
||||
{
|
||||
if (!_cache.TryGetValue(assemblyPath, out var provider))
|
||||
{
|
||||
var pdbPath = GetPdbPath(assemblyPath);
|
||||
|
||||
if (!string.IsNullOrEmpty(pdbPath) && File.Exists(pdbPath) && IsPortable(pdbPath))
|
||||
if (!string.IsNullOrEmpty(pdbPath) && File.Exists(pdbPath) && IsPortable(pdbPath!))
|
||||
{
|
||||
var pdbStream = File.OpenRead(pdbPath);
|
||||
provider = MetadataReaderProvider.FromPortablePdbStream(pdbStream);
|
||||
@ -86,7 +86,7 @@ namespace System.Diagnostics.Internal
|
||||
return provider?.GetMetadataReader();
|
||||
}
|
||||
|
||||
private static string GetPdbPath(string assemblyPath)
|
||||
private static string? GetPdbPath(string assemblyPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(assemblyPath))
|
||||
{
|
||||
@ -97,16 +97,16 @@ namespace System.Diagnostics.Internal
|
||||
{
|
||||
var peStream = File.OpenRead(assemblyPath);
|
||||
|
||||
using (var peReader = new PEReader(peStream))
|
||||
using var peReader = new PEReader(peStream);
|
||||
foreach (var entry in peReader.ReadDebugDirectory())
|
||||
{
|
||||
foreach (var entry in peReader.ReadDebugDirectory())
|
||||
if (entry.Type == DebugDirectoryEntryType.CodeView)
|
||||
{
|
||||
if (entry.Type == DebugDirectoryEntryType.CodeView)
|
||||
{
|
||||
var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
|
||||
var peDirectory = Path.GetDirectoryName(assemblyPath);
|
||||
return Path.Combine(peDirectory, Path.GetFileName(codeViewData.Path));
|
||||
}
|
||||
var codeViewData = peReader.ReadCodeViewDebugDirectoryData(entry);
|
||||
var peDirectory = Path.GetDirectoryName(assemblyPath);
|
||||
return peDirectory is null
|
||||
? null
|
||||
: Path.Combine(peDirectory, Path.GetFileName(codeViewData.Path));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,13 +116,11 @@ namespace System.Diagnostics.Internal
|
||||
|
||||
private static bool IsPortable(string pdbPath)
|
||||
{
|
||||
using (var pdbStream = File.OpenRead(pdbPath))
|
||||
{
|
||||
return pdbStream.ReadByte() == 'B' &&
|
||||
pdbStream.ReadByte() == 'S' &&
|
||||
pdbStream.ReadByte() == 'J' &&
|
||||
pdbStream.ReadByte() == 'B';
|
||||
}
|
||||
using var pdbStream = File.OpenRead(pdbPath);
|
||||
return pdbStream.ReadByte() == 'B' &&
|
||||
pdbStream.ReadByte() == 'S' &&
|
||||
pdbStream.ReadByte() == 'J' &&
|
||||
pdbStream.ReadByte() == 'B';
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@ -12,7 +12,7 @@ namespace System.Diagnostics.Internal
|
||||
/// </summary>
|
||||
public static class ReflectionHelper
|
||||
{
|
||||
private static PropertyInfo tranformerNamesLazyPropertyInfo;
|
||||
private static PropertyInfo? tranformerNamesLazyPropertyInfo;
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the <paramref name="type"/> is a value tuple type.
|
||||
@ -43,15 +43,15 @@ namespace System.Diagnostics.Internal
|
||||
/// To avoid compile-time depencency hell with System.ValueTuple, this method uses reflection
|
||||
/// instead of casting the attribute to a specific type.
|
||||
/// </remarks>
|
||||
public static IList<string> GetTransformerNames(this Attribute attribute)
|
||||
public static IList<string>? GetTransformerNames(this Attribute attribute)
|
||||
{
|
||||
Debug.Assert(attribute.IsTupleElementNameAttribue());
|
||||
|
||||
var propertyInfo = GetTransformNamesPropertyInfo(attribute.GetType());
|
||||
return (IList<string>)propertyInfo.GetValue(attribute);
|
||||
return propertyInfo?.GetValue(attribute) as IList<string>;
|
||||
}
|
||||
|
||||
private static PropertyInfo GetTransformNamesPropertyInfo(Type attributeType)
|
||||
private static PropertyInfo? GetTransformNamesPropertyInfo(Type attributeType)
|
||||
{
|
||||
return LazyInitializer.EnsureInitialized(ref tranformerNamesLazyPropertyInfo,
|
||||
() => attributeType.GetProperty("TransformNames", BindingFlags.Instance | BindingFlags.Public));
|
||||
|
||||
@ -9,27 +9,27 @@ namespace System.Diagnostics
|
||||
{
|
||||
public class ResolvedMethod
|
||||
{
|
||||
public MethodBase MethodBase { get; set; }
|
||||
public MethodBase? MethodBase { get; set; }
|
||||
|
||||
public Type DeclaringType { get; set; }
|
||||
public Type? DeclaringType { get; set; }
|
||||
|
||||
public bool IsAsync { get; set; }
|
||||
|
||||
public bool IsLambda { get; set; }
|
||||
|
||||
public ResolvedParameter ReturnParameter { get; set; }
|
||||
public ResolvedParameter? ReturnParameter { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
public int? Ordinal { get; set; }
|
||||
|
||||
public string GenericArguments { get; set; }
|
||||
public string? GenericArguments { get; set; }
|
||||
|
||||
public Type[] ResolvedGenericArguments { get; set; }
|
||||
public Type[]? ResolvedGenericArguments { get; set; }
|
||||
|
||||
public MethodBase SubMethodBase { get; set; }
|
||||
public MethodBase? SubMethodBase { get; set; }
|
||||
|
||||
public string SubMethod { get; set; }
|
||||
public string? SubMethod { get; set; }
|
||||
|
||||
public EnumerableIList<ResolvedParameter> Parameters { get; set; }
|
||||
|
||||
|
||||
@ -7,13 +7,15 @@ namespace System.Diagnostics
|
||||
{
|
||||
public class ResolvedParameter
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string? Name { get; set; }
|
||||
|
||||
public Type ResolvedType { get; set; }
|
||||
|
||||
public string Prefix { get; set; }
|
||||
public string? Prefix { get; set; }
|
||||
public bool IsDynamicType { get; set; }
|
||||
|
||||
public ResolvedParameter(Type resolvedType) => ResolvedType = resolvedType;
|
||||
|
||||
public override string ToString() => Append(new StringBuilder()).ToString();
|
||||
|
||||
public StringBuilder Append(StringBuilder sb)
|
||||
|
||||
@ -9,25 +9,31 @@ namespace System.Diagnostics
|
||||
{
|
||||
public class ValueTupleResolvedParameter : ResolvedParameter
|
||||
{
|
||||
public IList<string> TupleNames { get; set; }
|
||||
public IList<string> TupleNames { get; }
|
||||
|
||||
public ValueTupleResolvedParameter(Type resolvedType, IList<string> tupleNames)
|
||||
: base(resolvedType)
|
||||
=> TupleNames = tupleNames;
|
||||
|
||||
protected override void AppendTypeName(StringBuilder sb)
|
||||
{
|
||||
if (ResolvedType.IsValueTuple())
|
||||
if (ResolvedType is not null)
|
||||
{
|
||||
AppendValueTupleParameterName(sb, ResolvedType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to unwrap the first generic argument first.
|
||||
sb.Append(TypeNameHelper.GetTypeNameForGenericType(ResolvedType));
|
||||
sb.Append("<");
|
||||
AppendValueTupleParameterName(sb, ResolvedType.GetGenericArguments()[0]);
|
||||
sb.Append(">");
|
||||
if (ResolvedType.IsValueTuple())
|
||||
{
|
||||
AppendValueTupleParameterName(sb, ResolvedType);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to unwrap the first generic argument first.
|
||||
sb.Append(TypeNameHelper.GetTypeNameForGenericType(ResolvedType));
|
||||
sb.Append("<");
|
||||
AppendValueTupleParameterName(sb, ResolvedType.GetGenericArguments()[0]);
|
||||
sb.Append(">");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void AppendValueTupleParameterName(StringBuilder sb, Type parameterType)
|
||||
{
|
||||
sb.Append("(");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user