C#: Enable nullability checks on Semmle.Extraction.CIL

This commit is contained in:
Tamas Vajk
2020-08-19 14:53:40 +02:00
parent d56a03389c
commit 9cdee63ed7
22 changed files with 286 additions and 179 deletions

View File

@@ -9,7 +9,7 @@ namespace Semmle.Extraction.CIL
/// </summary>
/// <typeparam name="SrcType">The type of the source.</typeparam>
/// <typeparam name="TargetType">The type of the generated object.</typeparam>
public class CachedFunction<SrcType, TargetType>
public class CachedFunction<SrcType, TargetType> where SrcType : notnull
{
readonly Func<SrcType, TargetType> generator;
readonly Dictionary<SrcType, TargetType> cache;

View File

@@ -14,13 +14,19 @@ namespace Semmle.Extraction.CIL
/// </summary>
partial class Context : IDisposable
{
public Extraction.Context cx;
readonly FileStream stream;
public readonly MetadataReader mdReader;
public readonly PEReader peReader;
public readonly string assemblyPath;
public Entities.Assembly assembly;
public PDB.IPdb pdb;
Entities.Assembly? assemblyNull;
public Extraction.Context cx { get; }
public MetadataReader mdReader { get; }
public PEReader peReader { get; }
public string assemblyPath { get; }
public Entities.Assembly assembly
{
get { return assemblyNull!; }
set { assemblyNull = value; }
}
public PDB.IPdb? pdb { get; }
public Context(Extraction.Context cx, string assemblyPath, bool extractPdbs)
{
@@ -105,7 +111,7 @@ namespace Semmle.Extraction.CIL
/// </summary>
/// <param name="handle">The handle of the method.</param>
/// <returns>The debugging information, or null if the information could not be located.</returns>
public PDB.IMethod GetMethodDebugInformation(MethodDefinitionHandle handle)
public PDB.IMethod? GetMethodDebugInformation(MethodDefinitionHandle handle)
{
return pdb == null ? null : pdb.GetMethod(handle.ToDebugInformationHandle());
}
@@ -125,7 +131,8 @@ namespace Semmle.Extraction.CIL
}
/// <summary>
/// The list of generic type parameters.
/// The list of generic type parameters, including type parameters of
/// containing types.
/// </summary>
public abstract IEnumerable<Entities.Type> TypeParameters { get; }

View File

@@ -47,9 +47,9 @@ namespace Semmle.Extraction.CIL.Entities
trapFile.Write(cx.assemblyPath.Replace("\\", "/"));
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return GetType() == obj.GetType() && Equals(file, ((Assembly)obj).file);
return GetType() == obj?.GetType() && Equals(file, ((Assembly)obj).file);
}
public override int GetHashCode() => 7 * file.GetHashCode();
@@ -63,7 +63,7 @@ namespace Semmle.Extraction.CIL.Entities
get
{
yield return file;
yield return Tuples.assemblies(this, file, FullName, assemblyName.Name, assemblyName.Version.ToString());
yield return Tuples.assemblies(this, file, FullName, assemblyName.Name ?? string.Empty, assemblyName.Version?.ToString() ?? string.Empty);
if (cx.pdb != null)
{
@@ -75,7 +75,7 @@ namespace Semmle.Extraction.CIL.Entities
foreach (var handle in cx.mdReader.TypeDefinitions)
{
IExtractionProduct product = null;
IExtractionProduct? product = null;
try
{
product = cx.Create(handle);
@@ -92,7 +92,7 @@ namespace Semmle.Extraction.CIL.Entities
foreach (var handle in cx.mdReader.MethodDefinitions)
{
IExtractionProduct product = null;
IExtractionProduct? product = null;
try
{
product = cx.Create(handle);

View File

@@ -27,7 +27,7 @@ namespace Semmle.Extraction.CIL.Entities
this.@object = @object;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Attribute attribute && handle.Equals(attribute.handle);
}
@@ -58,13 +58,15 @@ namespace Semmle.Extraction.CIL.Entities
for (int index = 0; index < decoded.FixedArguments.Length; ++index)
{
object value = decoded.FixedArguments[index].Value;
yield return Tuples.cil_attribute_positional_argument(this, index, value == null ? "null" : value.ToString());
var stringValue = value?.ToString();
yield return Tuples.cil_attribute_positional_argument(this, index, stringValue ?? "null");
}
foreach (var p in decoded.NamedArguments)
{
object value = p.Value;
yield return Tuples.cil_attribute_named_argument(this, p.Name, value == null ? "null" : value.ToString());
var stringValue = value?.ToString();
yield return Tuples.cil_attribute_named_argument(this, p.Name, stringValue ?? "null");
}
}
}

View File

@@ -36,7 +36,7 @@ namespace Semmle.Extraction.CIL.Entities
public override string IdSuffix => ";cil-event";
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Event e && handle.Equals(e.handle);
}

View File

@@ -30,7 +30,7 @@ namespace Semmle.Extraction.CIL.Entities
{
get
{
IInstruction try_start, try_end, handler_start;
IInstruction? try_start, try_end, handler_start;
if (!jump_table.TryGetValue(r.TryOffset, out try_start))
throw new InternalError("Failed to retrieve handler");
@@ -44,7 +44,7 @@ namespace Semmle.Extraction.CIL.Entities
if (r.FilterOffset != -1)
{
IInstruction filter_start;
IInstruction? filter_start;
if (!jump_table.TryGetValue(r.FilterOffset, out filter_start))
throw new InternalError("ExceptionRegion filter clause");

View File

@@ -91,7 +91,7 @@ namespace Semmle.Extraction.CIL.Entities
fd = cx.mdReader.GetFieldDefinition(handle);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is DefinitionField field && handle.Equals(field.handle);
}
@@ -153,7 +153,7 @@ namespace Semmle.Extraction.CIL.Entities
declType = (Type)cx.CreateGeneric(gc, mr.Parent);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is MemberReferenceField field && Handle.Equals(field.Handle);
}

View File

@@ -25,9 +25,9 @@ namespace Semmle.Extraction.CIL.Entities
trapFile.Write(Semmle.Extraction.Entities.File.PathAsDatabaseId(path));
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return GetType() == obj.GetType() && path == ((File)obj).path;
return GetType() == obj?.GetType() && path == ((File)obj).path;
}
public override int GetHashCode() => 11 * path.GetHashCode();
@@ -36,7 +36,11 @@ namespace Semmle.Extraction.CIL.Entities
{
get
{
var parent = cx.CreateFolder(System.IO.Path.GetDirectoryName(path));
var directoryName = System.IO.Path.GetDirectoryName(path);
if (directoryName == null)
throw new InternalError($"Directory name for path '{path}' is null.");
var parent = cx.CreateFolder(directoryName);
yield return parent;
yield return Tuples.containerparent(parent, this);
yield return Tuples.files(this, path, System.IO.Path.GetFileNameWithoutExtension(path), System.IO.Path.GetExtension(path).Substring(1));

View File

@@ -41,7 +41,7 @@ namespace Semmle.Extraction.CIL.Entities
}
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Folder folder && path == folder.path;
}

View File

@@ -365,6 +365,11 @@ namespace Semmle.Extraction.CIL.Entities
{
int offset = Offset;
if (Method.Implementation is null)
{
yield break;
}
yield return Tuples.cil_instruction(this, (int)OpCode, Index, Method.Implementation);
switch (PayloadType)
@@ -414,11 +419,17 @@ namespace Semmle.Extraction.CIL.Entities
break;
case Payload.Arg8:
case Payload.Arg16:
yield return Tuples.cil_access(this, Method.Parameters[(int)UnsignedPayloadValue]);
if (!(Method.Parameters is null))
{
yield return Tuples.cil_access(this, Method.Parameters[(int)UnsignedPayloadValue]);
}
break;
case Payload.Local8:
case Payload.Local16:
yield return Tuples.cil_access(this, Method.LocalVariables[(int)UnsignedPayloadValue]);
if (!(Method.LocalVariables is null))
{
yield return Tuples.cil_access(this, Method.LocalVariables[(int)UnsignedPayloadValue]);
}
break;
case Payload.None:
case Payload.Target8:
@@ -439,7 +450,7 @@ namespace Semmle.Extraction.CIL.Entities
public IEnumerable<IExtractionProduct> JumpContents(Dictionary<int, IInstruction> jump_table)
{
int target;
IInstruction inst;
IInstruction? inst;
switch (PayloadType)
{

View File

@@ -23,25 +23,29 @@ namespace Semmle.Extraction.CIL.Entities
/// </summary>
abstract class Method : TypeContainer, IMethod
{
protected MethodTypeParameter[]? genericParams;
protected GenericContext gc;
protected MethodSignature<ITypeSignature> signature;
protected Method(GenericContext gc) : base(gc.cx)
{
this.gc = gc;
}
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(declaringType.TypeParameters);
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(DeclaringType.TypeParameters);
public override IEnumerable<Type> MethodParameters =>
genericParams == null ? gc.MethodParameters : gc.MethodParameters.Concat(genericParams);
public int GenericParameterCount => signature.GenericParameterCount;
public virtual Method SourceDeclaration => this;
public virtual Method? SourceDeclaration => this;
public abstract Type DeclaringType { get; }
public abstract string Name { get; }
public virtual IList<LocalVariable> LocalVariables => throw new NotImplementedException();
public IList<Parameter> Parameters { get; private set; }
public virtual IList<LocalVariable>? LocalVariables => throw new NotImplementedException();
public IList<Parameter>? Parameters { get; private set; }
public override void WriteId(TextWriter trapFile) => WriteMethodId(trapFile, DeclaringType, NameLabel);
@@ -70,12 +74,6 @@ namespace Semmle.Extraction.CIL.Entities
trapFile.Write(')');
}
protected MethodTypeParameter[] genericParams;
protected Type declaringType;
protected GenericContext gc;
protected MethodSignature<ITypeSignature> signature;
protected string name;
public override string IdSuffix => ";cil-method";
protected void PopulateParameters(IEnumerable<Type> parameterTypes)
@@ -145,13 +143,15 @@ namespace Semmle.Extraction.CIL.Entities
{
readonly Handle handle;
readonly MethodDefinition md;
readonly PDB.IMethod methodDebugInformation;
readonly PDB.IMethod? methodDebugInformation;
readonly Type declaringType;
LocalVariable[] locals;
string name;
LocalVariable[]? locals;
public MethodImplementation Implementation { get; private set; }
public MethodImplementation? Implementation { get; private set; }
public override IList<LocalVariable> LocalVariables => locals;
public override IList<LocalVariable>? LocalVariables => locals;
public DefinitionMethod(GenericContext gc, MethodDefinitionHandle handle) : base(gc)
{
@@ -167,7 +167,7 @@ namespace Semmle.Extraction.CIL.Entities
methodDebugInformation = cx.GetMethodDebugInformation(handle);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is DefinitionMethod method && handle.Equals(method.handle);
}
@@ -208,7 +208,7 @@ namespace Semmle.Extraction.CIL.Entities
PopulateParameters(typeSignature.ParameterTypes);
foreach (var c in Parameters)
foreach (var c in Parameters!)
yield return c;
foreach (var c in PopulateFlags)
@@ -315,8 +315,8 @@ namespace Semmle.Extraction.CIL.Entities
// The sequence point gives the location of each instruction.
// The location of an instruction is given by the sequence point *after* the
// instruction.
IEnumerator<PDB.SequencePoint> nextSequencePoint = null;
PdbSourceLocation instructionLocation = null;
IEnumerator<PDB.SequencePoint>? nextSequencePoint = null;
PdbSourceLocation? instructionLocation = null;
if (methodDebugInformation != null)
{
@@ -401,9 +401,9 @@ namespace Semmle.Extraction.CIL.Entities
{
readonly MemberReferenceHandle handle;
readonly MemberReference mr;
readonly Type declType;
readonly Type declaringType;
readonly GenericContext parent;
readonly Method sourceDeclaration;
readonly Method? sourceDeclaration;
public MemberReferenceMethod(GenericContext gc, MemberReferenceHandle handle) : base(gc)
{
@@ -416,22 +416,24 @@ namespace Semmle.Extraction.CIL.Entities
parent = (GenericContext)cx.CreateGeneric(gc, mr.Parent);
var parentMethod = parent as Method;
nameLabel = cx.GetString(mr.Name);
declType = parentMethod == null ? parent as Type : parentMethod.DeclaringType;
var declType = parentMethod == null ? parent as Type : parentMethod.DeclaringType;
if (declType is null)
throw new InternalError("Parent context of method is not a type");
var typeSourceDeclaration = declType.SourceDeclaration;
sourceDeclaration = typeSourceDeclaration == declType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
declaringType = declType;
nameLabel = cx.GetString(mr.Name);
var typeSourceDeclaration = declaringType.SourceDeclaration;
sourceDeclaration = typeSourceDeclaration == declaringType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
}
private readonly string nameLabel;
public override string NameLabel => nameLabel;
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is MemberReferenceMethod method && handle.Equals(method.handle);
}
@@ -441,11 +443,11 @@ namespace Semmle.Extraction.CIL.Entities
return handle.GetHashCode();
}
public override Method SourceDeclaration => sourceDeclaration;
public override Method? SourceDeclaration => sourceDeclaration;
public override bool IsStatic => !signature.Header.IsInstance;
public override Type DeclaringType => declType;
public override Type DeclaringType => declaringType;
public override string Name => cx.ShortName(mr.Name);
@@ -465,7 +467,7 @@ namespace Semmle.Extraction.CIL.Entities
var typeSignature = mr.DecodeMethodSignature(cx.TypeSignatureDecoder, this);
PopulateParameters(typeSignature.ParameterTypes);
foreach (var p in Parameters) yield return p;
foreach (var p in Parameters!) yield return p;
foreach (var f in PopulateFlags) yield return f;
@@ -486,6 +488,7 @@ namespace Semmle.Extraction.CIL.Entities
readonly MethodSpecification ms;
readonly Method unboundMethod;
readonly ImmutableArray<Type> typeParams;
readonly Type declaringType;
public MethodSpecificationMethod(GenericContext gc, MethodSpecificationHandle handle) : base(gc)
{
@@ -501,7 +504,7 @@ namespace Semmle.Extraction.CIL.Entities
unboundMethod.WriteId(trapFile);
trapFile.Write('<');
int index = 0;
foreach(var param in typeParams)
foreach (var param in typeParams)
{
trapFile.WriteSeparator(",", ref index);
trapFile.WriteSubId(param);
@@ -511,7 +514,7 @@ namespace Semmle.Extraction.CIL.Entities
public override string NameLabel => throw new NotImplementedException();
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is MethodSpecificationMethod method && handle.Equals(method.handle) && typeParams.SequenceEqual(method.typeParams);
}
@@ -548,7 +551,7 @@ namespace Semmle.Extraction.CIL.Entities
}
PopulateParameters(constructedTypeSignature.ParameterTypes);
foreach (var p in Parameters)
foreach (var p in Parameters!)
yield return p;
foreach (var f in PopulateFlags)

View File

@@ -17,7 +17,7 @@ namespace Semmle.Extraction.CIL.Entities
/// </summary>
public sealed class Namespace : TypeContainer, INamespace
{
public Namespace ParentNamespace;
public Namespace? ParentNamespace;
public readonly string Name;
public bool IsGlobalNamespace => ParentNamespace == null;
@@ -35,7 +35,7 @@ namespace Semmle.Extraction.CIL.Entities
trapFile.Write(Name);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj is Namespace ns && Name == ns.Name)
{
@@ -63,7 +63,7 @@ namespace Semmle.Extraction.CIL.Entities
return i == -1 ? fqn : fqn.Substring(i + 1);
}
static Namespace createParentNamespace(Context cx, string fqn)
static Namespace? createParentNamespace(Context cx, string fqn)
{
if (fqn == "") return null;
var i = fqn.LastIndexOf('.');
@@ -74,7 +74,7 @@ namespace Semmle.Extraction.CIL.Entities
{
}
public Namespace(Context cx, string name, Namespace parent) : base(cx)
public Namespace(Context cx, string name, Namespace? parent) : base(cx)
{
Name = name;
ParentNamespace = parent;
@@ -86,7 +86,7 @@ namespace Semmle.Extraction.CIL.Entities
{
yield return Tuples.namespaces(this, Name);
if (!IsGlobalNamespace)
yield return Tuples.parent_namespace(this, ParentNamespace);
yield return Tuples.parent_namespace(this, ParentNamespace!);
}
}
}

View File

@@ -33,7 +33,7 @@ namespace Semmle.Extraction.CIL.Entities
trapFile.Write(index);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Parameter param && method.Equals(param.method) && index == param.index;
}

View File

@@ -48,7 +48,7 @@ namespace Semmle.Extraction.CIL.Entities
trapFile.Write(")");
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Property property && Equals(handle, property.handle);
}

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CIL.Entities
trapFile.Write(location.EndColumn);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is PdbSourceLocation l && location.Equals(l.location);
}

View File

@@ -8,6 +8,7 @@ using System.Reflection;
using Semmle.Util;
using System.IO;
using System.Text;
using System.Diagnostics.CodeAnalysis;
namespace Semmle.Extraction.CIL.Entities
{
@@ -103,7 +104,7 @@ namespace Semmle.Extraction.CIL.Entities
/// shortcut to comparing the signature bytes since handles are unique.
/// </param>
/// <returns>The method, or 'null' if not found or not supported.</returns>
internal virtual Method LookupMethod(StringHandle methodName, BlobHandle signature)
internal virtual Method? LookupMethod(StringHandle methodName, BlobHandle signature)
{
return null;
}
@@ -160,7 +161,7 @@ namespace Semmle.Extraction.CIL.Entities
get;
}
public virtual TypeContainer Parent => (TypeContainer)ContainingType ?? Namespace;
public virtual TypeContainer Parent => (TypeContainer?)ContainingType ?? Namespace!;
public override IEnumerable<IExtractionProduct> Contents
{
@@ -177,9 +178,9 @@ namespace Semmle.Extraction.CIL.Entities
public abstract string Name { get; }
public abstract Namespace Namespace { get; }
public abstract Namespace? Namespace { get; }
public abstract Type ContainingType { get; }
public abstract Type? ContainingType { get; }
public abstract Type Construct(IEnumerable<Type> typeArguments);
@@ -233,7 +234,7 @@ namespace Semmle.Extraction.CIL.Entities
/// </summary>
/// <param name="t">The resulting primitive type, or null.</param>
/// <returns>True if this type is a primitive type.</returns>
public bool TryGetPrimitiveType(out PrimitiveType t)
public bool TryGetPrimitiveType([NotNullWhen(true)] out PrimitiveType? t)
{
if (TryGetPrimitiveTypeCode(out var code))
{
@@ -249,7 +250,7 @@ namespace Semmle.Extraction.CIL.Entities
private bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code)
{
if (ContainingType == null && Namespace.Name == cx.SystemNamespace.Name)
if (ContainingType == null && Namespace?.Name == cx.SystemNamespace.Name)
{
switch (Name)
{
@@ -341,7 +342,7 @@ namespace Semmle.Extraction.CIL.Entities
typeParams = new Lazy<IEnumerable<TypeTypeParameter>>(MakeTypeParameters);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is TypeDefinitionType t && handle.Equals(t.handle);
}
@@ -390,9 +391,9 @@ namespace Semmle.Extraction.CIL.Entities
public override Namespace Namespace => cx.Create(td.NamespaceDefinition);
readonly Type declType;
readonly Type? declType;
public override Type ContainingType => declType;
public override Type? ContainingType => declType;
public override int ThisTypeParameters
{
@@ -562,18 +563,14 @@ namespace Semmle.Extraction.CIL.Entities
readonly TypeReference tr;
readonly Lazy<TypeTypeParameter[]> typeParams;
public TypeReferenceType(Context cx, TypeReferenceHandle handle) : this(cx, handle, cx.mdReader.GetTypeReference(handle))
{
typeParams = new Lazy<TypeTypeParameter[]>(MakeTypeParameters);
}
public TypeReferenceType(Context cx, TypeReferenceHandle handle, TypeReference tr) : base(cx)
public TypeReferenceType(Context cx, TypeReferenceHandle handle) : base(cx)
{
this.typeParams = new Lazy<TypeTypeParameter[]>(MakeTypeParameters);
this.handle = handle;
this.tr = tr;
this.tr = cx.mdReader.GetTypeReference(handle);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is TypeReferenceType t && handle.Equals(t.handle);
}
@@ -637,7 +634,7 @@ namespace Semmle.Extraction.CIL.Entities
}
}
public override Type ContainingType
public override Type? ContainingType
{
get
{
@@ -654,7 +651,7 @@ namespace Semmle.Extraction.CIL.Entities
switch (tr.ResolutionScope.Kind)
{
case HandleKind.TypeReference:
ContainingType.WriteAssemblyPrefix(trapFile);
ContainingType!.WriteAssemblyPrefix(trapFile);
break;
case HandleKind.AssemblyReference:
var assemblyDef = cx.mdReader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope);
@@ -684,7 +681,7 @@ namespace Semmle.Extraction.CIL.Entities
var ct = ContainingType;
if (ct != null)
{
ContainingType.GetId(trapFile, inContext);
ct.GetId(trapFile, inContext);
}
else
{
@@ -719,9 +716,11 @@ namespace Semmle.Extraction.CIL.Entities
public sealed class ConstructedType : Type
{
readonly Type unboundGenericType;
readonly Type[] thisTypeArguments;
public override IEnumerable<Type> ThisTypeArguments => thisTypeArguments;
// Either null or notEmpty
readonly Type[]? thisTypeArguments;
public override IEnumerable<Type> ThisTypeArguments => thisTypeArguments.EnumerateNull();
public override IEnumerable<Type> ThisGenericArguments => thisTypeArguments.EnumerateNull();
@@ -751,7 +750,6 @@ namespace Semmle.Extraction.CIL.Entities
unboundGenericType = unboundType;
var thisParams = unboundType.ThisTypeParameters;
var parentParams = suppliedArgs - thisParams;
if (typeArguments.Count() == thisParams)
{
@@ -760,18 +758,21 @@ namespace Semmle.Extraction.CIL.Entities
}
else if (thisParams == 0)
{
containingType = unboundType.ContainingType.Construct(typeArguments);
// all type arguments belong to containing type
containingType = unboundType.ContainingType!.Construct(typeArguments);
}
else
{
containingType = unboundType.ContainingType.Construct(typeArguments.Take(parentParams));
// some type arguments belong to containing type
var parentParams = suppliedArgs - thisParams;
containingType = unboundType.ContainingType!.Construct(typeArguments.Take(parentParams));
thisTypeArguments = typeArguments.Skip(parentParams).ToArray();
}
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if(obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType))
if (obj is ConstructedType t && Equals(unboundGenericType, t.unboundGenericType) && Equals(containingType, t.containingType))
{
if (thisTypeArguments is null) return t.thisTypeArguments is null;
if (!(t.thisTypeArguments is null)) return thisTypeArguments.SequenceEqual(t.thisTypeArguments);
@@ -788,12 +789,12 @@ namespace Semmle.Extraction.CIL.Entities
return h;
}
readonly Type containingType;
public override Type ContainingType => containingType;
readonly Type? containingType;
public override Type? ContainingType => containingType;
public override string Name => unboundGenericType.Name;
public override Namespace Namespace => unboundGenericType.Namespace;
public override Namespace Namespace => unboundGenericType.Namespace!;
public override int ThisTypeParameters => thisTypeArguments == null ? 0 : thisTypeArguments.Length;
@@ -851,7 +852,7 @@ namespace Semmle.Extraction.CIL.Entities
typeCode = tc;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is PrimitiveType pt && typeCode == pt.typeCode;
}
@@ -871,7 +872,7 @@ namespace Semmle.Extraction.CIL.Entities
public override Namespace Namespace => cx.SystemNamespace;
public override Type ContainingType => null;
public override Type? ContainingType => null;
public override int ThisTypeParameters => 0;
@@ -894,19 +895,17 @@ namespace Semmle.Extraction.CIL.Entities
readonly Type elementType;
readonly int rank;
public ArrayType(Context cx, Type element, ArrayShape shape) : base(cx)
public ArrayType(Context cx, Type elementType, int rank) : base(cx)
{
rank = shape.Rank;
elementType = element;
this.rank = rank;
this.elementType = elementType;
}
public ArrayType(Context cx, Type element) : base(cx)
public ArrayType(Context cx, Type elementType) : this(cx, elementType, 1)
{
rank = 1;
elementType = element;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is ArrayType array && elementType.Equals(array.elementType) && rank == array.rank;
}
@@ -929,7 +928,7 @@ namespace Semmle.Extraction.CIL.Entities
public override Namespace Namespace => cx.SystemNamespace;
public override Type ContainingType => null;
public override Type? ContainingType => null;
public override int ThisTypeParameters => elementType.ThisTypeParameters;
@@ -972,9 +971,9 @@ namespace Semmle.Extraction.CIL.Entities
this.gc = gc;
}
public override Namespace Namespace => null;
public override Namespace? Namespace => null;
public override Type ContainingType => null;
public override Type? ContainingType => null;
public override int ThisTypeParameters => 0;
@@ -1034,7 +1033,7 @@ namespace Semmle.Extraction.CIL.Entities
this.index = index;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is MethodTypeParameter tp && method.Equals(tp.method) && index == tp.index;
}
@@ -1072,7 +1071,7 @@ namespace Semmle.Extraction.CIL.Entities
type = t;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is TypeTypeParameter tp && type.Equals(tp.type) && index == tp.index;
}
@@ -1089,7 +1088,7 @@ namespace Semmle.Extraction.CIL.Entities
trapFile.Write(index);
}
public override TypeContainer Parent => type ?? gc as TypeContainer;
public override TypeContainer Parent => type;
public override string Name => "!" + index;
public override IEnumerable<Type> TypeParameters => Enumerable.Empty<Type>();
@@ -1119,7 +1118,7 @@ namespace Semmle.Extraction.CIL.Entities
this.pointee = pointee;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is PointerType pt && pointee.Equals(pt.pointee);
}
@@ -1138,9 +1137,9 @@ namespace Semmle.Extraction.CIL.Entities
public override string Name => pointee.Name + "*";
public override Namespace Namespace => pointee.Namespace;
public override Namespace? Namespace => pointee.Namespace;
public override Type ContainingType => pointee.ContainingType;
public override Type? ContainingType => pointee.ContainingType;
public override TypeContainer Parent => pointee.Parent;
@@ -1180,7 +1179,7 @@ namespace Semmle.Extraction.CIL.Entities
public override Namespace Namespace => cx.GlobalNamespace;
public override Type ContainingType => null;
public override Type? ContainingType => null;
public override int ThisTypeParameters => 0;
@@ -1202,13 +1201,20 @@ namespace Semmle.Extraction.CIL.Entities
{
struct Array : ITypeSignature
{
public ITypeSignature elementType;
public ArrayShape shape;
private readonly ITypeSignature elementType;
private readonly ArrayShape shape;
public Array(ITypeSignature elementType, ArrayShape shape) : this()
{
this.elementType = elementType;
this.shape = shape;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
elementType.WriteId(trapFile, gc);
trapFile.Write('[');
for (int i=1; i<shape.Rank; ++i)
for (int i = 1; i < shape.Rank; ++i)
trapFile.Write(',');
trapFile.Write(']');
}
@@ -1216,7 +1222,12 @@ namespace Semmle.Extraction.CIL.Entities
struct ByRef : ITypeSignature
{
public ITypeSignature elementType;
private readonly ITypeSignature elementType;
public ByRef(ITypeSignature elementType)
{
this.elementType = elementType;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
@@ -1227,7 +1238,12 @@ namespace Semmle.Extraction.CIL.Entities
struct FnPtr : ITypeSignature
{
public MethodSignature<ITypeSignature> signature;
private readonly MethodSignature<ITypeSignature> signature;
public FnPtr(MethodSignature<ITypeSignature> signature)
{
this.signature = signature;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
@@ -1236,25 +1252,32 @@ namespace Semmle.Extraction.CIL.Entities
}
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetArrayType(ITypeSignature elementType, ArrayShape shape) =>
new Array { elementType = elementType, shape = shape };
new Array(elementType, shape);
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetByReferenceType(ITypeSignature elementType) =>
new ByRef { elementType = elementType };
new ByRef(elementType);
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetFunctionPointerType(MethodSignature<ITypeSignature> signature) =>
new FnPtr { signature = signature };
new FnPtr(signature);
class Instantiation : ITypeSignature
{
public ITypeSignature genericType;
public ImmutableArray<ITypeSignature> typeArguments;
private readonly ITypeSignature genericType;
private readonly ImmutableArray<ITypeSignature> typeArguments;
public Instantiation(ITypeSignature genericType, ImmutableArray<ITypeSignature> typeArguments)
{
this.genericType = genericType;
this.typeArguments = typeArguments;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
genericType.WriteId(trapFile, gc);
trapFile.Write('<');
int index = 0;
foreach(var arg in typeArguments)
foreach (var arg in typeArguments)
{
trapFile.WriteSeparator(",", ref index);
arg.WriteId(trapFile, gc);
@@ -1264,12 +1287,18 @@ namespace Semmle.Extraction.CIL.Entities
}
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetGenericInstantiation(ITypeSignature genericType, ImmutableArray<ITypeSignature> typeArguments) =>
new Instantiation { genericType = genericType, typeArguments = typeArguments };
new Instantiation(genericType, typeArguments);
class GenericMethodParameter : ITypeSignature
{
public object innerGc;
public int index;
private readonly object innerGc;
private readonly int index;
public GenericMethodParameter(object innerGc, int index)
{
this.innerGc = innerGc;
this.index = index;
}
public void WriteId(TextWriter trapFile, GenericContext outerGc)
{
@@ -1284,7 +1313,12 @@ namespace Semmle.Extraction.CIL.Entities
class GenericTypeParameter : ITypeSignature
{
public int index;
private readonly int index;
public GenericTypeParameter(int index)
{
this.index = index;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
@@ -1294,16 +1328,23 @@ namespace Semmle.Extraction.CIL.Entities
}
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetGenericMethodParameter(object genericContext, int index) =>
new GenericMethodParameter { innerGc = genericContext, index = index };
new GenericMethodParameter(genericContext, index);
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetGenericTypeParameter(object genericContext, int index) =>
new GenericTypeParameter { index = index };
new GenericTypeParameter(index);
class Modified : ITypeSignature
{
public ITypeSignature modifier;
public ITypeSignature unmodifiedType;
public bool isRequired;
private readonly ITypeSignature modifier;
private readonly ITypeSignature unmodifiedType;
private readonly bool isRequired;
public Modified(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired)
{
this.modifier = modifier;
this.unmodifiedType = unmodifiedType;
this.isRequired = isRequired;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
@@ -1313,12 +1354,17 @@ namespace Semmle.Extraction.CIL.Entities
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetModifiedType(ITypeSignature modifier, ITypeSignature unmodifiedType, bool isRequired)
{
return new Modified { modifier = modifier, unmodifiedType = unmodifiedType, isRequired = isRequired };
return new Modified(modifier, unmodifiedType, isRequired);
}
class Pinned : ITypeSignature
{
public ITypeSignature elementType;
private readonly ITypeSignature elementType;
public Pinned(ITypeSignature elementType)
{
this.elementType = elementType;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
@@ -1329,12 +1375,17 @@ namespace Semmle.Extraction.CIL.Entities
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetPinnedType(ITypeSignature elementType)
{
return new Pinned { elementType = elementType };
return new Pinned(elementType);
}
class PointerType : ITypeSignature
{
public ITypeSignature elementType;
private readonly ITypeSignature elementType;
public PointerType(ITypeSignature elementType)
{
this.elementType = elementType;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
@@ -1345,12 +1396,17 @@ namespace Semmle.Extraction.CIL.Entities
ITypeSignature IConstructedTypeProvider<ITypeSignature>.GetPointerType(ITypeSignature elementType)
{
return new PointerType { elementType = elementType };
return new PointerType(elementType);
}
class Primitive : ITypeSignature
{
public PrimitiveTypeCode typeCode;
private readonly PrimitiveTypeCode typeCode;
public Primitive(PrimitiveTypeCode typeCode)
{
this.typeCode = typeCode;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
@@ -1360,12 +1416,18 @@ namespace Semmle.Extraction.CIL.Entities
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetPrimitiveType(PrimitiveTypeCode typeCode)
{
return new Primitive { typeCode = typeCode };
return new Primitive(typeCode);
}
class SzArrayType : ITypeSignature
{
public ITypeSignature elementType;
private readonly ITypeSignature elementType;
public SzArrayType(ITypeSignature elementType)
{
this.elementType = elementType;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
elementType.WriteId(trapFile, gc);
@@ -1375,41 +1437,53 @@ namespace Semmle.Extraction.CIL.Entities
ITypeSignature ISZArrayTypeProvider<ITypeSignature>.GetSZArrayType(ITypeSignature elementType)
{
return new SzArrayType { elementType = elementType };
return new SzArrayType(elementType);
}
class TypeDefinition : ITypeSignature
{
public TypeDefinitionHandle handle;
public byte rawTypeKind;
Type type;
private readonly TypeDefinitionHandle handle;
private readonly byte rawTypeKind;
public TypeDefinition(TypeDefinitionHandle handle, byte rawTypeKind)
{
this.handle = handle;
this.rawTypeKind = rawTypeKind;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
type = (Type)gc.cx.Create(handle);
var type = (Type)gc.cx.Create(handle);
type.WriteId(trapFile);
}
}
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetTypeFromDefinition(MetadataReader reader, TypeDefinitionHandle handle, byte rawTypeKind)
{
return new TypeDefinition { handle = handle, rawTypeKind = rawTypeKind };
return new TypeDefinition(handle, rawTypeKind);
}
class TypeReference : ITypeSignature
{
public TypeReferenceHandle handle;
public byte rawTypeKind; // struct/class (not used)
Type type;
private readonly TypeReferenceHandle handle;
private readonly byte rawTypeKind; // struct/class (not used)
public TypeReference(TypeReferenceHandle handle, byte rawTypeKind)
{
this.handle = handle;
this.rawTypeKind = rawTypeKind;
}
public void WriteId(TextWriter trapFile, GenericContext gc)
{
type = (Type)gc.cx.Create(handle);
var type = (Type)gc.cx.Create(handle);
type.WriteId(trapFile);
}
}
ITypeSignature ISimpleTypeProvider<ITypeSignature>.GetTypeFromReference(MetadataReader reader, TypeReferenceHandle handle, byte rawTypeKind)
{
return new TypeReference { handle = handle, rawTypeKind = rawTypeKind };
return new TypeReference(handle, rawTypeKind);
}
ITypeSignature ISignatureTypeProvider<ITypeSignature, object>.GetTypeFromSpecification(MetadataReader reader, object genericContext, TypeSpecificationHandle handle, byte rawTypeKind)
@@ -1433,7 +1507,7 @@ namespace Semmle.Extraction.CIL.Entities
}
Type IConstructedTypeProvider<Type>.GetArrayType(Type elementType, ArrayShape shape) =>
cx.Populate(new ArrayType(cx, elementType, shape));
cx.Populate(new ArrayType(cx, elementType, shape.Rank));
Type IConstructedTypeProvider<Type>.GetByReferenceType(Type elementType) =>
elementType; // ??

View File

@@ -41,7 +41,7 @@ namespace Semmle.Extraction.CIL
e.WriteId(writer);
var id = writer.ToString();
if (debugLabels.TryGetValue(id, out IExtractedEntity previousEntity))
if (debugLabels.TryGetValue(id, out IExtractedEntity? previousEntity))
{
cx.Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning));
}

View File

@@ -25,7 +25,7 @@ namespace Semmle.Extraction.PDB
public string Path { get; private set; }
public string Contents => File.Exists(Path) ? File.ReadAllText(Path, System.Text.Encoding.Default) : null;
public string? Contents => File.Exists(Path) ? File.ReadAllText(Path, System.Text.Encoding.Default) : null;
}
// Turns out to be very important to keep the MetadataReaderProvider live
@@ -41,7 +41,7 @@ namespace Semmle.Extraction.PDB
public IEnumerable<ISourceFile> SourceFiles => reader.Documents.Select(handle => new SourceFile(reader, handle));
public IMethod GetMethod(MethodDebugInformationHandle handle)
public IMethod? GetMethod(MethodDebugInformationHandle handle)
{
var debugInfo = reader.GetMethodDebugInformation(handle);
@@ -51,10 +51,10 @@ namespace Semmle.Extraction.PDB
Where(p => p.Location.File.Path != null).
ToArray();
return sequencePoints.Any() ? new Method() { SequencePoints = sequencePoints } : null;
return sequencePoints.Any() ? new Method(sequencePoints) : null;
}
public static MetadataPdbReader CreateFromAssembly(string assemblyPath, PEReader peReader)
public static MetadataPdbReader? CreateFromAssembly(string assemblyPath, PEReader peReader)
{
foreach (var provider in peReader.
ReadDebugDirectory().

View File

@@ -23,7 +23,7 @@ namespace Semmle.Extraction.PDB
public Document(ISymUnmanagedDocument doc)
{
document = doc;
contents = new Lazy<string>(() =>
contents = new Lazy<string?>(() =>
{
bool isEmbedded;
if (document.HasEmbeddedSource(out isEmbedded) == 0 && isEmbedded)
@@ -38,7 +38,7 @@ namespace Semmle.Extraction.PDB
});
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
var otherDoc = obj as Document;
return otherDoc != null && Path.Equals(otherDoc.Path);
@@ -50,14 +50,14 @@ namespace Semmle.Extraction.PDB
public override string ToString() => Path;
readonly Lazy<string> contents;
readonly Lazy<string?> contents;
public string Contents => contents.Value;
public string? Contents => contents.Value;
}
public IEnumerable<ISourceFile> SourceFiles => reader.GetDocuments().Select(d => new Document(d));
public IMethod GetMethod(MethodDebugInformationHandle h)
public IMethod? GetMethod(MethodDebugInformationHandle h)
{
int methodToken = MetadataTokens.GetToken(h.ToDefinitionHandle());
var method = reader.GetMethod(methodToken);
@@ -72,7 +72,7 @@ namespace Semmle.Extraction.PDB
Select(sp => new SequencePoint(sp.Offset, new Location(new Document(sp.Document), sp.StartLine, sp.StartColumn, sp.EndLine, sp.EndColumn))).
ToArray();
return s.Any() ? new Method { SequencePoints = s } : null;
return s.Any() ? new Method(s) : null;
}
return null;
}
@@ -87,7 +87,7 @@ namespace Semmle.Extraction.PDB
readonly ISymUnmanagedReader5 reader;
readonly FileStream pdbStream;
public static NativePdbReader CreateFromAssembly(string assemblyPath, PEReader peReader)
public static NativePdbReader? CreateFromAssembly(string assemblyPath, PEReader peReader)
{
// The Native PDB reader uses an unmanaged Windows DLL
// so only works on Windows.
@@ -123,7 +123,7 @@ namespace Semmle.Extraction.PDB
{
}
public object GetMetadataImport() => null;
public object? GetMetadataImport() => null;
public unsafe bool TryGetStandaloneSignature(int standaloneSignatureToken, out byte* signature, out int length) =>
throw new NotImplementedException();

View File

@@ -55,7 +55,7 @@ namespace Semmle.Extraction.PDB
return string.Format("({0},{1})-({2},{3})", StartLine, StartColumn, EndLine, EndColumn);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
var otherLocation = obj as Location;
@@ -91,7 +91,12 @@ namespace Semmle.Extraction.PDB
class Method : IMethod
{
public IEnumerable<SequencePoint> SequencePoints { get; set; }
public IEnumerable<SequencePoint> SequencePoints { get; }
public Method(IEnumerable<SequencePoint> sequencePoints)
{
SequencePoints = sequencePoints;
}
public Location Location => SequencePoints.First().Location;
}
@@ -111,7 +116,7 @@ namespace Semmle.Extraction.PDB
/// null if the contents are unavailable.
/// E.g. if the PDB file exists but the corresponding source files are missing.
/// </summary>
string Contents { get; }
string? Contents { get; }
}
/// <summary>
@@ -131,7 +136,7 @@ namespace Semmle.Extraction.PDB
/// </summary>
/// <param name="methodHandle">The handle to query.</param>
/// <returns>The method information, or null if the method does not have debug information.</returns>
IMethod GetMethod(MethodDebugInformationHandle methodHandle);
IMethod? GetMethod(MethodDebugInformationHandle methodHandle);
}
class PdbReader
@@ -140,11 +145,11 @@ namespace Semmle.Extraction.PDB
/// Returns the PDB information associated with an assembly.
/// </summary>
/// <param name="assemblyPath">The path to the assembly.</param>
/// <param name="peReader">The PE reader for the assembky.</param>
/// <param name="peReader">The PE reader for the assembly.</param>
/// <returns>A PdbReader, or null if no PDB information is available.</returns>
public static IPdb Create(string assemblyPath, PEReader peReader)
public static IPdb? Create(string assemblyPath, PEReader peReader)
{
return (IPdb)MetadataPdbReader.CreateFromAssembly(assemblyPath, peReader) ??
return (IPdb?)MetadataPdbReader.CreateFromAssembly(assemblyPath, peReader) ??
NativePdbReader.CreateFromAssembly(assemblyPath, peReader);
}
}

View File

@@ -7,6 +7,7 @@
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<RuntimeIdentifiers>win-x64;linux-x64;osx-x64</RuntimeIdentifiers>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -64,7 +64,7 @@ namespace Semmle.Util
/// Enumerates a possibly null enumerable.
/// If the enumerable is null, the list is empty.
/// </summary>
public static IEnumerable<T> EnumerateNull<T>(this IEnumerable<T> items)
public static IEnumerable<T> EnumerateNull<T>(this IEnumerable<T>? items)
{
if (items == null) yield break;
foreach (var item in items) yield return item;
@@ -93,7 +93,7 @@ namespace Semmle.Util
/// <typeparam name="T">The type of the item.</typeparam>
/// <param name="items">The list of items to hash.</param>
/// <returns>The hash code.</returns>
public static int SequenceHash<T>(this IEnumerable<T> items) where T: notnull
public static int SequenceHash<T>(this IEnumerable<T> items) where T : notnull
{
int h = 0;
foreach (var i in items)