Enabled Nullable Reference Types (#136)

This commit is contained in:
Bruno Garcia 2021-01-03 20:14:24 -05:00 committed by GitHub
parent 42b64441a1
commit d3195acac0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 97 additions and 93 deletions

View File

@ -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>

View File

@ -12,6 +12,7 @@
<IncludeSource>true</IncludeSource>
<DebugType>embedded</DebugType>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>

View File

@ -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)

View File

@ -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)

View File

@ -102,11 +102,12 @@ 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));
}

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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()

View File

@ -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));

View File

@ -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; }

View File

@ -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)

View File

@ -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("(");