Merge pull request #5197 from tamasvajk/feature/refactor-4

C#: Enable nullability in Extraction.CSharp
This commit is contained in:
Tamás Vajk
2021-03-05 16:24:19 +01:00
committed by GitHub
118 changed files with 1334 additions and 1189 deletions

View File

@@ -7,7 +7,7 @@ namespace Semmle.Extraction.CIL
{
public static class Analyser
{
private static void ExtractCIL(Extractor extractor, TrapWriter trapWriter, bool extractPdbs)
private static void ExtractCIL(TracingExtractor extractor, TrapWriter trapWriter, bool extractPdbs)
{
using var cilContext = new Context(extractor, trapWriter, extractor.OutputPath, extractPdbs);
cilContext.Populate(new Assembly(cilContext));
@@ -33,7 +33,7 @@ namespace Semmle.Extraction.CIL
{
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
var pathTransformer = new PathTransformer(canonicalPathCache);
var extractor = new Extractor(false, assemblyPath, logger, pathTransformer);
var extractor = new TracingExtractor(assemblyPath, logger, pathTransformer);
var transformedAssemblyPath = pathTransformer.Transform(assemblyPath);
var project = layout.LookupProjectOrDefault(transformedAssemblyPath);
using var trapWriter = project.CreateTrapWriter(logger, transformedAssemblyPath.WithSuffix(".cil"), trapCompression, discardDuplicates: true);

View File

@@ -114,7 +114,7 @@ namespace Semmle.Extraction.CIL
entity = new MethodSpecificationMethod(gc, (MethodSpecificationHandle)handle);
break;
case HandleKind.FieldDefinition:
entity = new DefinitionField(gc.Cx, (FieldDefinitionHandle)handle);
entity = new DefinitionField(gc.Context, (FieldDefinitionHandle)handle);
break;
case HandleKind.TypeReference:
var tr = new TypeReferenceType(this, (TypeReferenceHandle)handle);
@@ -130,7 +130,7 @@ namespace Semmle.Extraction.CIL
break;
case HandleKind.StandaloneSignature:
var signature = MdReader.GetStandaloneSignature((StandaloneSignatureHandle)handle);
var method = signature.DecodeMethodSignature(gc.Cx.TypeSignatureDecoder, gc);
var method = signature.DecodeMethodSignature(gc.Context.TypeSignatureDecoder, gc);
entity = new FunctionPointerType(this, method);
break;
default:

View File

@@ -9,10 +9,10 @@ namespace Semmle.Extraction.CIL
{
public EmptyContext(Context cx)
{
Cx = cx;
Context = cx;
}
public Context Cx { get; }
public Context Context { get; }
public IEnumerable<Entities.Type> TypeParameters { get { yield break; } }

View File

@@ -42,7 +42,7 @@ namespace Semmle.Extraction.CIL.Entities
public override string Name => elementType.Name + "[]";
public override Namespace ContainingNamespace => Cx.SystemNamespace;
public override Namespace ContainingNamespace => Context.SystemNamespace;
public override Type? ContainingType => null;
@@ -50,9 +50,9 @@ namespace Semmle.Extraction.CIL.Entities
public override CilTypeKind Kind => CilTypeKind.Array;
public override Type Construct(IEnumerable<Type> typeArguments) => Cx.Populate(new ArrayType(Cx, elementType.Construct(typeArguments)));
public override Type Construct(IEnumerable<Type> typeArguments) => Context.Populate(new ArrayType(Context, elementType.Construct(typeArguments)));
public override Type SourceDeclaration => Cx.Populate(new ArrayType(Cx, elementType.SourceDeclaration));
public override Type SourceDeclaration => Context.Populate(new ArrayType(Context, elementType.SourceDeclaration));
public override IEnumerable<IExtractionProduct> Contents
{

View File

@@ -36,7 +36,7 @@ namespace Semmle.Extraction.CIL.Entities
{
trapFile.Write(FullName);
trapFile.Write("#file:///");
trapFile.Write(Cx.AssemblyPath.Replace("\\", "/"));
trapFile.Write(Context.AssemblyPath.Replace("\\", "/"));
trapFile.Write(";assembly");
}
@@ -56,24 +56,24 @@ namespace Semmle.Extraction.CIL.Entities
yield return file;
yield return Tuples.assemblies(this, file, FullName, assemblyName.Name ?? string.Empty, assemblyName.Version?.ToString() ?? string.Empty);
if (Cx.Pdb != null)
if (Context.Pdb != null)
{
foreach (var f in Cx.Pdb.SourceFiles)
foreach (var f in Context.Pdb.SourceFiles)
{
yield return Cx.CreateSourceFile(f);
yield return Context.CreateSourceFile(f);
}
}
foreach (var handle in Cx.MdReader.TypeDefinitions)
foreach (var handle in Context.MdReader.TypeDefinitions)
{
IExtractionProduct? product = null;
try
{
product = Cx.Create(handle);
product = Context.Create(handle);
}
catch (InternalError e)
{
Cx.ExtractionError("Error processing type definition", e.Message, GeneratedLocation.Create(Cx), e.StackTrace);
Context.ExtractionError("Error processing type definition", e.Message, GeneratedLocation.Create(Context), e.StackTrace);
}
// Limitation of C#: Cannot yield return inside a try-catch.
@@ -81,16 +81,16 @@ namespace Semmle.Extraction.CIL.Entities
yield return product;
}
foreach (var handle in Cx.MdReader.MethodDefinitions)
foreach (var handle in Context.MdReader.MethodDefinitions)
{
IExtractionProduct? product = null;
try
{
product = Cx.Create(handle);
product = Context.Create(handle);
}
catch (InternalError e)
{
Cx.ExtractionError("Error processing bytecode", e.Message, GeneratedLocation.Create(Cx), e.StackTrace);
Context.ExtractionError("Error processing bytecode", e.Message, GeneratedLocation.Create(Context), e.StackTrace);
}
if (product != null)

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CIL.Entities
{
get
{
var constructor = (Method)Cx.Create(attrib.Constructor);
var constructor = (Method)Context.Create(attrib.Constructor);
yield return constructor;
yield return Tuples.cil_attribute(this, @object, constructor);
@@ -41,11 +41,11 @@ namespace Semmle.Extraction.CIL.Entities
try
{
decoded = attrib.DecodeValue(new CustomAttributeDecoder(Cx));
decoded = attrib.DecodeValue(new CustomAttributeDecoder(Context));
}
catch
{
Cx.Extractor.Logger.Log(Util.Logging.Severity.Info,
Context.Extractor.Logger.Log(Util.Logging.Severity.Info,
$"Attribute decoding is partial. Decoding attribute {constructor.DeclaringType.GetQualifiedName()} failed on {@object}.");
yield break;
}

View File

@@ -8,7 +8,7 @@ namespace Semmle.Extraction.CIL
/// </summary>
internal interface IGenericContext
{
Context Cx { get; }
Context Context { get; }
/// <summary>
/// The list of generic type parameters/arguments, including type parameters/arguments of

View File

@@ -10,8 +10,7 @@ namespace Semmle.Extraction.CIL
/// </summary>
internal abstract class LabelledEntity : Extraction.LabelledEntity, IExtractedEntity
{
// todo: with .NET 5 this can override the base context, and change the return type.
public Context Cx => (Context)base.Context;
public override Context Context => (Context)base.Context;
protected LabelledEntity(Context cx) : base(cx)
{

View File

@@ -9,8 +9,7 @@ namespace Semmle.Extraction.CIL
/// </summary>
internal abstract class UnlabelledEntity : Extraction.UnlabelledEntity, IExtractedEntity
{
// todo: with .NET 5 this can override the base context, and change the return type.
public Context Cx => (Context)base.Context;
public override Context Context => (Context)base.Context;
protected UnlabelledEntity(Context cx) : base(cx)
{

View File

@@ -14,7 +14,7 @@ namespace Semmle.Extraction.CIL.Entities
public DefinitionField(Context cx, FieldDefinitionHandle handle) : base(cx)
{
this.handle = handle;
fd = Cx.MdReader.GetFieldDefinition(handle);
fd = Context.MdReader.GetFieldDefinition(handle);
}
public override bool Equals(object? obj)
@@ -28,7 +28,7 @@ namespace Semmle.Extraction.CIL.Entities
{
get
{
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
foreach (var c in base.Contents)
yield return c;
@@ -48,16 +48,16 @@ namespace Semmle.Extraction.CIL.Entities
if (fd.Attributes.HasFlag(FieldAttributes.Assembly))
yield return Tuples.cil_internal(this);
foreach (var c in Attribute.Populate(Cx, this, fd.GetCustomAttributes()))
foreach (var c in Attribute.Populate(Context, this, fd.GetCustomAttributes()))
yield return c;
}
}
public override string Name => Cx.GetString(fd.Name);
public override string Name => Context.GetString(fd.Name);
public override Type DeclaringType => (Type)Cx.Create(fd.GetDeclaringType());
public override Type DeclaringType => (Type)Context.Create(fd.GetDeclaringType());
public override Type Type => fd.DecodeSignature(Cx.TypeSignatureDecoder, DeclaringType);
public override Type Type => fd.DecodeSignature(Context.TypeSignatureDecoder, DeclaringType);
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();

View File

@@ -25,16 +25,16 @@ namespace Semmle.Extraction.CIL.Entities
public DefinitionMethod(IGenericContext gc, MethodDefinitionHandle handle) : base(gc)
{
md = Cx.MdReader.GetMethodDefinition(handle);
md = Context.MdReader.GetMethodDefinition(handle);
this.gc = gc;
this.handle = handle;
name = Cx.GetString(md.Name);
name = Context.GetString(md.Name);
declaringType = (Type)Cx.CreateGeneric(this, md.GetDeclaringType());
declaringType = (Type)Context.CreateGeneric(this, md.GetDeclaringType());
signature = md.DecodeSignature(new SignatureDecoder(), this);
methodDebugInformation = Cx.GetMethodDebugInformation(handle);
methodDebugInformation = Context.GetMethodDebugInformation(handle);
}
public override bool Equals(object? obj)
@@ -48,7 +48,7 @@ namespace Semmle.Extraction.CIL.Entities
public override Type DeclaringType => declaringType;
public override string Name => Cx.ShortName(md.Name);
public override string Name => Context.ShortName(md.Name);
public override string NameLabel => name;
@@ -67,14 +67,14 @@ namespace Semmle.Extraction.CIL.Entities
// depend on other type parameters (as a constraint).
genericParams = new MethodTypeParameter[md.GetGenericParameters().Count];
for (var i = 0; i < genericParams.Length; ++i)
genericParams[i] = Cx.Populate(new MethodTypeParameter(this, this, i));
genericParams[i] = Context.Populate(new MethodTypeParameter(this, this, i));
for (var i = 0; i < genericParams.Length; ++i)
genericParams[i].PopulateHandle(md.GetGenericParameters()[i]);
foreach (var p in genericParams)
yield return p;
}
var typeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this);
var typeSignature = md.DecodeSignature(Context.TypeSignatureDecoder, this);
var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
Parameters = parameters.OfType<Parameter>().ToArray();
@@ -85,17 +85,17 @@ namespace Semmle.Extraction.CIL.Entities
foreach (var c in PopulateFlags)
yield return c;
foreach (var p in md.GetParameters().Select(h => Cx.MdReader.GetParameter(h)).Where(p => p.SequenceNumber > 0))
foreach (var p in md.GetParameters().Select(h => Context.MdReader.GetParameter(h)).Where(p => p.SequenceNumber > 0))
{
var pe = Parameters[IsStatic ? p.SequenceNumber - 1 : p.SequenceNumber];
if (p.Attributes.HasFlag(ParameterAttributes.Out))
yield return Tuples.cil_parameter_out(pe);
if (p.Attributes.HasFlag(ParameterAttributes.In))
yield return Tuples.cil_parameter_in(pe);
Attribute.Populate(Cx, pe, p.GetCustomAttributes());
Attribute.Populate(Context, pe, p.GetCustomAttributes());
}
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
foreach (var m in GetMethodExtractionProducts(Name, declaringType, typeSignature.ReturnType))
{
@@ -103,19 +103,19 @@ namespace Semmle.Extraction.CIL.Entities
}
yield return Tuples.cil_method_source_declaration(this, this);
yield return Tuples.cil_method_location(this, Cx.Assembly);
yield return Tuples.cil_method_location(this, Context.Assembly);
if (HasBytecode)
{
Implementation = new MethodImplementation(this);
yield return Implementation;
var body = Cx.PeReader.GetMethodBody(md.RelativeVirtualAddress);
var body = Context.PeReader.GetMethodBody(md.RelativeVirtualAddress);
if (!body.LocalSignature.IsNil)
{
var locals = Cx.MdReader.GetStandaloneSignature(body.LocalSignature);
var localVariableTypes = locals.DecodeLocalSignature(Cx.TypeSignatureDecoder, this);
var locals = Context.MdReader.GetStandaloneSignature(body.LocalSignature);
var localVariableTypes = locals.DecodeLocalSignature(Context.TypeSignatureDecoder, this);
this.locals = new LocalVariable[localVariableTypes.Length];
@@ -125,13 +125,13 @@ namespace Semmle.Extraction.CIL.Entities
if (t is ByRefType brt)
{
t = brt.ElementType;
this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, t));
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
yield return this.locals[l];
yield return Tuples.cil_type_annotation(this.locals[l], TypeAnnotation.Ref);
}
else
{
this.locals[l] = Cx.Populate(new LocalVariable(Cx, Implementation, l, t));
this.locals[l] = Context.Populate(new LocalVariable(Context, Implementation, l, t));
yield return this.locals[l];
}
}
@@ -152,7 +152,7 @@ namespace Semmle.Extraction.CIL.Entities
if (methodDebugInformation != null)
{
var sourceLocation = Cx.CreateSourceLocation(methodDebugInformation.Location);
var sourceLocation = Context.CreateSourceLocation(methodDebugInformation.Location);
yield return sourceLocation;
yield return Tuples.cil_method_location(this, sourceLocation);
}
@@ -191,7 +191,7 @@ namespace Semmle.Extraction.CIL.Entities
yield return Tuples.cil_newslot(this);
// Populate attributes
Attribute.Populate(Cx, this, md.GetCustomAttributes());
Attribute.Populate(Context, this, md.GetCustomAttributes());
}
}
@@ -210,7 +210,7 @@ namespace Semmle.Extraction.CIL.Entities
nextSequencePoint = methodDebugInformation.SequencePoints.GetEnumerator();
if (nextSequencePoint.MoveNext())
{
instructionLocation = Cx.CreateSourceLocation(nextSequencePoint.Current.Location);
instructionLocation = Context.CreateSourceLocation(nextSequencePoint.Current.Location);
yield return instructionLocation;
}
else
@@ -222,12 +222,12 @@ namespace Semmle.Extraction.CIL.Entities
var child = 0;
for (var offset = 0; offset < (ilbytes?.Length ?? 0);)
{
var instruction = new Instruction(Cx, this, ilbytes!, offset, child++);
var instruction = new Instruction(Context, this, ilbytes!, offset, child++);
yield return instruction;
if (nextSequencePoint != null && offset >= nextSequencePoint.Current.Offset)
{
instructionLocation = Cx.CreateSourceLocation(nextSequencePoint.Current.Location);
instructionLocation = Context.CreateSourceLocation(nextSequencePoint.Current.Location);
yield return instructionLocation;
if (!nextSequencePoint.MoveNext())
nextSequencePoint = null;
@@ -257,7 +257,7 @@ namespace Semmle.Extraction.CIL.Entities
{
if (md.ImplAttributes == MethodImplAttributes.IL && md.RelativeVirtualAddress != 0)
{
var body = Cx.PeReader.GetMethodBody(md.RelativeVirtualAddress);
var body = Context.PeReader.GetMethodBody(md.RelativeVirtualAddress);
var ilbytes = body.GetILBytes();
@@ -267,7 +267,7 @@ namespace Semmle.Extraction.CIL.Entities
Instruction decoded;
try
{
decoded = new Instruction(Cx, this, ilbytes!, offset, child++);
decoded = new Instruction(Context, this, ilbytes!, offset, child++);
offset += decoded.Width;
}
catch // lgtm[cs/catch-of-all-exceptions]

View File

@@ -16,7 +16,7 @@ namespace Semmle.Extraction.CIL.Entities
public override string Name => "!error";
public override Namespace ContainingNamespace => Cx.GlobalNamespace;
public override Namespace ContainingNamespace => Context.GlobalNamespace;
public override Type? ContainingType => null;

View File

@@ -24,7 +24,7 @@ namespace Semmle.Extraction.CIL.Entities
{
parent.WriteId(trapFile);
trapFile.Write('.');
trapFile.Write(Cx.ShortName(ed.Name));
trapFile.Write(Context.ShortName(ed.Name));
trapFile.Write(";cil-event");
}
@@ -39,34 +39,34 @@ namespace Semmle.Extraction.CIL.Entities
{
get
{
var signature = (Type)Cx.CreateGeneric(parent, ed.Type);
var signature = (Type)Context.CreateGeneric(parent, ed.Type);
yield return signature;
yield return Tuples.cil_event(this, parent, Cx.ShortName(ed.Name), signature);
yield return Tuples.cil_event(this, parent, Context.ShortName(ed.Name), signature);
var accessors = ed.GetAccessors();
if (!accessors.Adder.IsNil)
{
var adder = (Method)Cx.CreateGeneric(parent, accessors.Adder);
var adder = (Method)Context.CreateGeneric(parent, accessors.Adder);
yield return adder;
yield return Tuples.cil_adder(this, adder);
}
if (!accessors.Remover.IsNil)
{
var remover = (Method)Cx.CreateGeneric(parent, accessors.Remover);
var remover = (Method)Context.CreateGeneric(parent, accessors.Remover);
yield return remover;
yield return Tuples.cil_remover(this, remover);
}
if (!accessors.Raiser.IsNil)
{
var raiser = (Method)Cx.CreateGeneric(parent, accessors.Raiser);
var raiser = (Method)Context.CreateGeneric(parent, accessors.Raiser);
yield return raiser;
yield return Tuples.cil_raiser(this, raiser);
}
foreach (var c in Attribute.Populate(Cx, this, ed.GetCustomAttributes()))
foreach (var c in Attribute.Populate(Context, this, ed.GetCustomAttributes()))
yield return c;
}
}

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CIL.Entities
private readonly System.Reflection.Metadata.ExceptionRegion r;
private readonly Dictionary<int, Instruction> jump_table;
public ExceptionRegion(IGenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary<int, Instruction> jump_table) : base(gc.Cx)
public ExceptionRegion(IGenericContext gc, MethodImplementation method, int index, System.Reflection.Metadata.ExceptionRegion r, Dictionary<int, Instruction> jump_table) : base(gc.Context)
{
this.gc = gc;
this.method = method;
@@ -46,7 +46,7 @@ namespace Semmle.Extraction.CIL.Entities
if (!r.CatchType.IsNil)
{
var catchType = (Type)Cx.CreateGeneric(gc, r.CatchType);
var catchType = (Type)Context.CreateGeneric(gc, r.CatchType);
yield return catchType;
yield return Tuples.cil_handler_type(this, catchType);
}

View File

@@ -11,7 +11,7 @@ namespace Semmle.Extraction.CIL.Entities
public File(Context cx, string path) : base(cx)
{
this.OriginalPath = path;
TransformedPath = Cx.Extractor.PathTransformer.Transform(OriginalPath);
TransformedPath = Context.Extractor.PathTransformer.Transform(OriginalPath);
}
public override void WriteId(TextWriter trapFile)
@@ -33,7 +33,7 @@ namespace Semmle.Extraction.CIL.Entities
{
if (TransformedPath.ParentDirectory is PathTransformer.ITransformedPath dir)
{
var parent = Cx.CreateFolder(dir);
var parent = Context.CreateFolder(dir);
yield return parent;
yield return Tuples.containerparent(parent, this);
}

View File

@@ -24,7 +24,7 @@ namespace Semmle.Extraction.CIL.Entities
{
if (transformedPath.ParentDirectory is PathTransformer.ITransformedPath parent)
{
var parentFolder = Cx.CreateFolder(parent);
var parentFolder = Context.CreateFolder(parent);
yield return parentFolder;
yield return Tuples.containerparent(parentFolder, this);
}

View File

@@ -30,7 +30,7 @@ namespace Semmle.Extraction.CIL.Entities
}
}
public override Namespace? ContainingNamespace => Cx.GlobalNamespace;
public override Namespace? ContainingNamespace => Context.GlobalNamespace;
public override Type? ContainingType => null;
@@ -104,7 +104,7 @@ namespace Semmle.Extraction.CIL.Entities
yield return Tuples.cil_function_pointer_calling_conventions(this, signature.Header.CallingConvention);
foreach (var p in Method.GetParameterExtractionProducts(signature.ParameterTypes, this, this, Cx, 0))
foreach (var p in Method.GetParameterExtractionProducts(signature.ParameterTypes, this, this, Context, 0))
{
yield return p;
}

View File

@@ -356,7 +356,7 @@ namespace Semmle.Extraction.CIL.Entities
switch (PayloadType)
{
case Payload.String:
yield return Tuples.cil_value(this, Cx.MdReader.GetUserString(MetadataTokens.UserStringHandle(payloadValue)));
yield return Tuples.cil_value(this, Context.MdReader.GetUserString(MetadataTokens.UserStringHandle(payloadValue)));
break;
case Payload.Float32:
yield return Tuples.cil_value(this, BitConverter.ToSingle(data, offset).ToString());
@@ -388,7 +388,7 @@ namespace Semmle.Extraction.CIL.Entities
{
// A generic EntityHandle.
var handle = MetadataTokens.EntityHandle(payloadValue);
var target = Cx.CreateGeneric(Method, handle);
var target = Context.CreateGeneric(Method, handle);
yield return target;
if (target != null)
{
@@ -428,11 +428,11 @@ namespace Semmle.Extraction.CIL.Entities
IExtractedEntity? target = null;
try
{
target = Cx.CreateGeneric(Method, handle);
target = Context.CreateGeneric(Method, handle);
}
catch (Exception exc)
{
Cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, $"Couldn't interpret payload of payload type {PayloadType} as a function pointer type. {exc.Message} {exc.StackTrace}");
Context.Extractor.Logger.Log(Util.Logging.Severity.Warning, $"Couldn't interpret payload of payload type {PayloadType} as a function pointer type. {exc.Message} {exc.StackTrace}");
}
if (target != null)
@@ -501,7 +501,7 @@ namespace Semmle.Extraction.CIL.Entities
// TODO: Find a solution to this.
// For now, just log the error
Cx.ExtractionError("A CIL instruction jumps outside the current method", null, Extraction.Entities.GeneratedLocation.Create(Cx), "", Util.Logging.Severity.Warning);
Context.ExtractionError("A CIL instruction jumps outside the current method", null, Extraction.Entities.GeneratedLocation.Create(Context), "", Util.Logging.Severity.Warning);
}
}
}

View File

@@ -11,12 +11,12 @@ namespace Semmle.Extraction.CIL.Entities
private readonly IGenericContext gc;
private readonly Type declType;
public MemberReferenceField(IGenericContext gc, MemberReferenceHandle handle) : base(gc.Cx)
public MemberReferenceField(IGenericContext gc, MemberReferenceHandle handle) : base(gc.Context)
{
this.handle = handle;
this.gc = gc;
mr = Cx.MdReader.GetMemberReference(handle);
declType = (Type)Cx.CreateGeneric(gc, mr.Parent);
mr = Context.MdReader.GetMemberReference(handle);
declType = (Type)Context.CreateGeneric(gc, mr.Parent);
}
public override bool Equals(object? obj)
@@ -29,11 +29,11 @@ namespace Semmle.Extraction.CIL.Entities
return handle.GetHashCode();
}
public override string Name => Cx.GetString(mr.Name);
public override string Name => Context.GetString(mr.Name);
public override Type DeclaringType => declType;
public override Type Type => mr.DecodeFieldSignature(Cx.TypeSignatureDecoder, this);
public override Type Type => mr.DecodeFieldSignature(Context.TypeSignatureDecoder, this);
public override IEnumerable<Type> TypeParameters => gc.TypeParameters.Concat(declType.TypeParameters);

View File

@@ -19,11 +19,11 @@ namespace Semmle.Extraction.CIL.Entities
{
this.handle = handle;
this.gc = gc;
mr = Cx.MdReader.GetMemberReference(handle);
mr = Context.MdReader.GetMemberReference(handle);
signature = mr.DecodeMethodSignature(new SignatureDecoder(), gc);
parent = (IGenericContext)Cx.CreateGeneric(gc, mr.Parent);
parent = (IGenericContext)Context.CreateGeneric(gc, mr.Parent);
var declType = parent is Method parentMethod
? parentMethod.DeclaringType
@@ -33,7 +33,7 @@ namespace Semmle.Extraction.CIL.Entities
throw new InternalError("Parent context of method is not a type");
declaringType = declType;
nameLabel = Cx.GetString(mr.Name);
nameLabel = Context.GetString(mr.Name);
var typeSourceDeclaration = declaringType.SourceDeclaration;
sourceDeclaration = typeSourceDeclaration == declaringType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
@@ -59,7 +59,7 @@ namespace Semmle.Extraction.CIL.Entities
public override Type DeclaringType => declaringType;
public override string Name => Cx.ShortName(mr.Name);
public override string Name => Context.ShortName(mr.Name);
public override IEnumerable<Type> TypeParameters => parent.TypeParameters.Concat(gc.TypeParameters);
@@ -69,12 +69,12 @@ namespace Semmle.Extraction.CIL.Entities
{
genericParams = new MethodTypeParameter[signature.GenericParameterCount];
for (var p = 0; p < genericParams.Length; ++p)
genericParams[p] = Cx.Populate(new MethodTypeParameter(this, this, p));
genericParams[p] = Context.Populate(new MethodTypeParameter(this, this, p));
foreach (var p in genericParams)
yield return p;
var typeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this);
var typeSignature = mr.DecodeMethodSignature(Context.TypeSignatureDecoder, this);
var parameters = GetParameterExtractionProducts(typeSignature.ParameterTypes).ToArray();
Parameters = parameters.OfType<Parameter>().ToArray();

View File

@@ -15,7 +15,7 @@ namespace Semmle.Extraction.CIL.Entities
protected IGenericContext gc;
protected MethodSignature<ITypeSignature> signature;
protected Method(IGenericContext gc) : base(gc.Cx)
protected Method(IGenericContext gc) : base(gc.Context)
{
this.gc = gc;
}
@@ -83,10 +83,10 @@ namespace Semmle.Extraction.CIL.Entities
if (!IsStatic)
{
yield return Cx.Populate(new Parameter(Cx, this, i++, DeclaringType));
yield return Context.Populate(new Parameter(Context, this, i++, DeclaringType));
}
foreach (var p in GetParameterExtractionProducts(parameterTypes, this, this, Cx, i))
foreach (var p in GetParameterExtractionProducts(parameterTypes, this, this, Context, i))
{
yield return p;
}

View File

@@ -10,7 +10,7 @@ namespace Semmle.Extraction.CIL.Entities
{
private readonly Method m;
public MethodImplementation(Method m) : base(m.Cx)
public MethodImplementation(Method m) : base(m.Context)
{
this.m = m;
}
@@ -19,7 +19,7 @@ namespace Semmle.Extraction.CIL.Entities
{
get
{
yield return Tuples.cil_method_implementation(this, m, Cx.Assembly);
yield return Tuples.cil_method_implementation(this, m, Context.Assembly);
}
}
}

View File

@@ -21,9 +21,9 @@ namespace Semmle.Extraction.CIL.Entities
public MethodSpecificationMethod(IGenericContext gc, MethodSpecificationHandle handle) : base(gc)
{
this.handle = handle;
ms = Cx.MdReader.GetMethodSpecification(handle);
typeParams = ms.DecodeSignature(Cx.TypeSignatureDecoder, gc);
unboundMethod = (Method)Cx.CreateGeneric(gc, ms.Method);
ms = Context.MdReader.GetMethodSpecification(handle);
typeParams = ms.DecodeSignature(Context.TypeSignatureDecoder, gc);
unboundMethod = (Method)Context.CreateGeneric(gc, ms.Method);
}
public override void WriteId(TextWriter trapFile)
@@ -66,12 +66,12 @@ namespace Semmle.Extraction.CIL.Entities
switch (ms.Method.Kind)
{
case HandleKind.MemberReference:
var mr = Cx.MdReader.GetMemberReference((MemberReferenceHandle)ms.Method);
constructedTypeSignature = mr.DecodeMethodSignature(Cx.TypeSignatureDecoder, this);
var mr = Context.MdReader.GetMemberReference((MemberReferenceHandle)ms.Method);
constructedTypeSignature = mr.DecodeMethodSignature(Context.TypeSignatureDecoder, this);
break;
case HandleKind.MethodDefinition:
var md = Cx.MdReader.GetMethodDefinition((MethodDefinitionHandle)ms.Method);
constructedTypeSignature = md.DecodeSignature(Cx.TypeSignatureDecoder, this);
var md = Context.MdReader.GetMethodDefinition((MethodDefinitionHandle)ms.Method);
constructedTypeSignature = md.DecodeSignature(Context.TypeSignatureDecoder, this);
break;
default:
throw new InternalError($"Unexpected constructed method handle kind {ms.Method.Kind}");

View File

@@ -38,11 +38,11 @@ namespace Semmle.Extraction.CIL.Entities
unboundGenericType = nameParser.UnboundGenericTypeName == null
? this
: new NoMetadataHandleType(Cx, nameParser.UnboundGenericTypeName);
: new NoMetadataHandleType(Context, nameParser.UnboundGenericTypeName);
if (nameParser.TypeArguments != null)
{
thisTypeArguments = nameParser.TypeArguments.Select(t => new NoMetadataHandleType(Cx, t)).ToArray();
thisTypeArguments = nameParser.TypeArguments.Select(t => new NoMetadataHandleType(Context, t)).ToArray();
}
else
{
@@ -51,14 +51,14 @@ namespace Semmle.Extraction.CIL.Entities
containingType = isContainerNamespace
? null
: new NoMetadataHandleType(Cx, containerName);
: new NoMetadataHandleType(Context, containerName);
containingNamespace = isContainerNamespace
? containerName == Cx.GlobalNamespace.Name
? Cx.GlobalNamespace
: containerName == Cx.SystemNamespace.Name
? Cx.SystemNamespace
: new Namespace(Cx, containerName)
? containerName == Context.GlobalNamespace.Name
? Context.GlobalNamespace
: containerName == Context.SystemNamespace.Name
? Context.SystemNamespace
: new Namespace(Context, containerName)
: null;
Populate();
@@ -68,10 +68,10 @@ namespace Semmle.Extraction.CIL.Entities
{
if (ContainingNamespace is object)
{
Cx.Populate(ContainingNamespace);
Context.Populate(ContainingNamespace);
}
Cx.Populate(this);
Context.Populate(this);
}
public override bool Equals(object? obj)
@@ -118,7 +118,7 @@ namespace Semmle.Extraction.CIL.Entities
if (TotalTypeParametersCount != typeArguments.Count())
throw new InternalError("Mismatched type arguments");
return Cx.Populate(new ConstructedType(Cx, this, typeArguments));
return Context.Populate(new ConstructedType(Context, this, typeArguments));
}
public override void WriteAssemblyPrefix(TextWriter trapFile)
@@ -133,7 +133,7 @@ namespace Semmle.Extraction.CIL.Entities
}
else
{
Cx.WriteAssemblyPrefix(trapFile);
Context.WriteAssemblyPrefix(trapFile);
}
}

View File

@@ -21,9 +21,9 @@ namespace Semmle.Extraction.CIL.Entities
var text = file.Contents;
if (text == null)
Cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, string.Format("PDB source file {0} could not be found", OriginalPath));
Context.Extractor.Logger.Log(Util.Logging.Severity.Warning, string.Format("PDB source file {0} could not be found", OriginalPath));
else
Cx.TrapWriter.Archive(TransformedPath, text);
Context.TrapWriter.Archive(TransformedPath, text);
yield return Tuples.file_extraction_mode(this, 2);
}

View File

@@ -27,7 +27,7 @@ namespace Semmle.Extraction.CIL.Entities
public override string Name => typeCode.Id();
public override Namespace ContainingNamespace => Cx.SystemNamespace;
public override Namespace ContainingNamespace => Context.SystemNamespace;
public override Type? ContainingType => null;

View File

@@ -15,11 +15,11 @@ namespace Semmle.Extraction.CIL.Entities
private readonly PropertyDefinition pd;
private readonly IGenericContext gc;
public Property(IGenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.Cx)
public Property(IGenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.Context)
{
this.gc = gc;
this.handle = handle;
pd = Cx.MdReader.GetPropertyDefinition(handle);
pd = Context.MdReader.GetPropertyDefinition(handle);
this.type = type;
}
@@ -27,7 +27,7 @@ namespace Semmle.Extraction.CIL.Entities
{
trapFile.WriteSubId(type);
trapFile.Write('.');
trapFile.Write(Cx.GetString(pd.Name));
trapFile.Write(Context.GetString(pd.Name));
trapFile.Write("(");
var index = 0;
var signature = pd.DecodeSignature(new SignatureDecoder(), gc);
@@ -51,10 +51,10 @@ namespace Semmle.Extraction.CIL.Entities
{
get
{
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
var sig = pd.DecodeSignature(Cx.TypeSignatureDecoder, type);
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
var sig = pd.DecodeSignature(Context.TypeSignatureDecoder, type);
var name = Cx.ShortName(pd.Name);
var name = Context.ShortName(pd.Name);
var t = sig.ReturnType;
if (t is ModifiedType mt)
@@ -72,19 +72,19 @@ namespace Semmle.Extraction.CIL.Entities
var accessors = pd.GetAccessors();
if (!accessors.Getter.IsNil)
{
var getter = (Method)Cx.CreateGeneric(type, accessors.Getter);
var getter = (Method)Context.CreateGeneric(type, accessors.Getter);
yield return getter;
yield return Tuples.cil_getter(this, getter);
}
if (!accessors.Setter.IsNil)
{
var setter = (Method)Cx.CreateGeneric(type, accessors.Setter);
var setter = (Method)Context.CreateGeneric(type, accessors.Setter);
yield return setter;
yield return Tuples.cil_setter(this, setter);
}
foreach (var c in Attribute.Populate(Cx, this, pd.GetCustomAttributes()))
foreach (var c in Attribute.Populate(Context, this, pd.GetCustomAttributes()))
yield return c;
}
}

View File

@@ -250,7 +250,7 @@ namespace Semmle.Extraction.CIL.Entities
public void WriteId(TextWriter trapFile, IGenericContext gc)
{
var type = (Type)gc.Cx.Create(handle);
var type = (Type)gc.Context.Create(handle);
type.WriteId(trapFile);
}
}
@@ -271,7 +271,7 @@ namespace Semmle.Extraction.CIL.Entities
public void WriteId(TextWriter trapFile, IGenericContext gc)
{
var type = (Type)gc.Cx.Create(handle);
var type = (Type)gc.Context.Create(handle);
type.WriteId(trapFile);
}
}

View File

@@ -174,7 +174,7 @@ namespace Semmle.Extraction.CIL.Entities
{
if (TryGetPrimitiveTypeCode(out var code))
{
t = Cx.Create(code);
t = Context.Create(code);
return true;
}
@@ -185,7 +185,7 @@ namespace Semmle.Extraction.CIL.Entities
private bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code)
{
if (ContainingType == null &&
ContainingNamespace?.Name == Cx.SystemNamespace.Name &&
ContainingNamespace?.Name == Context.SystemNamespace.Name &&
primitiveTypeCodeMapping.TryGetValue(Name, out code))
{
return true;
@@ -200,6 +200,6 @@ namespace Semmle.Extraction.CIL.Entities
public sealed override IEnumerable<Type> MethodParameters => Enumerable.Empty<Type>();
public static Type DecodeType(IGenericContext gc, TypeSpecificationHandle handle) =>
gc.Cx.MdReader.GetTypeSpecification(handle).DecodeSignature(gc.Cx.TypeSignatureDecoder, gc);
gc.Context.MdReader.GetTypeSpecification(handle).DecodeSignature(gc.Context.TypeSignatureDecoder, gc);
}
}

View File

@@ -45,9 +45,9 @@ namespace Semmle.Extraction.CIL.Entities
idWriter.WriteId(trapFile, inContext);
}
public override string Name => GenericsHelper.GetNonGenericName(td.Name, Cx.MdReader);
public override string Name => GenericsHelper.GetNonGenericName(td.Name, Context.MdReader);
public override Namespace ContainingNamespace => Cx.Create(td.NamespaceDefinition);
public override Namespace ContainingNamespace => Context.Create(td.NamespaceDefinition);
public override Type? ContainingType => declType;
@@ -58,14 +58,14 @@ namespace Semmle.Extraction.CIL.Entities
if (TotalTypeParametersCount != typeArguments.Count())
throw new InternalError("Mismatched type arguments");
return Cx.Populate(new ConstructedType(Cx, this, typeArguments));
return Context.Populate(new ConstructedType(Context, this, typeArguments));
}
public override void WriteAssemblyPrefix(TextWriter trapFile)
{
var ct = ContainingType;
if (ct is null)
Cx.WriteAssemblyPrefix(trapFile);
Context.WriteAssemblyPrefix(trapFile);
else if (IsPrimitiveType)
trapFile.Write(Type.PrimitiveTypePrefix);
else
@@ -83,7 +83,7 @@ namespace Semmle.Extraction.CIL.Entities
// Two-phase population because type parameters can be mutually dependent
for (var i = 0; i < newTypeParams.Length; ++i)
newTypeParams[i] = Cx.Populate(new TypeTypeParameter(this, i));
newTypeParams[i] = Context.Populate(new TypeTypeParameter(this, i));
for (var i = 0; i < newTypeParams.Length; ++i)
newTypeParams[i].PopulateHandle(genericParams[i + toSkip]);
return newTypeParams;
@@ -96,7 +96,7 @@ namespace Semmle.Extraction.CIL.Entities
var containingType = td.GetDeclaringType();
var parentTypeParameters = containingType.IsNil
? 0
: Cx.MdReader.GetTypeDefinition(containingType).GetGenericParameters().Count;
: Context.MdReader.GetTypeDefinition(containingType).GetGenericParameters().Count;
return td.GetGenericParameters().Count - parentTypeParameters;
}
@@ -110,7 +110,7 @@ namespace Semmle.Extraction.CIL.Entities
{
get
{
yield return Tuples.metadata_handle(this, Cx.Assembly, MetadataTokens.GetToken(handle));
yield return Tuples.metadata_handle(this, Context.Assembly, MetadataTokens.GetToken(handle));
foreach (var c in base.Contents) yield return c;
@@ -119,7 +119,7 @@ namespace Semmle.Extraction.CIL.Entities
foreach (var f in td.GetFields())
{
// Populate field if needed
yield return Cx.CreateGeneric(this, f);
yield return Context.CreateGeneric(this, f);
}
foreach (var prop in td.GetProperties())
@@ -129,16 +129,16 @@ namespace Semmle.Extraction.CIL.Entities
foreach (var @event in td.GetEvents())
{
yield return new Event(Cx, this, @event);
yield return new Event(Context, this, @event);
}
foreach (var a in Attribute.Populate(Cx, this, td.GetCustomAttributes()))
foreach (var a in Attribute.Populate(Context, this, td.GetCustomAttributes()))
yield return a;
foreach (var impl in td.GetMethodImplementations().Select(i => Cx.MdReader.GetMethodImplementation(i)))
foreach (var impl in td.GetMethodImplementations().Select(i => Context.MdReader.GetMethodImplementation(i)))
{
var m = (Method)Cx.CreateGeneric(this, impl.MethodBody);
var decl = (Method)Cx.CreateGeneric(this, impl.MethodDeclaration);
var m = (Method)Context.CreateGeneric(this, impl.MethodBody);
var decl = (Method)Context.CreateGeneric(this, impl.MethodDeclaration);
yield return m;
yield return decl;
@@ -166,7 +166,7 @@ namespace Semmle.Extraction.CIL.Entities
if (!td.BaseType.IsNil)
{
var @base = (Type)Cx.CreateGeneric(this, td.BaseType);
var @base = (Type)Context.CreateGeneric(this, td.BaseType);
yield return @base;
yield return Tuples.cil_base_class(this, @base);
@@ -174,21 +174,21 @@ namespace Semmle.Extraction.CIL.Entities
GetUnderlyingEnumType() is var underlying &&
underlying.HasValue)
{
var underlyingType = Cx.Create(underlying.Value);
var underlyingType = Context.Create(underlying.Value);
yield return underlyingType;
yield return Tuples.cil_enum_underlying_type(this, underlyingType);
}
}
foreach (var @interface in td.GetInterfaceImplementations().Select(i => Cx.MdReader.GetInterfaceImplementation(i)))
foreach (var @interface in td.GetInterfaceImplementations().Select(i => Context.MdReader.GetInterfaceImplementation(i)))
{
var t = (Type)Cx.CreateGeneric(this, @interface.Interface);
var t = (Type)Context.CreateGeneric(this, @interface.Interface);
yield return t;
yield return Tuples.cil_base_interface(this, t);
}
// Only type definitions have locations.
yield return Tuples.cil_type_location(this, Cx.Assembly);
yield return Tuples.cil_type_location(this, Context.Assembly);
}
}
@@ -204,36 +204,36 @@ namespace Semmle.Extraction.CIL.Entities
private bool IsSystemEnum(TypeReferenceHandle baseType)
{
var baseTypeReference = Cx.MdReader.GetTypeReference(baseType);
var baseTypeReference = Context.MdReader.GetTypeReference(baseType);
return IsSystemEnum(baseTypeReference.Name, baseTypeReference.Namespace);
}
private bool IsSystemEnum(TypeDefinitionHandle baseType)
{
var baseTypeDefinition = Cx.MdReader.GetTypeDefinition(baseType);
var baseTypeDefinition = Context.MdReader.GetTypeDefinition(baseType);
return IsSystemEnum(baseTypeDefinition.Name, baseTypeDefinition.Namespace);
}
private bool IsSystemEnum(StringHandle typeName, StringHandle namespaceName)
{
return Cx.MdReader.StringComparer.Equals(typeName, "Enum") &&
return Context.MdReader.StringComparer.Equals(typeName, "Enum") &&
!namespaceName.IsNil &&
Cx.MdReader.StringComparer.Equals(namespaceName, "System");
Context.MdReader.StringComparer.Equals(namespaceName, "System");
}
internal PrimitiveTypeCode? GetUnderlyingEnumType()
{
foreach (var handle in td.GetFields())
{
var field = Cx.MdReader.GetFieldDefinition(handle);
var field = Context.MdReader.GetFieldDefinition(handle);
if (field.Attributes.HasFlag(FieldAttributes.Static))
{
continue;
}
var blob = Cx.MdReader.GetBlobReader(field.Signature);
var blob = Context.MdReader.GetBlobReader(field.Signature);
if (blob.ReadSignatureHeader().Kind != SignatureKind.Field)
{
break;
@@ -249,11 +249,11 @@ namespace Semmle.Extraction.CIL.Entities
{
foreach (var h in td.GetMethods())
{
var md = Cx.MdReader.GetMethodDefinition(h);
var md = Context.MdReader.GetMethodDefinition(h);
if (md.Name == name && md.Signature == signature)
{
return (Method)Cx.Create(h);
return (Method)Context.Create(h);
}
}

View File

@@ -11,7 +11,7 @@ namespace Semmle.Extraction.CIL.Entities
{
protected readonly IGenericContext gc;
protected TypeParameter(IGenericContext gc) : base(gc.Cx)
protected TypeParameter(IGenericContext gc) : base(gc.Context)
{
this.gc = gc;
}
@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CIL.Entities
{
if (!parameterHandle.IsNil)
{
var tp = Cx.MdReader.GetGenericParameter(parameterHandle);
var tp = Context.MdReader.GetGenericParameter(parameterHandle);
if (tp.Attributes.HasFlag(GenericParameterAttributes.Contravariant))
yield return Tuples.cil_typeparam_contravariant(this);
@@ -45,9 +45,9 @@ namespace Semmle.Extraction.CIL.Entities
if (tp.Attributes.HasFlag(GenericParameterAttributes.NotNullableValueTypeConstraint))
yield return Tuples.cil_typeparam_struct(this);
foreach (var constraint in tp.GetConstraints().Select(h => Cx.MdReader.GetGenericParameterConstraint(h)))
foreach (var constraint in tp.GetConstraints().Select(h => Context.MdReader.GetGenericParameterConstraint(h)))
{
var t = (Type)Cx.CreateGeneric(this.gc, constraint.Type);
var t = (Type)Context.CreateGeneric(this.gc, constraint.Type);
yield return t;
yield return Tuples.cil_typeparam_constraint(this, t);
}

View File

@@ -46,16 +46,16 @@ namespace Semmle.Extraction.CIL.Entities
}
}
public override string Name => GenericsHelper.GetNonGenericName(tr.Name, Cx.MdReader);
public override string Name => GenericsHelper.GetNonGenericName(tr.Name, Context.MdReader);
public override Namespace ContainingNamespace => Cx.CreateNamespace(tr.Namespace);
public override Namespace ContainingNamespace => Context.CreateNamespace(tr.Namespace);
public override Type? ContainingType
{
get
{
return tr.ResolutionScope.Kind == HandleKind.TypeReference
? (Type)Cx.Create((TypeReferenceHandle)tr.ResolutionScope)
? (Type)Context.Create((TypeReferenceHandle)tr.ResolutionScope)
: null;
}
}
@@ -70,19 +70,19 @@ namespace Semmle.Extraction.CIL.Entities
ContainingType!.WriteAssemblyPrefix(trapFile);
break;
case HandleKind.AssemblyReference:
var assemblyDef = Cx.MdReader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope);
trapFile.Write(Cx.GetString(assemblyDef.Name));
var assemblyDef = Context.MdReader.GetAssemblyReference((AssemblyReferenceHandle)tr.ResolutionScope);
trapFile.Write(Context.GetString(assemblyDef.Name));
trapFile.Write('_');
trapFile.Write(assemblyDef.Version.ToString());
trapFile.Write(Entities.Type.AssemblyTypeNameSeparator);
break;
default:
Cx.WriteAssemblyPrefix(trapFile);
Context.WriteAssemblyPrefix(trapFile);
break;
}
}
public override int ThisTypeParameterCount => GenericsHelper.GetGenericTypeParameterCount(tr.Name, Cx.MdReader);
public override int ThisTypeParameterCount => GenericsHelper.GetGenericTypeParameterCount(tr.Name, Context.MdReader);
public override IEnumerable<Type> TypeParameters => GenericsHelper.GetAllTypeParameters(ContainingType, typeParams!.Value);
@@ -98,7 +98,7 @@ namespace Semmle.Extraction.CIL.Entities
if (TotalTypeParametersCount != typeArguments.Count())
throw new InternalError("Mismatched type arguments");
return Cx.Populate(new ConstructedType(Cx, this, typeArguments));
return Context.Populate(new ConstructedType(Context, this, typeArguments));
}
}
}

View File

@@ -1,573 +0,0 @@
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.IO;
using System.Linq;
using Semmle.Extraction.CSharp.Populators;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using Semmle.Util.Logging;
using Semmle.Util;
namespace Semmle.Extraction.CSharp
{
/// <summary>
/// Encapsulates a C# analysis task.
/// </summary>
public sealed class Analyser : IDisposable
{
private Extraction.Extractor extractor;
private CSharpCompilation compilation;
private Layout layout;
private bool init;
private readonly object progressMutex = new object();
private int taskCount = 0;
private CommonOptions options;
private Entities.Compilation compilationEntity;
private IDisposable compilationTrapFile;
private readonly Stopwatch stopWatch = new Stopwatch();
private readonly IProgressMonitor progressMonitor;
public ILogger Logger { get; }
public bool AddAssemblyTrapPrefix { get; }
public PathTransformer PathTransformer { get; }
public Analyser(IProgressMonitor pm, ILogger logger, bool addAssemblyTrapPrefix, PathTransformer pathTransformer)
{
Logger = logger;
AddAssemblyTrapPrefix = addAssemblyTrapPrefix;
Logger.Log(Severity.Info, "EXTRACTION STARTING at {0}", DateTime.Now);
stopWatch.Start();
progressMonitor = pm;
PathTransformer = pathTransformer;
}
/// <summary>
/// Start initialization of the analyser.
/// </summary>
/// <param name="roslynArgs">The arguments passed to Roslyn.</param>
/// <returns>A Boolean indicating whether to proceed with extraction.</returns>
public bool BeginInitialize(IEnumerable<string> roslynArgs)
{
return init = LogRoslynArgs(roslynArgs, Extraction.Extractor.Version);
}
/// <summary>
/// End initialization of the analyser.
/// </summary>
/// <param name="commandLineArguments">Arguments passed to csc.</param>
/// <param name="options">Extractor options.</param>
/// <param name="compilation">The Roslyn compilation.</param>
/// <returns>A Boolean indicating whether to proceed with extraction.</returns>
public void EndInitialize(
CSharpCommandLineArguments commandLineArguments,
Options options,
CSharpCompilation compilation)
{
if (!init)
throw new InternalError("EndInitialize called without BeginInitialize returning true");
layout = new Layout();
this.options = options;
this.compilation = compilation;
extractor = new Extraction.Extractor(false, GetOutputName(compilation, commandLineArguments), Logger, PathTransformer);
LogDiagnostics();
SetReferencePaths();
CompilationErrors += FilteredDiagnostics.Count();
}
/// <summary>
/// Constructs the map from assembly string to its filename.
///
/// Roslyn doesn't record the relationship between a filename and its assembly
/// information, so we need to retrieve this information manually.
/// </summary>
private void SetReferencePaths()
{
foreach (var reference in compilation.References.OfType<PortableExecutableReference>())
{
try
{
var refPath = reference.FilePath;
/* This method is significantly faster and more lightweight than using
* System.Reflection.Assembly.ReflectionOnlyLoadFrom. It is also allows
* loading the same assembly from different locations.
*/
using var pereader = new System.Reflection.PortableExecutable.PEReader(new FileStream(refPath, FileMode.Open, FileAccess.Read, FileShare.Read));
var metadata = pereader.GetMetadata();
string assemblyIdentity;
unsafe
{
var reader = new System.Reflection.Metadata.MetadataReader(metadata.Pointer, metadata.Length);
var def = reader.GetAssemblyDefinition();
assemblyIdentity = reader.GetString(def.Name) + " " + def.Version;
}
extractor.SetAssemblyFile(assemblyIdentity, refPath);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
extractor.Message(new Message("Exception reading reference file", reference.FilePath, null, ex.StackTrace));
}
}
}
public void InitializeStandalone(CSharpCompilation compilationIn, CommonOptions options)
{
compilation = compilationIn;
layout = new Layout();
extractor = new Extraction.Extractor(true, null, Logger, PathTransformer);
this.options = options;
LogExtractorInfo(Extraction.Extractor.Version);
SetReferencePaths();
}
private readonly HashSet<string> errorsToIgnore = new HashSet<string>
{
"CS7027", // Code signing failure
"CS1589", // XML referencing not supported
"CS1569" // Error writing XML documentation
};
private IEnumerable<Diagnostic> FilteredDiagnostics
{
get
{
return extractor == null || extractor.Standalone || compilation == null ? Enumerable.Empty<Diagnostic>() :
compilation.
GetDiagnostics().
Where(e => e.Severity >= DiagnosticSeverity.Error && !errorsToIgnore.Contains(e.Id));
}
}
public IEnumerable<string> MissingTypes => extractor.MissingTypes;
public IEnumerable<string> MissingNamespaces => extractor.MissingNamespaces;
/// <summary>
/// Determine the path of the output dll/exe.
/// </summary>
/// <param name="compilation">Information about the compilation.</param>
/// <param name="cancel">Cancellation token required.</param>
/// <returns>The filename.</returns>
private static string GetOutputName(CSharpCompilation compilation,
CSharpCommandLineArguments commandLineArguments)
{
// There's no apparent way to access the output filename from the compilation,
// so we need to re-parse the command line arguments.
if (commandLineArguments.OutputFileName == null)
{
// No output specified: Use name based on first filename
var entry = compilation.GetEntryPoint(System.Threading.CancellationToken.None);
if (entry == null)
{
if (compilation.SyntaxTrees.Length == 0)
throw new InvalidOperationException("No source files seen");
// Probably invalid, but have a go anyway.
var entryPointFile = compilation.SyntaxTrees.First().FilePath;
return Path.ChangeExtension(entryPointFile, ".exe");
}
var entryPointFilename = entry.Locations.First().SourceTree.FilePath;
return Path.ChangeExtension(entryPointFilename, ".exe");
}
return Path.Combine(commandLineArguments.OutputDirectory, commandLineArguments.OutputFileName);
}
/// <summary>
/// Perform an analysis on a source file/syntax tree.
/// </summary>
/// <param name="tree">Syntax tree to analyse.</param>
public void AnalyseTree(SyntaxTree tree)
{
extractionTasks.Add(() => DoExtractTree(tree));
}
/// <summary>
/// Perform an analysis on an assembly.
/// </summary>
/// <param name="assembly">Assembly to analyse.</param>
private void AnalyseReferenceAssembly(PortableExecutableReference assembly)
{
// CIL first - it takes longer.
if (options.CIL)
extractionTasks.Add(() => DoExtractCIL(assembly));
extractionTasks.Add(() => DoAnalyseReferenceAssembly(assembly));
}
private static bool FileIsUpToDate(string src, string dest)
{
return File.Exists(dest) &&
File.GetLastWriteTime(dest) >= File.GetLastWriteTime(src);
}
/// <summary>
/// Extracts compilation-wide entities, such as compilations and compiler diagnostics.
/// </summary>
public void AnalyseCompilation()
{
extractionTasks.Add(() => DoAnalyseCompilation());
}
private void DoAnalyseCompilation()
{
try
{
var assemblyPath = extractor.OutputPath;
var transformedAssemblyPath = PathTransformer.Transform(assemblyPath);
var assembly = compilation.Assembly;
var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath);
var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, options.TrapCompression, discardDuplicates: false);
compilationTrapFile = trapWriter; // Dispose later
var cx = new Context(extractor, compilation.Clone(), trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix);
compilationEntity = Entities.Compilation.Create(cx);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
Logger.Log(Severity.Error, " Unhandled exception analyzing {0}: {1}", "compilation", ex);
}
}
public void LogPerformance(Entities.PerformanceMetrics p) => compilationEntity.PopulatePerformance(p);
/// <summary>
/// Extract an assembly to a new trap file.
/// If the trap file exists, skip extraction to avoid duplicating
/// extraction within the snapshot.
/// </summary>
/// <param name="r">The assembly to extract.</param>
private void DoAnalyseReferenceAssembly(PortableExecutableReference r)
{
try
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var assemblyPath = r.FilePath;
var transformedAssemblyPath = PathTransformer.Transform(assemblyPath);
var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath);
using var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, options.TrapCompression, discardDuplicates: true);
var skipExtraction = options.Cache && File.Exists(trapWriter.TrapFile);
if (!skipExtraction)
{
/* Note on parallel builds:
*
* The trap writer and source archiver both perform atomic moves
* of the file to the final destination.
*
* If the same source file or trap file are generated concurrently
* (by different parallel invocations of the extractor), then
* last one wins.
*
* Specifically, if two assemblies are analysed concurrently in a build,
* then there is a small amount of duplicated work but the output should
* still be correct.
*/
// compilation.Clone() reduces memory footprint by allowing the symbols
// in c to be garbage collected.
Compilation c = compilation.Clone();
if (c.GetAssemblyOrModuleSymbol(r) is IAssemblySymbol assembly)
{
var cx = new Context(extractor, c, trapWriter, new AssemblyScope(assembly, assemblyPath), AddAssemblyTrapPrefix);
foreach (var module in assembly.Modules)
{
AnalyseNamespace(cx, module.GlobalNamespace);
}
Entities.Attribute.ExtractAttributes(cx, assembly, Entities.Assembly.Create(cx, assembly.GetSymbolLocation()));
cx.PopulateAll();
}
}
ReportProgress(assemblyPath, trapWriter.TrapFile, stopwatch.Elapsed, skipExtraction ? AnalysisAction.UpToDate : AnalysisAction.Extracted);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
Logger.Log(Severity.Error, " Unhandled exception analyzing {0}: {1}", r.FilePath, ex);
}
}
private void DoExtractCIL(PortableExecutableReference r)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
CIL.Analyser.ExtractCIL(layout, r.FilePath, Logger, !options.Cache, options.PDB, options.TrapCompression, out var trapFile, out var extracted);
stopwatch.Stop();
ReportProgress(r.FilePath, trapFile, stopwatch.Elapsed, extracted ? AnalysisAction.Extracted : AnalysisAction.UpToDate);
}
private void AnalyseNamespace(Context cx, INamespaceSymbol ns)
{
foreach (var memberNamespace in ns.GetNamespaceMembers())
{
AnalyseNamespace(cx, memberNamespace);
}
foreach (var memberType in ns.GetTypeMembers())
{
Entities.Type.Create(cx, memberType).ExtractRecursive();
}
}
/// <summary>
/// Enqueue all reference analysis tasks.
/// </summary>
public void AnalyseReferences()
{
foreach (var r in compilation.References.OfType<PortableExecutableReference>())
{
AnalyseReferenceAssembly(r);
}
}
// The bulk of the extraction work, potentially executed in parallel.
private readonly List<Action> extractionTasks = new List<Action>();
private void ReportProgress(string src, string output, TimeSpan time, AnalysisAction action)
{
lock (progressMutex)
progressMonitor.Analysed(++taskCount, extractionTasks.Count, src, output, time, action);
}
private void DoExtractTree(SyntaxTree tree)
{
try
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var sourcePath = tree.FilePath;
var transformedSourcePath = PathTransformer.Transform(sourcePath);
var projectLayout = layout.LookupProjectOrNull(transformedSourcePath);
var excluded = projectLayout == null;
var trapPath = excluded ? "" : projectLayout.GetTrapPath(Logger, transformedSourcePath, options.TrapCompression);
var upToDate = false;
if (!excluded)
{
// compilation.Clone() is used to allow symbols to be garbage collected.
using var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedSourcePath, options.TrapCompression, discardDuplicates: false);
upToDate = options.Fast && FileIsUpToDate(sourcePath, trapWriter.TrapFile);
if (!upToDate)
{
var cx = new Context(extractor, compilation.Clone(), trapWriter, new SourceScope(tree), AddAssemblyTrapPrefix);
// Ensure that the file itself is populated in case the source file is totally empty
var root = tree.GetRoot();
Entities.File.Create(cx, root.SyntaxTree.FilePath);
var csNode = (CSharpSyntaxNode)root;
csNode.Accept(new CompilationUnitVisitor(cx));
csNode.Accept(new DirectiveVisitor(cx));
cx.PopulateAll();
CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator);
cx.PopulateAll();
}
}
ReportProgress(sourcePath, trapPath, stopwatch.Elapsed, excluded
? AnalysisAction.Excluded
: upToDate
? AnalysisAction.UpToDate
: AnalysisAction.Extracted);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
extractor.Message(new Message($"Unhandled exception processing syntax tree. {ex.Message}", tree.FilePath, null, ex.StackTrace));
}
}
/// <summary>
/// Run all extraction tasks.
/// </summary>
/// <param name="numberOfThreads">The number of threads to use.</param>
public void PerformExtraction(int numberOfThreads)
{
Parallel.Invoke(
new ParallelOptions { MaxDegreeOfParallelism = numberOfThreads },
extractionTasks.ToArray());
}
public void Dispose()
{
compilationTrapFile?.Dispose();
stopWatch.Stop();
Logger.Log(Severity.Info, " Peak working set = {0} MB", Process.GetCurrentProcess().PeakWorkingSet64 / (1024 * 1024));
if (TotalErrors > 0)
Logger.Log(Severity.Info, "EXTRACTION FAILED with {0} error{1} in {2}", TotalErrors, TotalErrors == 1 ? "" : "s", stopWatch.Elapsed);
else
Logger.Log(Severity.Info, "EXTRACTION SUCCEEDED in {0}", stopWatch.Elapsed);
Logger.Dispose();
}
/// <summary>
/// Number of errors encountered during extraction.
/// </summary>
public int ExtractorErrors => extractor == null ? 0 : extractor.Errors;
/// <summary>
/// Number of errors encountered by the compiler.
/// </summary>
public int CompilationErrors { get; set; }
/// <summary>
/// Total number of errors reported.
/// </summary>
public int TotalErrors => CompilationErrors + ExtractorErrors;
/// <summary>
/// Logs information about the extractor.
/// </summary>
public void LogExtractorInfo(string extractorVersion)
{
Logger.Log(Severity.Info, " Extractor: {0}", Environment.GetCommandLineArgs().First());
Logger.Log(Severity.Info, " Extractor version: {0}", extractorVersion);
Logger.Log(Severity.Info, " Current working directory: {0}", Directory.GetCurrentDirectory());
}
/// <summary>
/// Logs information about the extractor, as well as the arguments to Roslyn.
/// </summary>
/// <param name="roslynArgs">The arguments passed to Roslyn.</param>
/// <returns>A Boolean indicating whether the same arguments have been logged previously.</returns>
private bool LogRoslynArgs(IEnumerable<string> roslynArgs, string extractorVersion)
{
LogExtractorInfo(extractorVersion);
Logger.Log(Severity.Info, $" Arguments to Roslyn: {string.Join(' ', roslynArgs)}");
var tempFile = Extractor.GetCSharpArgsLogPath(Path.GetRandomFileName());
bool argsWritten;
using (var streamWriter = new StreamWriter(new FileStream(tempFile, FileMode.Append, FileAccess.Write)))
{
streamWriter.WriteLine($"# Arguments to Roslyn: {string.Join(' ', roslynArgs.Where(arg => !arg.StartsWith('@')))}");
argsWritten = roslynArgs.WriteCommandLine(streamWriter);
}
var hash = FileUtils.ComputeFileHash(tempFile);
var argsFile = Extractor.GetCSharpArgsLogPath(hash);
if (argsWritten)
Logger.Log(Severity.Info, $" Arguments have been written to {argsFile}");
if (File.Exists(argsFile))
{
try
{
File.Delete(tempFile);
}
catch (IOException e)
{
Logger.Log(Severity.Warning, $" Failed to remove {tempFile}: {e.Message}");
}
return false;
}
try
{
File.Move(tempFile, argsFile);
}
catch (IOException e)
{
Logger.Log(Severity.Warning, $" Failed to move {tempFile} to {argsFile}: {e.Message}");
}
return true;
}
/// <summary>
/// Logs detailed information about this invocation,
/// in the event that errors were detected.
/// </summary>
/// <returns>A Boolean indicating whether to proceed with extraction.</returns>
public void LogDiagnostics()
{
foreach (var error in FilteredDiagnostics)
{
Logger.Log(Severity.Error, " Compilation error: {0}", error);
}
if (FilteredDiagnostics.Any())
{
foreach (var reference in compilation.References)
{
Logger.Log(Severity.Info, " Resolved reference {0}", reference.Display);
}
}
}
}
/// <summary>
/// What action was performed when extracting a file.
/// </summary>
public enum AnalysisAction
{
Extracted,
UpToDate,
Excluded
}
/// <summary>
/// Callback for various extraction events.
/// (Used for display of progress).
/// </summary>
public interface IProgressMonitor
{
/// <summary>
/// Callback that a particular item has been analysed.
/// </summary>
/// <param name="item">The item number being processed.</param>
/// <param name="total">The total number of items to process.</param>
/// <param name="source">The name of the item, e.g. a source file.</param>
/// <param name="output">The name of the item being output, e.g. a trap file.</param>
/// <param name="time">The time to extract the item.</param>
/// <param name="action">What action was taken for the file.</param>
void Analysed(int item, int total, string source, string output, TimeSpan time, AnalysisAction action);
/// <summary>
/// A "using namespace" directive was seen but the given
/// namespace could not be found.
/// Only called once for each @namespace.
/// </summary>
/// <param name="namespace"></param>
void MissingNamespace(string @namespace);
/// <summary>
/// An ErrorType was found.
/// Called once for each type name.
/// </summary>
/// <param name="type">The full/partial name of the type.</param>
void MissingType(string type);
/// <summary>
/// Report a summary of missing entities.
/// </summary>
/// <param name="types">The number of missing types.</param>
/// <param name="namespaces">The number of missing using namespace declarations.</param>
void MissingSummary(int types, int namespaces);
}
}

View File

@@ -26,7 +26,7 @@ namespace Semmle.Extraction.CSharp
private readonly Dictionary<Label, Key> duplicationGuardKeys = new Dictionary<Label, Key>();
private Key GetDuplicationGuardKey(Label label)
private Key? GetDuplicationGuardKey(Label label)
{
if (duplicationGuardKeys.TryGetValue(label, out var duplicationGuardKey))
return duplicationGuardKey;
@@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp
private class LocationComparer : IComparer<Location>
{
public int Compare(Location l1, Location l2) => CommentProcessor.Compare(l1, l2);
public int Compare(Location? l1, Location? l2) => CommentProcessor.Compare(l1, l2);
}
/// <summary>
@@ -44,7 +44,7 @@ namespace Semmle.Extraction.CSharp
/// <param name="l1">First location</param>
/// <param name="l2">Second location</param>
/// <returns>&lt;0 if l1 before l2, &gt;0 if l1 after l2, else 0.</returns>
private static int Compare(Location l1, Location l2)
private static int Compare(Location? l1, Location? l2)
{
if (object.ReferenceEquals(l1, l2))
return 0;
@@ -68,7 +68,7 @@ namespace Semmle.Extraction.CSharp
/// <param name="elementLabel">The label of the element in the trap file.</param>
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any.</param>
/// <param name="loc">The location of the element.</param>
public void AddElement(Label elementLabel, Key duplicationGuardKey, Location loc)
public void AddElement(Label elementLabel, Key? duplicationGuardKey, Location? loc)
{
if (loc != null && loc.IsInSource)
elements[loc] = elementLabel;
@@ -265,7 +265,7 @@ namespace Semmle.Extraction.CSharp
CommentBindingCallback cb
)
{
Comments.CommentBlock block = null;
Comments.CommentBlock? block = null;
// Iterate comments until the commentEnumerator has gone past nextElement
while (nextElement == null || Compare(commentEnumerator.Current.Value.Location, nextElement.Value.Key) < 0)
@@ -350,5 +350,5 @@ namespace Semmle.Extraction.CSharp
/// <param name="duplicationGuardKey">The duplication guard key of the element, if any</param>
/// <param name="commentBlock">The comment block associated with the element</param>
/// <param name="binding">The relationship between the commentblock and the element</param>
internal delegate void CommentBindingCallback(Label elementLabel, Key duplicationGuardKey, Comments.CommentBlock commentBlock, CommentBinding binding);
internal delegate void CommentBindingCallback(Label elementLabel, Key? duplicationGuardKey, Comments.CommentBlock commentBlock, CommentBinding binding);
}

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// Gets the property symbol associated accessor `symbol`, or `null`
/// if there is no associated symbol.
/// </summary>
public static IPropertySymbol GetPropertySymbol(IMethodSymbol symbol)
public static IPropertySymbol? GetPropertySymbol(IMethodSymbol symbol)
{
// Usually, the property/indexer can be fetched from the associated symbol
if (symbol.AssociatedSymbol is IPropertySymbol prop)
@@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// <summary>
/// Gets the property symbol associated with this accessor.
/// </summary>
private IPropertySymbol PropertySymbol => GetPropertySymbol(Symbol);
private IPropertySymbol? PropertySymbol => GetPropertySymbol(Symbol);
public new Accessor OriginalDefinition => Create(Context, Symbol.OriginalDefinition);
@@ -37,7 +37,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
PopulateMethod(trapFile);
PopulateModifiers(trapFile);
ContainingType.PopulateGenerics();
ContainingType!.PopulateGenerics();
var prop = PropertySymbol;
if (prop == null)
@@ -52,12 +52,12 @@ namespace Semmle.Extraction.CSharp.Entities
if (SymbolEqualityComparer.Default.Equals(Symbol, prop.GetMethod))
{
kind = 1;
unboundAccessor = Create(Context, prop.OriginalDefinition.GetMethod);
unboundAccessor = Create(Context, prop.OriginalDefinition.GetMethod!);
}
else if (SymbolEqualityComparer.Default.Equals(Symbol, prop.SetMethod))
{
kind = 2;
unboundAccessor = Create(Context, prop.OriginalDefinition.SetMethod);
unboundAccessor = Create(Context, prop.OriginalDefinition.SetMethod!);
}
else
{

View File

@@ -6,19 +6,18 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class Assembly : Extraction.Entities.Location
{
// todo: this can be changed to an override after the .NET 5 upgrade
private new Context Context => (Context)base.Context;
public override Context Context => (Context)base.Context;
private readonly string assemblyPath;
private readonly IAssemblySymbol assembly;
private Assembly(Context cx, Microsoft.CodeAnalysis.Location init)
private Assembly(Context cx, Microsoft.CodeAnalysis.Location? init)
: base(cx, init)
{
if (init == null)
{
// This is the output assembly
assemblyPath = cx.Extractor.OutputPath;
assemblyPath = ((TracingExtractor)cx.Extractor).OutputPath;
assembly = cx.Compilation.Assembly;
}
else
@@ -44,7 +43,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override int GetHashCode() =>
Symbol == null ? 91187354 : Symbol.GetHashCode();
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj is Assembly other && other.GetType() == typeof(Assembly))
return Equals(Symbol, other.Symbol);
@@ -54,18 +53,18 @@ namespace Semmle.Extraction.CSharp.Entities
public static Extraction.Entities.Location Create(Context cx, Microsoft.CodeAnalysis.Location loc) => AssemblyConstructorFactory.Instance.CreateEntity(cx, loc, loc);
private class AssemblyConstructorFactory : CachedEntityFactory<Microsoft.CodeAnalysis.Location, Assembly>
private class AssemblyConstructorFactory : CachedEntityFactory<Microsoft.CodeAnalysis.Location?, Assembly>
{
public static AssemblyConstructorFactory Instance { get; } = new AssemblyConstructorFactory();
public override Assembly Create(Context cx, Microsoft.CodeAnalysis.Location init) => new Assembly(cx, init);
public override Assembly Create(Context cx, Microsoft.CodeAnalysis.Location? init) => new Assembly(cx, init);
}
private static readonly object outputAssemblyCacheKey = new object();
public static Assembly CreateOutputAssembly(Context cx)
{
if (cx.Extractor.OutputPath == null)
if (cx.Extractor.Standalone)
throw new InternalError("Attempting to create the output assembly in standalone extraction mode");
return AssemblyConstructorFactory.Instance.CreateEntity(cx, outputAssemblyCacheKey, null);
}

View File

@@ -10,7 +10,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
bool IExpressionParentEntity.IsTopLevelParent => true;
private readonly AttributeSyntax attributeSyntax;
private readonly AttributeSyntax? attributeSyntax;
private readonly IEntity entity;
private Attribute(Context cx, AttributeData attributeData, IEntity entity)
@@ -53,7 +53,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (attributeSyntax is object)
{
if (Context.Extractor.OutputPath != null)
if (!Context.Extractor.Standalone)
{
trapFile.attribute_location(this, Assembly.CreateOutputAssembly(Context));
}
@@ -93,7 +93,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
var expr = CreateExpressionFromArgument(
namedArgument.Value,
attributeSyntax?.ArgumentList.Arguments.Single(a => a.NameEquals?.Name?.Identifier.Text == namedArgument.Key).Expression,
attributeSyntax?.ArgumentList?.Arguments.Single(a => a.NameEquals?.Name?.Identifier.Text == namedArgument.Key).Expression,
this,
childIndex++);
@@ -104,7 +104,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
private Expression CreateExpressionFromArgument(TypedConstant constant, ExpressionSyntax syntax, IExpressionParentEntity parent,
private Expression? CreateExpressionFromArgument(TypedConstant constant, ExpressionSyntax? syntax, IExpressionParentEntity parent,
int childIndex)
{
return syntax is null
@@ -114,11 +114,14 @@ namespace Semmle.Extraction.CSharp.Entities
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
public override Microsoft.CodeAnalysis.Location ReportingLocation => attributeSyntax?.Name.GetLocation();
public override Microsoft.CodeAnalysis.Location? ReportingLocation => attributeSyntax?.Name.GetLocation();
private Semmle.Extraction.Entities.Location? location;
private Semmle.Extraction.Entities.Location location;
private Semmle.Extraction.Entities.Location Location =>
location ?? (location = Context.CreateLocation(attributeSyntax is null ? entity.ReportingLocation : attributeSyntax.Name.GetLocation()));
location ??= Context.CreateLocation(attributeSyntax is null
? entity.ReportingLocation
: attributeSyntax.Name.GetLocation());
public override bool NeedsPopulation => true;

View File

@@ -1,11 +1,11 @@
namespace Semmle.Extraction.CSharp.Entities
{
internal abstract class CachedEntity<T> : Extraction.CachedEntity<T>
internal abstract class CachedEntity<T> : Extraction.CachedEntity<T> where T : notnull
{
// todo: this can be changed to an override after the .NET 5 upgrade
protected new Context Context => (Context)base.Context;
public override Context Context => (Context)base.Context;
protected CachedEntity(Context context, T symbol) : base(context, symbol)
protected CachedEntity(Context context, T symbol)
: base(context, symbol)
{
}
}

View File

@@ -9,17 +9,14 @@ using System.Reflection.Metadata.Ecma335;
namespace Semmle.Extraction.CSharp.Entities
{
internal abstract class CachedSymbol<T> : CachedEntity<T> where T : ISymbol
internal abstract class CachedSymbol<T> : CachedEntity<T> where T : class, ISymbol
{
// todo: this can be changed to an override after the .NET 5 upgrade
protected new Context Context => (Context)base.Context;
protected CachedSymbol(Context cx, T init)
: base(cx, init)
{
}
public virtual Type ContainingType => Symbol.ContainingType != null ? Type.Create(Context, Symbol.ContainingType) : null;
public virtual Type? ContainingType => Symbol.ContainingType != null ? Type.Create(Context, Symbol.ContainingType) : null;
public void PopulateModifiers(TextWriter trapFile)
{
@@ -68,12 +65,12 @@ namespace Semmle.Extraction.CSharp.Entities
/// The location which is stored in the database and is used when highlighing source code.
/// It's generally short, e.g. a method name.
/// </summary>
public override Microsoft.CodeAnalysis.Location ReportingLocation => Symbol.Locations.FirstOrDefault();
public override Microsoft.CodeAnalysis.Location? ReportingLocation => Symbol.Locations.FirstOrDefault();
/// <summary>
/// The full text span of the entity, e.g. for binding comments.
/// </summary>
public virtual Microsoft.CodeAnalysis.Location FullLocation => Symbol.Locations.FirstOrDefault();
public virtual Microsoft.CodeAnalysis.Location? FullLocation => Symbol.Locations.FirstOrDefault();
public virtual IEnumerable<Extraction.Entities.Location> Locations
{
@@ -84,7 +81,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
// Some built in operators lack locations, so loc is null.
yield return Context.CreateLocation(ReportingLocation);
if (Context.Extractor.OutputPath != null && loc.Kind == LocationKind.SourceFile)
if (!Context.Extractor.Standalone && loc.Kind == LocationKind.SourceFile)
yield return Assembly.CreateOutputAssembly(Context);
}
}
@@ -102,7 +99,7 @@ namespace Semmle.Extraction.CSharp.Entities
protected virtual T BodyDeclaringSymbol => Symbol;
public BlockSyntax Block
public BlockSyntax? Block
{
get
{
@@ -113,7 +110,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public ExpressionSyntax ExpressionBody
public ExpressionSyntax? ExpressionBody
{
get
{
@@ -139,7 +136,7 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.metadata_handle(this, Location, MetadataTokens.GetToken(handle.Value));
}
private static System.Reflection.PropertyInfo GetPropertyInfo(object o, string name)
private static System.Reflection.PropertyInfo? GetPropertyInfo(object o, string name)
{
return o.GetType().GetProperty(name, System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.GetProperty);
}

View File

@@ -1,5 +1,6 @@
using Semmle.Extraction.Entities;
using System.IO;
using System;
namespace Semmle.Extraction.CSharp.Entities
{
@@ -18,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities
public string Text { get { return Symbol.Item2; } }
public string RawText { get; private set; }
private Location location;
private Location? location;
public override void Populate(TextWriter trapFile)
{
@@ -27,7 +28,7 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.commentline_location(this, location);
}
public override Microsoft.CodeAnalysis.Location ReportingLocation => location.Symbol;
public override Microsoft.CodeAnalysis.Location? ReportingLocation => location?.Symbol;
public override bool NeedsPopulation => true;

View File

@@ -25,9 +25,11 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
#nullable disable warnings
private Compilation(Context cx) : base(cx, null)
{
}
#nullable restore warnings
public override void Populate(TextWriter trapFile)
{
@@ -54,7 +56,8 @@ namespace Semmle.Extraction.CSharp.Entities
index = 0;
foreach (var file in Context.Compilation.References
.OfType<PortableExecutableReference>()
.Select(r => File.Create(Context, r.FilePath)))
.Where(r => r.FilePath is object)
.Select(r => File.Create(Context, r.FilePath!)))
{
trapFile.compilation_referencing_files(this, index++, file);
}
@@ -90,11 +93,11 @@ namespace Semmle.Extraction.CSharp.Entities
public override bool NeedsPopulation => Context.IsAssemblyScope;
private class CompilationFactory : CachedEntityFactory<object, Compilation>
private class CompilationFactory : CachedEntityFactory<object?, Compilation>
{
public static CompilationFactory Instance { get; } = new CompilationFactory();
public override Compilation Create(Context cx, object init) => new Compilation(cx);
public override Compilation Create(Context cx, object? init) => new Compilation(cx);
}
private static readonly object compilationCacheKey = new object();

View File

@@ -5,6 +5,7 @@ using System.Linq;
using Microsoft.CodeAnalysis.CSharp;
using Semmle.Extraction.Entities;
using System.IO;
using System.Diagnostics.CodeAnalysis;
namespace Semmle.Extraction.CSharp.Entities
{
@@ -17,7 +18,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
PopulateMethod(trapFile);
PopulateModifiers(trapFile);
ContainingType.PopulateGenerics();
ContainingType!.PopulateGenerics();
trapFile.constructors(this, Symbol.ContainingType.Name, ContainingType, (Constructor)OriginalDefinition);
trapFile.constructor_location(this, Location);
@@ -48,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities
switch (initializer.Kind())
{
case SyntaxKind.BaseConstructorInitializer:
initializerType = Symbol.ContainingType.BaseType;
initializerType = Symbol.ContainingType.BaseType!;
break;
case SyntaxKind.ThisConstructorInitializer:
initializerType = Symbol.ContainingType;
@@ -69,8 +70,7 @@ namespace Semmle.Extraction.CSharp.Entities
var init = new Expression(initInfo);
var target = Constructor.Create(Context, (IMethodSymbol)symbolInfo.Symbol);
var target = Constructor.Create(Context, (IMethodSymbol?)symbolInfo.Symbol);
if (target == null)
{
Context.ModelError(Symbol, "Unable to resolve call");
@@ -86,7 +86,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
private ConstructorDeclarationSyntax Syntax
private ConstructorDeclarationSyntax? Syntax
{
get
{
@@ -97,7 +97,8 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public static new Constructor Create(Context cx, IMethodSymbol constructor)
[return: NotNullIfNotNull("constructor")]
public static new Constructor? Create(Context cx, IMethodSymbol? constructor)
{
if (constructor == null)
return null;
@@ -116,17 +117,17 @@ namespace Semmle.Extraction.CSharp.Entities
{
if (Symbol.IsStatic)
trapFile.Write("static");
trapFile.WriteSubId(ContainingType);
trapFile.WriteSubId(ContainingType!);
AddParametersToId(Context, trapFile, Symbol);
trapFile.Write(";constructor");
}
private ConstructorDeclarationSyntax GetSyntax() =>
private ConstructorDeclarationSyntax? GetSyntax() =>
Symbol.DeclaringSyntaxReferences.Select(r => r.GetSyntax()).OfType<ConstructorDeclarationSyntax>().FirstOrDefault();
public override Microsoft.CodeAnalysis.Location FullLocation => ReportingLocation;
public override Microsoft.CodeAnalysis.Location? FullLocation => ReportingLocation;
public override Microsoft.CodeAnalysis.Location ReportingLocation
public override Microsoft.CodeAnalysis.Location? ReportingLocation
{
get
{
@@ -138,7 +139,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (Symbol.IsImplicitlyDeclared)
{
return ContainingType.ReportingLocation;
return ContainingType!.ReportingLocation;
}
return Symbol.ContainingType.Locations.FirstOrDefault();

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities
public static new Conversion Create(Context cx, IMethodSymbol symbol) =>
ConversionFactory.Instance.CreateEntityFromSymbol(cx, symbol);
public override Microsoft.CodeAnalysis.Location ReportingLocation
public override Microsoft.CodeAnalysis.Location? ReportingLocation
{
get
{

View File

@@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
PopulateMethod(trapFile);
PopulateModifiers(trapFile);
ContainingType.PopulateGenerics();
ContainingType!.PopulateGenerics();
trapFile.destructors(this, string.Format("~{0}", Symbol.ContainingType.Name), ContainingType, OriginalDefinition(Context, this, Symbol));
trapFile.destructor_location(this, Location);

View File

@@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(ContainingType);
trapFile.WriteSubId(ContainingType!);
trapFile.Write('.');
Method.AddExplicitInterfaceQualifierToId(Context, trapFile, Symbol.ExplicitInterfaceImplementations);
trapFile.Write(Symbol.Name);
@@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateNullability(trapFile, Symbol.GetAnnotatedType());
var type = Type.Create(Context, Symbol.Type);
trapFile.events(this, Symbol.GetName(), ContainingType, type.TypeRef, Create(Context, Symbol.OriginalDefinition));
trapFile.events(this, Symbol.GetName(), ContainingType!, type.TypeRef, Create(Context, Symbol.OriginalDefinition));
var adder = Symbol.AddMethod;
var remover = Symbol.RemoveMethod;
@@ -47,7 +47,7 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.explicitly_implements(this, explicitInterface.TypeRef);
foreach (var syntax in declSyntaxReferences.OfType<EventDeclarationSyntax>())
TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier.Name, this, explicitInterface);
TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier!.Name, this, explicitInterface);
}
foreach (var l in Locations)

View File

@@ -11,12 +11,12 @@ namespace Semmle.Extraction.CSharp.Entities
/// <summary>
/// Gets the event symbol associated with this accessor.
/// </summary>
private IEventSymbol EventSymbol => Symbol.AssociatedSymbol as IEventSymbol;
private IEventSymbol? EventSymbol => Symbol.AssociatedSymbol as IEventSymbol;
public override void Populate(TextWriter trapFile)
{
PopulateMethod(trapFile);
ContainingType.PopulateGenerics();
ContainingType!.PopulateGenerics();
var @event = EventSymbol;
if (@event == null)
@@ -31,12 +31,12 @@ namespace Semmle.Extraction.CSharp.Entities
if (SymbolEqualityComparer.Default.Equals(Symbol, @event.AddMethod))
{
kind = 1;
unboundAccessor = Create(Context, @event.OriginalDefinition.AddMethod);
unboundAccessor = Create(Context, @event.OriginalDefinition.AddMethod!);
}
else if (SymbolEqualityComparer.Default.Equals(Symbol, @event.RemoveMethod))
{
kind = 2;
unboundAccessor = Create(Context, @event.OriginalDefinition.RemoveMethod);
unboundAccessor = Create(Context, @event.OriginalDefinition.RemoveMethod!);
}
else
{

View File

@@ -57,7 +57,7 @@ namespace Semmle.Extraction.CSharp.Entities
type.PopulateGenerics();
}
public override Microsoft.CodeAnalysis.Location ReportingLocation => Location.Symbol;
public override Location? ReportingLocation => Location.Symbol;
bool IExpressionParentEntity.IsTopLevelParent => false;
@@ -66,7 +66,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// </summary>
/// <param name="obj">The value.</param>
/// <returns>The string representation.</returns>
public static string ValueAsString(object value)
public static string ValueAsString(object? value)
{
return value == null
? "null"
@@ -74,7 +74,7 @@ namespace Semmle.Extraction.CSharp.Entities
? b
? "true"
: "false"
: value.ToString();
: value.ToString()!;
}
/// <summary>
@@ -118,10 +118,11 @@ namespace Semmle.Extraction.CSharp.Entities
/// <summary>
/// Creates a generated expression from a typed constant.
/// </summary>
public static Expression CreateGenerated(Context cx, TypedConstant constant, IExpressionParentEntity parent,
int childIndex, Semmle.Extraction.Entities.Location location)
public static Expression? CreateGenerated(Context cx, TypedConstant constant, IExpressionParentEntity parent,
int childIndex, Extraction.Entities.Location location)
{
if (constant.IsNull)
if (constant.IsNull ||
constant.Type is null)
{
return Literal.CreateGeneratedNullLiteral(cx, parent, childIndex, location);
}
@@ -132,11 +133,11 @@ namespace Semmle.Extraction.CSharp.Entities
return Literal.CreateGenerated(cx, parent, childIndex, constant.Type, constant.Value, location);
case TypedConstantKind.Enum:
// Enum value is generated in the following format: (Enum)value
Action<Expression, int> createChild = (parent, index) => Literal.CreateGenerated(cx, parent, index, ((INamedTypeSymbol)constant.Type).EnumUnderlyingType, constant.Value, location);
var cast = Cast.CreateGenerated(cx, parent, childIndex, constant.Type, constant.Value, createChild, location);
Action<Expression, int> createChild = (parent, index) => Literal.CreateGenerated(cx, parent, index, ((INamedTypeSymbol)constant.Type).EnumUnderlyingType!, constant.Value, location);
var cast = Cast.CreateGenerated(cx, parent, childIndex, constant.Type!, constant.Value, createChild, location);
return cast;
case TypedConstantKind.Type:
var type = ((ITypeSymbol)constant.Value).OriginalDefinition;
var type = ((ITypeSymbol)constant.Value!).OriginalDefinition;
return TypeOf.CreateGenerated(cx, parent, childIndex, type, location);
case TypedConstantKind.Array:
// Single dimensional arrays are in the following format:
@@ -145,6 +146,7 @@ namespace Semmle.Extraction.CSharp.Entities
//
// itemI is generated recursively.
return NormalArrayCreation.CreateGenerated(cx, parent, childIndex, constant.Type, constant.Values, location);
case TypedConstantKind.Error:
default:
cx.ExtractionError("Couldn't extract constant in attribute", constant.ToString(), location);
return null;
@@ -242,7 +244,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// <returns>The qualifier of the conditional access.</returns>
protected static ExpressionSyntax FindConditionalQualifier(ExpressionSyntax node)
{
for (SyntaxNode n = node; n != null; n = n.Parent)
for (SyntaxNode? n = node; n != null; n = n.Parent)
{
if (n.Parent is ConditionalAccessExpressionSyntax conditionalAccess &&
conditionalAccess.WhenNotNull == n)

View File

@@ -15,10 +15,10 @@ namespace Semmle.Extraction.CSharp.Entities
public IExpressionParentEntity Parent { get; }
public int Child { get; }
public bool IsCompilerGenerated { get; }
public string ExprValue { get; }
public string? ExprValue { get; }
public ExpressionInfo(Context cx, AnnotatedTypeSymbol? type, Extraction.Entities.Location location, ExprKind kind,
IExpressionParentEntity parent, int child, bool isCompilerGenerated, string value)
IExpressionParentEntity parent, int child, bool isCompilerGenerated, string? value)
{
Context = cx;
Type = type;

View File

@@ -74,7 +74,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
private Microsoft.CodeAnalysis.Location location;
private Microsoft.CodeAnalysis.Location? location;
public Microsoft.CodeAnalysis.Location CodeAnalysisLocation
{
@@ -92,7 +92,7 @@ namespace Semmle.Extraction.CSharp.Entities
public SemanticModel Model => Context.GetModel(Node);
public string ExprValue
public string? ExprValue
{
get
{
@@ -111,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
private Extraction.Entities.Location cachedLocation;
private Extraction.Entities.Location? cachedLocation;
public Extraction.Entities.Location Location
{

View File

@@ -21,9 +21,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
{
protected ExplicitArrayCreation(ExpressionNodeInfo info) : base(info.SetKind(ExprKind.ARRAY_CREATION)) { }
protected abstract ArrayTypeSyntax TypeSyntax { get; }
protected abstract ArrayTypeSyntax? TypeSyntax { get; }
public abstract InitializerExpressionSyntax Initializer { get; }
public abstract InitializerExpressionSyntax? Initializer { get; }
protected override void PopulateExpression(TextWriter trapFile)
{
@@ -32,6 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
if (TypeSyntax is null)
{
Context.ModelError(Syntax, "Array has unexpected type syntax");
return;
}
var firstLevelSizes = TypeSyntax.RankSpecifiers.First()?.Sizes ?? SyntaxFactory.SeparatedList<ExpressionSyntax>();
@@ -60,7 +61,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
TypeMention.Create(Context, TypeSyntax, this, Type);
}
private void SetArraySizes(InitializerExpressionSyntax initializer, int rank)
private void SetArraySizes(InitializerExpressionSyntax? initializer, int rank)
{
for (var level = 0; level < rank; level++)
{
@@ -82,7 +83,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
protected override ArrayTypeSyntax TypeSyntax => Syntax.Type;
public override InitializerExpressionSyntax Initializer => Syntax.Initializer;
public override InitializerExpressionSyntax? Initializer => Syntax.Initializer;
public static Expression Create(ExpressionNodeInfo info) => new NormalArrayCreation(info).TryPopulate();
@@ -122,9 +123,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
{
private StackAllocArrayCreation(ExpressionNodeInfo info) : base(info) { }
protected override ArrayTypeSyntax TypeSyntax => Syntax.Type as ArrayTypeSyntax;
protected override ArrayTypeSyntax? TypeSyntax => Syntax.Type as ArrayTypeSyntax;
public override InitializerExpressionSyntax Initializer => Syntax.Initializer;
public override InitializerExpressionSyntax? Initializer => Syntax.Initializer;
protected override void PopulateExpression(TextWriter trapFile)
{

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
public override Microsoft.CodeAnalysis.Location ReportingLocation => Syntax.GetLocation();
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, object value, Action<Expression, int> createChild, Extraction.Entities.Location location)
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, Microsoft.CodeAnalysis.ITypeSymbol type, object? value, Action<Expression, int> createChild, Extraction.Entities.Location location)
{
var info = new ExpressionInfo(
cx,

View File

@@ -42,7 +42,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
}
}
public sealed override Microsoft.CodeAnalysis.Location ReportingLocation => base.ReportingLocation;
public sealed override Microsoft.CodeAnalysis.Location? ReportingLocation => base.ReportingLocation;
private static ExprKind GetKind(Context cx, ExpressionSyntax qualifier)
{

View File

@@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
}
var child = -1;
string memberName = null;
string? memberName = null;
var target = TargetSymbol;
switch (Syntax.Expression)
{
@@ -54,11 +54,15 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
if (target != null && !target.IsStatic)
{
// Implicit `this` qualifier; add explicitly
if (Context.GetModel(Syntax).GetEnclosingSymbol(Location.Symbol.SourceSpan.Start) is IMethodSymbol callingMethod)
if (Location.Symbol is object &&
Context.GetModel(Syntax).GetEnclosingSymbol(Location.Symbol.SourceSpan.Start) is IMethodSymbol callingMethod)
{
This.CreateImplicit(Context, callingMethod.ContainingType, Location, this, child++);
}
else
{
Context.ModelError(Syntax, "Couldn't determine implicit this type");
}
}
else
{
@@ -105,7 +109,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
public SymbolInfo SymbolInfo => info.SymbolInfo;
public IMethodSymbol TargetSymbol
public IMethodSymbol? TargetSymbol
{
get
{
@@ -144,7 +148,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return IsDelegateLikeCall(info, IsDelegateInvoke);
}
private static bool IsDelegateLikeCall(ExpressionNodeInfo info, Func<ISymbol, bool> check)
private static bool IsDelegateLikeCall(ExpressionNodeInfo info, Func<ISymbol?, bool> check)
{
var si = info.SymbolInfo;
@@ -167,13 +171,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return check(si.Symbol);
}
private static bool IsFunctionPointer(ISymbol symbol)
private static bool IsFunctionPointer(ISymbol? symbol)
{
return symbol != null &&
symbol.Kind == SymbolKind.FunctionPointerType;
}
private static bool IsDelegateInvoke(ISymbol symbol)
private static bool IsDelegateInvoke(ISymbol? symbol)
{
return symbol != null &&
symbol.Kind == SymbolKind.Method &&

View File

@@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
private void VisitParameter(ParameterSyntax p)
{
var symbol = Context.GetModel(p).GetDeclaredSymbol(p);
var symbol = Context.GetModel(p).GetDeclaredSymbol(p)!;
Parameter.Create(Context, symbol, this);
}

View File

@@ -35,7 +35,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return GetExprKind(type, info.Node, info.Context);
}
private static ExprKind GetExprKind(ITypeSymbol type, ExpressionSyntax expr, Context context)
private static ExprKind GetExprKind(ITypeSymbol? type, ExpressionSyntax? expr, Context context)
{
switch (type?.SpecialType)
{
@@ -83,7 +83,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
}
}
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object value,
public static Expression CreateGenerated(Context cx, IExpressionParentEntity parent, int childIndex, ITypeSymbol type, object? value,
Extraction.Entities.Location location)
{
var info = new ExpressionInfo(

View File

@@ -6,7 +6,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
{
internal class MemberAccess : Expression
{
private MemberAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, ISymbol target) : base(info)
private MemberAccess(ExpressionNodeInfo info, ExpressionSyntax qualifier, ISymbol? target) : base(info)
{
var trapFile = info.Context.TrapWriter.Writer;
Qualifier = Create(Context, qualifier, this, -1);

View File

@@ -23,7 +23,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
if (target == null && symbolInfo.CandidateReason == CandidateReason.OverloadResolutionFailure)
{
// The expression is probably a cast
target = info.Context.GetSymbolInfo((CSharpSyntaxNode)info.Node.Parent).Symbol;
target = info.Context.GetSymbolInfo((CSharpSyntaxNode)info.Node.Parent!).Symbol;
}
if (target == null && (symbolInfo.CandidateReason == CandidateReason.Ambiguous || symbolInfo.CandidateReason == CandidateReason.MemberGroup))

View File

@@ -18,22 +18,25 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
protected override void PopulateExpression(TextWriter trapFile)
{
var target = Context.GetSymbolInfo(Syntax);
var method = (IMethodSymbol)target.Symbol;
var method = (IMethodSymbol?)target.Symbol;
if (method != null)
{
trapFile.expr_call(this, Method.Create(Context, method));
}
var child = 0;
var objectInitializer = Syntax.Initializers.Any() ?
new Expression(new ExpressionInfo(Context, Type, Location, ExprKind.OBJECT_INIT, this, -1, false, null)) :
null;
if (!Syntax.Initializers.Any())
{
return;
}
var objectInitializer = new Expression(new ExpressionInfo(Context, Type, Location, ExprKind.OBJECT_INIT, this, -1, false, null));
foreach (var init in Syntax.Initializers)
{
// Create an "assignment"
var property = Context.GetModel(init).GetDeclaredSymbol(init);
var property = Context.GetModel(init).GetDeclaredSymbol(init)!;
var propEntity = Property.Create(Context, property);
var type = property.GetAnnotatedType();
var loc = Context.CreateLocation(init.GetLocation());

View File

@@ -14,6 +14,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
foreach (var sub in pp.Subpatterns)
{
var p = Expressions.Pattern.Create(cx, sub.Pattern, this, child++);
if (sub.NameColon is null)
{
Context.ModelError(sub, "Expected to find 'Name:' in pattern.");
continue;
}
trapFile.exprorstmt_name(p, sub.NameColon.Name.ToString());
}
}

View File

@@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
SyntaxKind.GreaterThanEqualsToken => ExprKind.GE_PATTERN,
SyntaxKind.LessThanToken => ExprKind.LT_PATTERN,
SyntaxKind.GreaterThanToken => ExprKind.GT_PATTERN,
_ => throw new InternalError(operatorToken.Parent, $"Relation pattern with operator token '{operatorToken.Kind()}' is not supported."),
_ => throw new InternalError(operatorToken.Parent!, $"Relation pattern with operator token '{operatorToken.Kind()}' is not supported."),
};
}
}

View File

@@ -21,7 +21,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
/// </remarks>
private class QueryCall : Expression
{
public QueryCall(Context cx, IMethodSymbol method, SyntaxNode clause, IExpressionParentEntity parent, int child)
public QueryCall(Context cx, IMethodSymbol? method, SyntaxNode clause, IExpressionParentEntity parent, int child)
: base(new ExpressionInfo(cx, method?.GetAnnotatedReturnType(),
cx.CreateLocation(clause.GetLocation()),
ExprKind.METHOD_INVOCATION, parent, child, false, null))
@@ -36,11 +36,11 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
/// </summary>
private abstract class Clause
{
protected readonly IMethodSymbol method;
protected readonly IMethodSymbol? method;
protected readonly List<ExpressionSyntax> arguments = new List<ExpressionSyntax>();
protected readonly SyntaxNode node;
protected Clause(IMethodSymbol method, SyntaxNode node)
protected Clause(IMethodSymbol? method, SyntaxNode node)
{
this.method = method;
this.node = node;
@@ -48,10 +48,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
public ExpressionSyntax Expr => arguments.First();
public CallClause WithCallClause(IMethodSymbol newMethod, SyntaxNode newNode) =>
public CallClause WithCallClause(IMethodSymbol? newMethod, SyntaxNode newNode) =>
new CallClause(this, newMethod, newNode);
public LetClause WithLetClause(IMethodSymbol newMethod, SyntaxNode newNode, ISymbol newDeclaration, SyntaxToken newName) =>
public LetClause WithLetClause(IMethodSymbol? newMethod, SyntaxNode newNode, ISymbol newDeclaration, SyntaxToken newName) =>
new LetClause(this, newMethod, newNode, newDeclaration, newName);
public Clause AddArgument(ExpressionSyntax arg)
@@ -66,7 +66,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
var type = cx.GetType(Expr);
AnnotatedTypeSymbol? declType;
TypeSyntax declTypeSyntax = null;
TypeSyntax? declTypeSyntax = null;
if (getElement)
{
if (node is FromClauseSyntax from && from.Type != null)
@@ -126,7 +126,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
.FirstOrDefault();
}
private static AnnotatedTypeSymbol? GetElementType(Context cx, ITypeSymbol symbol) =>
private static AnnotatedTypeSymbol? GetElementType(Context cx, ITypeSymbol? symbol) =>
symbol switch
{
IArrayTypeSymbol a => a.GetAnnotatedElementType(),
@@ -150,7 +150,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
private readonly ISymbol declaration;
private readonly SyntaxToken name;
public RangeClause(IMethodSymbol method, SyntaxNode node, ISymbol declaration, SyntaxToken name) : base(method, node)
public RangeClause(IMethodSymbol? method, SyntaxNode node, ISymbol declaration, SyntaxToken name) : base(method, node)
{
this.declaration = declaration;
this.name = name;
@@ -165,9 +165,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
private readonly Clause operand;
private readonly ISymbol declaration;
private readonly SyntaxToken name;
private ISymbol intoDeclaration;
private ISymbol? intoDeclaration;
public LetClause(Clause operand, IMethodSymbol method, SyntaxNode node, ISymbol declaration, SyntaxToken name) : base(method, node)
public LetClause(Clause operand, IMethodSymbol? method, SyntaxNode node, ISymbol declaration, SyntaxToken name) : base(method, node)
{
this.operand = operand;
this.declaration = declaration;
@@ -204,7 +204,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
{
private readonly Clause operand;
public CallClause(Clause operand, IMethodSymbol method, SyntaxNode node) : base(method, node)
public CallClause(Clause operand, IMethodSymbol? method, SyntaxNode node) : base(method, node)
{
this.operand = operand;
}
@@ -230,7 +230,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
var info = cx.GetModel(node).GetQueryClauseInfo(node.FromClause);
var method = info.OperationInfo.Symbol as IMethodSymbol;
var clauseExpr = new RangeClause(method, node.FromClause, cx.GetModel(node).GetDeclaredSymbol(node.FromClause), node.FromClause.Identifier).AddArgument(node.FromClause.Expression);
var clauseExpr = new RangeClause(method, node.FromClause, cx.GetModel(node).GetDeclaredSymbol(node.FromClause)!, node.FromClause.Identifier).AddArgument(node.FromClause.Expression);
foreach (var qc in node.Body.Clauses)
{
@@ -259,25 +259,25 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SyntaxKind.FromClause:
var fromClause = (FromClauseSyntax)qc;
clauseExpr = clauseExpr.
WithLetClause(method, fromClause, cx.GetModel(node).GetDeclaredSymbol(fromClause), fromClause.Identifier).
WithLetClause(method, fromClause, cx.GetModel(node).GetDeclaredSymbol(fromClause)!, fromClause.Identifier).
AddArgument(fromClause.Expression);
break;
case SyntaxKind.LetClause:
var letClause = (LetClauseSyntax)qc;
clauseExpr = clauseExpr.WithLetClause(method, letClause, cx.GetModel(node).GetDeclaredSymbol(letClause), letClause.Identifier).
clauseExpr = clauseExpr.WithLetClause(method, letClause, cx.GetModel(node).GetDeclaredSymbol(letClause)!, letClause.Identifier).
AddArgument(letClause.Expression);
break;
case SyntaxKind.JoinClause:
var joinClause = (JoinClauseSyntax)qc;
clauseExpr = clauseExpr.WithLetClause(method, joinClause, cx.GetModel(node).GetDeclaredSymbol(joinClause), joinClause.Identifier).
clauseExpr = clauseExpr.WithLetClause(method, joinClause, cx.GetModel(node).GetDeclaredSymbol(joinClause)!, joinClause.Identifier).
AddArgument(joinClause.InExpression).
AddArgument(joinClause.LeftExpression).
AddArgument(joinClause.RightExpression);
if (joinClause.Into != null)
{
var into = cx.GetModel(node).GetDeclaredSymbol(joinClause.Into);
var into = cx.GetModel(node).GetDeclaredSymbol(joinClause.Into)!;
((LetClause)clauseExpr).WithInto(into);
}

View File

@@ -13,11 +13,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
public static Expression Create(ExpressionNodeInfo info) => new Switch(info).TryPopulate();
public Expression SwitchedExpr { get; private set; }
protected override void PopulateExpression(TextWriter trapFile)
{
SwitchedExpr = Expression.Create(Context, Syntax.GoverningExpression, this, -1);
Expression.Create(Context, Syntax.GoverningExpression, this, -1);
for (var i = 0; i < Syntax.Arms.Count; i++)
{
new SwitchCase(Context, Syntax.Arms[i], this, i);

View File

@@ -15,7 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
{
case SyntaxKind.SimpleMemberAccessExpression:
var maes = (MemberAccessExpressionSyntax)Syntax;
if (Type?.Symbol.ContainingType is null)
if (Type?.Symbol?.ContainingType is null)
{
// namespace qualifier
TypeMention.Create(Context, maes.Name, this, Type, Syntax.GetLocation());

View File

@@ -11,7 +11,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
{
private VariableDeclaration(IExpressionInfo info) : base(info) { }
public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedTypeSymbol? type, TypeSyntax optionalSyntax, Extraction.Entities.Location exprLocation, bool isVar, IExpressionParentEntity parent, int child)
public static VariableDeclaration Create(Context cx, ISymbol symbol, AnnotatedTypeSymbol? type, TypeSyntax? optionalSyntax, Extraction.Entities.Location exprLocation, bool isVar, IExpressionParentEntity parent, int child)
{
var ret = new VariableDeclaration(new ExpressionInfo(cx, type, exprLocation, ExprKind.LOCAL_VAR_DECL, parent, child, false, null));
cx.Try(null, null, () =>
@@ -102,7 +102,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
}
private static Expression Create(Context cx, DeclarationExpressionSyntax node, VariableDesignationSyntax designation, IExpressionParentEntity parent, int child)
private static Expression Create(Context cx, DeclarationExpressionSyntax node, VariableDesignationSyntax? designation, IExpressionParentEntity parent, int child)
{
switch (designation)
{
@@ -127,12 +127,12 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
public static VariableDeclaration Create(Context cx, CatchDeclarationSyntax d, bool isVar, IExpressionParentEntity parent, int child)
{
var symbol = cx.GetModel(d).GetDeclaredSymbol(d);
var symbol = cx.GetModel(d).GetDeclaredSymbol(d)!;
var type = symbol.GetAnnotatedType();
var ret = Create(cx, d, type, parent, child);
cx.Try(d, null, () =>
{
var declSymbol = cx.GetModel(d).GetDeclaredSymbol(d);
var declSymbol = cx.GetModel(d).GetDeclaredSymbol(d)!;
var l = LocalVariable.Create(cx, declSymbol);
l.PopulateManual(ret, isVar);
TypeMention.Create(cx, d.Type, ret, type);
@@ -145,7 +145,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
var ret = Create(cx, d, type, parent, child);
cx.Try(d, null, () =>
{
var declSymbol = cx.GetModel(d).GetDeclaredSymbol(d);
var declSymbol = cx.GetModel(d).GetDeclaredSymbol(d)!;
var localVar = LocalVariable.Create(cx, declSymbol);
localVar.PopulateManual(ret, isVar);

View File

@@ -28,7 +28,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
PopulateMetadataHandle(trapFile);
PopulateAttributes();
ContainingType.PopulateGenerics();
ContainingType!.PopulateGenerics();
PopulateNullability(trapFile, Symbol.GetAnnotatedType());
var unboundFieldKey = Field.Create(Context, Symbol.OriginalDefinition);
@@ -67,7 +67,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
var loc = Context.CreateLocation(initializer.GetLocation());
var fieldAccess = AddInitializerAssignment(trapFile, initializer.Initializer.Value, loc, null, ref child);
var fieldAccess = AddInitializerAssignment(trapFile, initializer.Initializer!.Value, loc, null, ref child);
if (!Symbol.IsStatic)
{
@@ -88,7 +88,7 @@ namespace Semmle.Extraction.CSharp.Entities
var loc = Context.CreateLocation(initializer.GetLocation());
AddInitializerAssignment(trapFile, initializer.EqualsValue.Value, loc, constValue, ref child);
AddInitializerAssignment(trapFile, initializer.EqualsValue!.Value, loc, constValue, ref child);
}
if (IsSourceDeclaration)
@@ -105,7 +105,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
private Expression AddInitializerAssignment(TextWriter trapFile, ExpressionSyntax initializer, Extraction.Entities.Location loc,
string constValue, ref int child)
string? constValue, ref int child)
{
var type = Symbol.GetAnnotatedType();
var simpleAssignExpr = new Expression(new ExpressionInfo(Context, type, loc, ExprKind.SIMPLE_ASSIGN, this, child++, false, constValue));
@@ -122,7 +122,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
trapFile.WriteSubId(Type);
trapFile.Write(" ");
trapFile.WriteSubId(ContainingType);
trapFile.WriteSubId(ContainingType!);
trapFile.Write('.');
trapFile.Write(Symbol.Name);
trapFile.Write(";field");

View File

@@ -8,8 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class File : Extraction.Entities.File
{
// todo: this can be changed to an override after the .NET 5 upgrade
private new Context Context => (Context)base.Context;
public override Context Context => (Context)base.Context;
protected File(Context cx, string path)
: base(cx, path)

View File

@@ -2,8 +2,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal abstract class FreshEntity : Extraction.FreshEntity
{
// todo: this can be changed to an override after the .NET 5 upgrade
protected new Context Context => (Context)base.Context;
public override Context Context => (Context)base.Context;
protected FreshEntity(Context cx)
: base(cx)

View File

@@ -46,7 +46,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// If the expression does not have a value, then this
/// is null.
/// </summary>
string ExprValue { get; }
string? ExprValue { get; }
NullableFlowState FlowState { get; }
}

View File

@@ -17,7 +17,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateNullability(trapFile, Symbol.GetAnnotatedType());
var type = Type.Create(Context, Symbol.Type);
trapFile.indexers(this, Symbol.GetName(useMetadataName: true), ContainingType, type.TypeRef, OriginalDefinition);
trapFile.indexers(this, Symbol.GetName(useMetadataName: true), ContainingType!, type.TypeRef, OriginalDefinition);
foreach (var l in Locations)
trapFile.indexer_location(this, l);
@@ -63,7 +63,7 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.explicitly_implements(this, explicitInterface.TypeRef);
foreach (var syntax in declSyntaxReferences)
TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier.Name, this, explicitInterface);
TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier!.Name, this, explicitInterface);
}
@@ -75,7 +75,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(ContainingType);
trapFile.WriteSubId(ContainingType!);
trapFile.Write('.');
trapFile.Write(Symbol.MetadataName);
trapFile.Write('(');

View File

@@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
if (Symbol is ILocalSymbol local && local.HasConstantValue)
{
trapFile.constant_value(this, Expression.ValueAsString(local.ConstantValue));
trapFile.constant_value(this, Expression.ValueAsString(local.ConstantValue!));
}
}

View File

@@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Semmle.Extraction.CSharp.Populators;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
@@ -25,7 +26,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
// Non-generic reduced extensions must be extracted exactly like the
// non-reduced counterparts
parameters = Symbol.ReducedFrom.Parameters;
parameters = Symbol.ReducedFrom!.Parameters;
}
else
{
@@ -82,7 +83,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (block != null)
Statements.Block.Create(Context, block, this, 0);
else
Expression.Create(Context, expr, this, 0);
Expression.Create(Context, expr!, this, 0);
NumberOfLines(trapFile, BodyDeclaringSymbol, this);
});
@@ -95,7 +96,10 @@ namespace Semmle.Extraction.CSharp.Entities
{
var node = (CSharpSyntaxNode)decl.GetSyntax();
var lineCounts = node.Accept(new AstLineCounter());
trapFile.numlines(callable, lineCounts);
if (lineCounts is object)
{
trapFile.numlines(callable, lineCounts);
}
}
}
@@ -110,7 +114,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (IsSourceDeclaration)
{
foreach (var syntax in Symbol.DeclaringSyntaxReferences.Select(d => d.GetSyntax()).OfType<MethodDeclarationSyntax>())
TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier.Name, this, explicitInterface);
TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier!.Name, this, explicitInterface);
}
}
@@ -128,7 +132,7 @@ namespace Semmle.Extraction.CSharp.Entities
m.Symbol.ReturnType.BuildOrWriteId(m.Context, trapFile, m.Symbol);
trapFile.Write(" ");
trapFile.WriteSubId(m.ContainingType);
trapFile.WriteSubId(m.ContainingType!);
AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.Symbol.ExplicitInterfaceImplementations);
@@ -189,7 +193,7 @@ namespace Semmle.Extraction.CSharp.Entities
var index = 0;
var @params = method.MethodKind == MethodKind.ReducedExtension
? method.ReducedFrom.Parameters
? method.ReducedFrom!.Parameters
: method.Parameters;
foreach (var param in @params)
@@ -232,7 +236,8 @@ namespace Semmle.Extraction.CSharp.Entities
/// <param name="cx"></param>
/// <param name="methodDecl"></param>
/// <returns></returns>
public static Method Create(Context cx, IMethodSymbol methodDecl)
[return: NotNullIfNotNull("methodDecl")]
public static Method? Create(Context cx, IMethodSymbol? methodDecl)
{
if (methodDecl == null)
return null;
@@ -278,10 +283,10 @@ namespace Semmle.Extraction.CSharp.Entities
public Method OriginalDefinition =>
IsReducedExtension
? Create(Context, Symbol.ReducedFrom)
? Create(Context, Symbol.ReducedFrom!)
: Create(Context, Symbol.OriginalDefinition);
public override Microsoft.CodeAnalysis.Location FullLocation => ReportingLocation;
public override Location? FullLocation => ReportingLocation;
public override bool IsSourceDeclaration => Symbol.IsSourceDeclaration();

View File

@@ -8,7 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities
private Modifier(Context cx, string init)
: base(cx, init) { }
public override Microsoft.CodeAnalysis.Location ReportingLocation => null;
public override Location? ReportingLocation => null;
public override void WriteId(TextWriter trapFile)
{

View File

@@ -8,7 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities
private Namespace(Context cx, INamespaceSymbol init)
: base(cx, init) { }
public override Microsoft.CodeAnalysis.Location ReportingLocation => null;
public override Location? ReportingLocation => null;
public override void Populate(TextWriter trapFile)
{
@@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities
private string QualifiedName => Symbol.ToDisplayString();
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj is Namespace ns && QualifiedName == ns.QualifiedName;
}

View File

@@ -28,7 +28,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
var @namespace = (INamespaceSymbol)Context.GetModel(node).GetSymbolInfo(node.Name).Symbol;
var @namespace = (INamespaceSymbol)Context.GetModel(node).GetSymbolInfo(node.Name).Symbol!;
var ns = Namespace.Create(Context, @namespace);
trapFile.namespace_declarations(this, ns);
trapFile.namespace_declaration_location(this, Context.CreateLocation(node.Name.GetLocation()));

View File

@@ -5,8 +5,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class NonGeneratedSourceLocation : Extraction.Entities.SourceLocation
{
// todo: this can be changed to an override after the .NET 5 upgrade
private new Context Context => (Context)base.Context;
public override Context Context => (Context)base.Context;
protected NonGeneratedSourceLocation(Context cx, Location init)
: base(cx, init)

View File

@@ -30,7 +30,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
PopulateMethod(trapFile);
PopulateModifiers(trapFile);
ContainingType.PopulateGenerics();
ContainingType!.PopulateGenerics();
var returnType = Type.Create(Context, Symbol.ReturnType);
trapFile.methods(this, Name, ContainingType, returnType.TypeRef, OriginalDefinition);

View File

@@ -9,10 +9,10 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal class Parameter : CachedSymbol<IParameterSymbol>, IExpressionParentEntity
{
protected IEntity Parent { get; set; }
protected IEntity? Parent { get; set; }
protected Parameter Original { get; }
protected Parameter(Context cx, IParameterSymbol init, IEntity parent, Parameter original)
protected Parameter(Context cx, IParameterSymbol init, IEntity? parent, Parameter? original)
: base(cx, init)
{
Parent = parent;
@@ -67,7 +67,7 @@ namespace Semmle.Extraction.CSharp.Entities
}
}
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) =>
public static Parameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null) =>
ParameterFactory.Instance.CreateEntity(cx, param, (param, parent, original));
public static Parameter Create(Context cx, IParameterSymbol param) =>
@@ -77,6 +77,10 @@ namespace Semmle.Extraction.CSharp.Entities
{
if (Parent == null)
Parent = Method.Create(Context, Symbol.ContainingSymbol as IMethodSymbol);
if (Parent == null)
throw new InternalError(Symbol, "Couldn't get parent of symbol.");
trapFile.WriteSubId(Parent);
trapFile.Write('_');
trapFile.Write(Ordinal);
@@ -107,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities
Context.ModelError(Symbol, "Inconsistent parameter declaration");
var type = Type.Create(Context, Symbol.Type);
trapFile.@params(this, Name, type.TypeRef, Ordinal, ParamKind, Parent, Original);
trapFile.@params(this, Name, type.TypeRef, Ordinal, ParamKind, Parent!, Original);
foreach (var l in Symbol.Locations)
trapFile.param_location(this, Context.CreateLocation(l));
@@ -132,7 +136,7 @@ namespace Semmle.Extraction.CSharp.Entities
.OfType<ParameterSyntax>()
.Where(s => s.Type != null))
{
TypeMention.Create(Context, syntax.Type, this, type);
TypeMention.Create(Context, syntax.Type!, this, type);
}
}
@@ -151,7 +155,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (method != null)
{
var i = method.Parameters.IndexOf(Symbol);
var indexer = (IPropertySymbol)method.AssociatedSymbol;
var indexer = (IPropertySymbol?)method.AssociatedSymbol;
if (indexer != null)
defaultValue = GetParameterDefaultValue(indexer.Parameters[i]);
}
@@ -171,17 +175,17 @@ namespace Semmle.Extraction.CSharp.Entities
bool IExpressionParentEntity.IsTopLevelParent => true;
private static EqualsValueClauseSyntax GetParameterDefaultValue(IParameterSymbol parameter)
private static EqualsValueClauseSyntax? GetParameterDefaultValue(IParameterSymbol parameter)
{
var syntax = parameter.DeclaringSyntaxReferences.Select(@ref => @ref.GetSyntax()).OfType<ParameterSyntax>().FirstOrDefault();
return syntax?.Default;
}
private class ParameterFactory : CachedEntityFactory<(IParameterSymbol, IEntity, Parameter), Parameter>
private class ParameterFactory : CachedEntityFactory<(IParameterSymbol, IEntity?, Parameter?), Parameter>
{
public static ParameterFactory Instance { get; } = new ParameterFactory();
public override Parameter Create(Context cx, (IParameterSymbol, IEntity, Parameter) init) => new Parameter(cx, init.Item1, init.Item2, init.Item3);
public override Parameter Create(Context cx, (IParameterSymbol, IEntity?, Parameter?) init) => new Parameter(cx, init.Item1, init.Item2, init.Item3);
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;
@@ -211,42 +215,44 @@ namespace Semmle.Extraction.CSharp.Entities
return 98735267;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj != null && obj.GetType() == typeof(VarargsType);
}
public static VarargsType Create(Context cx) => VarargsTypeFactory.Instance.CreateEntity(cx, typeof(VarargsType), null);
private class VarargsTypeFactory : CachedEntityFactory<string, VarargsType>
private class VarargsTypeFactory : CachedEntityFactory<string?, VarargsType>
{
public static VarargsTypeFactory Instance { get; } = new VarargsTypeFactory();
public override VarargsType Create(Context cx, string init) => new VarargsType(cx);
public override VarargsType Create(Context cx, string? init) => new VarargsType(cx);
}
}
internal class VarargsParam : Parameter
{
#nullable disable warnings
private VarargsParam(Context cx, Method methodKey)
: base(cx, null, methodKey, null) { }
#nullable restore warnings
public override void Populate(TextWriter trapFile)
{
var typeKey = VarargsType.Create(Context);
// !! Maybe originaldefinition is wrong
trapFile.@params(this, "", typeKey, Ordinal, Kind.None, Parent, this);
trapFile.@params(this, "", typeKey, Ordinal, Kind.None, Parent!, this);
trapFile.param_location(this, GeneratedLocation.Create(Context));
}
protected override int Ordinal => ((Method)Parent).OriginalDefinition.Symbol.Parameters.Length;
protected override int Ordinal => ((Method)Parent!).OriginalDefinition.Symbol.Parameters.Length;
public override int GetHashCode()
{
return 9873567;
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj != null && obj.GetType() == typeof(VarargsParam);
}
@@ -268,18 +274,18 @@ namespace Semmle.Extraction.CSharp.Entities
private ConstructedExtensionParameter(Context cx, Method method, Parameter original)
: base(cx, original.Symbol, method, original)
{
constructedType = method.Symbol.ReceiverType;
constructedType = method.Symbol.ReceiverType!;
}
public override void Populate(TextWriter trapFile)
{
var typeKey = Type.Create(Context, constructedType);
trapFile.@params(this, Original.Symbol.Name, typeKey.TypeRef, 0, Kind.This, Parent, Original);
trapFile.@params(this, Original.Symbol.Name, typeKey.TypeRef, 0, Kind.This, Parent!, Original);
trapFile.param_location(this, Original.Location);
}
public static ConstructedExtensionParameter Create(Context cx, Method method, Parameter parameter) =>
ExtensionParamFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(parameter.Symbol), new SymbolEqualityWrapper(method.Symbol.ReceiverType)), (method, parameter));
ExtensionParamFactory.Instance.CreateEntity(cx, (new SymbolEqualityWrapper(parameter.Symbol), new SymbolEqualityWrapper(method.Symbol.ReceiverType!)), (method, parameter));
private class ExtensionParamFactory : CachedEntityFactory<(Method, Parameter), ConstructedExtensionParameter>
{

View File

@@ -26,7 +26,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (trivia.Line.IsKind(SyntaxKind.NumericLiteralToken))
{
var value = (int)trivia.Line.Value;
var value = (int)trivia.Line.Value!;
trapFile.directive_line_value(this, value);
if (!string.IsNullOrWhiteSpace(trivia.File.ValueText))

View File

@@ -25,7 +25,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
trapFile.WriteSubId(Type);
trapFile.Write(" ");
trapFile.WriteSubId(ContainingType);
trapFile.WriteSubId(ContainingType!);
trapFile.Write('.');
Method.AddExplicitInterfaceQualifierToId(Context, trapFile, Symbol.ExplicitInterfaceImplementations);
trapFile.Write(Symbol.Name);
@@ -42,7 +42,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateRefKind(trapFile, Symbol.RefKind);
var type = Type;
trapFile.properties(this, Symbol.GetName(), ContainingType, type.TypeRef, Create(Context, Symbol.OriginalDefinition));
trapFile.properties(this, Symbol.GetName(), ContainingType!, type.TypeRef, Create(Context, Symbol.OriginalDefinition));
var getter = Symbol.GetMethod;
var setter = Symbol.SetMethod;
@@ -63,7 +63,7 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.explicitly_implements(this, explicitInterface.TypeRef);
foreach (var syntax in declSyntaxReferences)
TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier.Name, this, explicitInterface);
TypeMention.Create(Context, syntax.ExplicitInterfaceSpecifier!.Name, this, explicitInterface);
}
foreach (var l in Locations)
@@ -84,7 +84,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
Context.PopulateLater(() =>
{
var loc = Context.CreateLocation(initializer.GetLocation());
var loc = Context.CreateLocation(initializer!.GetLocation());
var annotatedType = AnnotatedTypeSymbol.CreateNotAnnotated(Symbol.Type);
var simpleAssignExpr = new Expression(new ExpressionInfo(Context, annotatedType, loc, ExprKind.SIMPLE_ASSIGN, this, child++, false, null));
Expression.CreateFromNode(new ExpressionNodeInfo(Context, initializer.Value, simpleAssignExpr, 0));

View File

@@ -15,16 +15,16 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
protected override void PopulateStatement(TextWriter trapFile)
{
var isSpecificCatchClause = Stmt.Declaration != null;
var hasVariableDeclaration = isSpecificCatchClause && Stmt.Declaration.Identifier.RawKind != 0;
var hasVariableDeclaration = isSpecificCatchClause && Stmt.Declaration!.Identifier.RawKind != 0;
if (hasVariableDeclaration) // A catch clause of the form 'catch(Ex ex) { ... }'
{
var decl = Expressions.VariableDeclaration.Create(Context, Stmt.Declaration, false, this, 0);
var decl = Expressions.VariableDeclaration.Create(Context, Stmt.Declaration!, false, this, 0);
trapFile.catch_type(this, Type.Create(Context, decl.Type).TypeRef, true);
}
else if (isSpecificCatchClause) // A catch clause of the form 'catch(Ex) { ... }'
{
trapFile.catch_type(this, Type.Create(Context, Context.GetType(Stmt.Declaration.Type)).TypeRef, true);
trapFile.catch_type(this, Type.Create(Context, Context.GetType(Stmt.Declaration!.Type)).TypeRef, true);
}
else // A catch clause of the form 'catch { ... }'
{

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
Expression.Create(Context, Stmt.Expression, this, 1);
var semanticModel = Context.GetModel(Stmt);
var typeSymbol = semanticModel.GetDeclaredSymbol(Stmt);
var typeSymbol = semanticModel.GetDeclaredSymbol(Stmt)!;
var type = typeSymbol.GetAnnotatedType();
var location = Context.CreateLocation(Stmt.Identifier.GetLocation());

View File

@@ -15,7 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
this.parent = parent;
}
public override Microsoft.CodeAnalysis.Location ReportingLocation
public override Microsoft.CodeAnalysis.Location? ReportingLocation
{
get
{

View File

@@ -36,12 +36,12 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
switch (GetKind(Stmt))
{
case StmtKind.GOTO:
var target = ((IdentifierNameSyntax)Stmt.Expression).Identifier.Text;
var target = ((IdentifierNameSyntax)Stmt.Expression!).Identifier.Text;
trapFile.exprorstmt_name(this, target);
break;
case StmtKind.GOTO_CASE:
Expr = Expression.Create(Context, Stmt.Expression, this, 0);
ConstantValue = Switch.LabelForValue(Context.GetModel(Stmt).GetConstantValue(Stmt.Expression).Value);
Expr = Expression.Create(Context, Stmt.Expression!, this, 0);
ConstantValue = Switch.LabelForValue(Context.GetModel(Stmt).GetConstantValue(Stmt.Expression!).Value);
break;
case StmtKind.GOTO_DEFAULT:
ConstantValue = Switch.DefaultLabel;
@@ -49,9 +49,9 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
}
}
public Expression Expr { get; private set; }
public Expression? Expr { get; private set; }
public object ConstantValue { get; private set; }
public object? ConstantValue { get; private set; }
public bool IsDefault => ConstantValue == Switch.DefaultLabel;
}

View File

@@ -8,7 +8,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
{
private readonly IStatementParentEntity parent;
private readonly int child;
private Statement labelledStmt;
private Statement? labelledStmt;
private Labeled(Context cx, LabeledStatementSyntax stmt, IStatementParentEntity parent, int child)
: base(cx, stmt, StmtKind.LABEL, parent, child)
@@ -33,6 +33,6 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
labelledStmt = Statement.Create(Context, Stmt.Statement, parent, child + 1);
}
public override int NumberOfStatements => 1 + labelledStmt.NumberOfStatements;
public override int NumberOfStatements => 1 + labelledStmt?.NumberOfStatements ?? 0;
}
}

View File

@@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
/// <summary>
/// Gets the IMethodSymbol for this local function statement.
/// </summary>
private IMethodSymbol Symbol
private IMethodSymbol? Symbol
{
get
{
@@ -31,14 +31,16 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
}
}
/// <summary>
/// Gets the function defined by this local statement.
/// </summary>
private Entities.LocalFunction Function => Entities.LocalFunction.Create(Context, Symbol);
protected override void PopulateStatement(TextWriter trapFile)
{
trapFile.local_function_stmts(this, Function);
if (Symbol is null)
{
Context.ExtractionError("Could not get local function symbol", null, Context.CreateLocation(this.ReportingLocation), severity: Util.Logging.Severity.Warning);
return;
}
var function = Entities.LocalFunction.Create(Context, Symbol);
trapFile.local_function_stmts(this, function);
}
}
}

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
// Sometimes, the literal "null" is used as a label.
// This is inconveniently represented by the "null" object.
// This cannot be stored in a Dictionary<>, so substitute an object which can be.
public static object LabelForValue(object label)
public static object LabelForValue(object? label)
{
return label ?? nullLabel;
}

View File

@@ -32,17 +32,5 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
Create(Context, Stmt.Finally.Block, this, -1);
}
}
public static SyntaxNodeOrToken NextNode(SyntaxNode node)
{
for (var i = node.Parent.ChildNodesAndTokens().GetEnumerator(); i.MoveNext();)
{
if (i.Current == node)
{
return i.MoveNext() ? i.Current : null;
}
}
return null;
}
}
}

View File

@@ -12,9 +12,9 @@ namespace Semmle.Extraction.CSharp.Entities
private readonly TypeSyntax syntax;
private readonly IEntity parent;
private readonly Type type;
private readonly Microsoft.CodeAnalysis.Location loc;
private readonly Microsoft.CodeAnalysis.Location? loc;
private TypeMention(Context cx, TypeSyntax syntax, IEntity parent, Type type, Microsoft.CodeAnalysis.Location loc = null)
private TypeMention(Context cx, TypeSyntax syntax, IEntity parent, Type type, Microsoft.CodeAnalysis.Location? loc = null)
: base(cx)
{
this.syntax = syntax;
@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
case NullableTypeSyntax nts:
// int[]? -> int[] -> int
// int? -> int?
return Context.GetTypeInfo(nts.ElementType).Type.IsReferenceType
return Context.GetTypeInfo(nts.ElementType).Type?.IsReferenceType == true
? GetArrayElementType(nts.ElementType)
: nts;
case PointerTypeSyntax pts:
@@ -121,14 +121,14 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.type_mention_location(this, Context.CreateLocation(loc));
}
public static TypeMention Create(Context cx, TypeSyntax syntax, IEntity parent, Type type, Microsoft.CodeAnalysis.Location loc = null)
public static TypeMention Create(Context cx, TypeSyntax syntax, IEntity parent, Type type, Microsoft.CodeAnalysis.Location? loc = null)
{
var ret = new TypeMention(cx, syntax, parent, type, loc);
cx.Try(syntax, null, () => ret.Populate(cx.TrapWriter.Writer));
return ret;
}
public static TypeMention Create(Context cx, TypeSyntax syntax, IEntity parent, AnnotatedTypeSymbol? type, Microsoft.CodeAnalysis.Location loc = null) =>
public static TypeMention Create(Context cx, TypeSyntax syntax, IEntity parent, AnnotatedTypeSymbol? type, Microsoft.CodeAnalysis.Location? loc = null) =>
Create(cx, syntax, parent, Type.Create(cx, type?.Symbol), loc);
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.OptionalLabel;

View File

@@ -11,7 +11,7 @@ namespace Semmle.Extraction.CSharp.Entities
public static DynamicType Create(Context cx, IDynamicTypeSymbol type) => DynamicTypeFactory.Instance.CreateEntityFromSymbol(cx, type);
public override Microsoft.CodeAnalysis.Location ReportingLocation => Context.Compilation.ObjectType.Locations.FirstOrDefault();
public override Microsoft.CodeAnalysis.Location? ReportingLocation => Context.Compilation.ObjectType.Locations.FirstOrDefault();
public override void Populate(TextWriter trapFile)
{

View File

@@ -36,7 +36,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
if (Symbol.TypeKind == TypeKind.Error)
{
Context.Extractor.MissingType(Symbol.ToString(), Context.FromSource);
Context.Extractor.MissingType(Symbol.ToString()!, Context.FromSource);
return;
}
@@ -108,7 +108,7 @@ namespace Semmle.Extraction.CSharp.Entities
foreach (var l in GetLocations(Symbol))
yield return Context.CreateLocation(l);
if (Context.Extractor.OutputPath != null && Symbol.DeclaringSyntaxReferences.Any())
if (!Context.Extractor.Standalone && Symbol.DeclaringSyntaxReferences.Any())
yield return Assembly.CreateOutputAssembly(Context);
}
}
@@ -124,7 +124,7 @@ namespace Semmle.Extraction.CSharp.Entities
);
}
public override Microsoft.CodeAnalysis.Location ReportingLocation => GetLocations(Symbol).FirstOrDefault();
public override Microsoft.CodeAnalysis.Location? ReportingLocation => GetLocations(Symbol).FirstOrDefault();
private bool IsAnonymousType() => Symbol.IsAnonymousType || Symbol.Name.Contains("__AnonymousType");

View File

@@ -22,18 +22,18 @@ namespace Semmle.Extraction.CSharp.Entities
public override int GetHashCode() => 987354;
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
return obj != null && obj.GetType() == typeof(NullType);
}
public static Type Create(Context cx) => NullTypeFactory.Instance.CreateEntity(cx, typeof(NullType), null);
private class NullTypeFactory : CachedEntityFactory<ITypeSymbol, NullType>
private class NullTypeFactory : CachedEntityFactory<ITypeSymbol?, NullType>
{
public static NullTypeFactory Instance { get; } = new NullTypeFactory();
public override NullType Create(Context cx, ITypeSymbol init) => new NullType(cx);
public override NullType Create(Context cx, ITypeSymbol? init) => new NullType(cx);
}
}
}

View File

@@ -64,7 +64,7 @@ namespace Semmle.Extraction.CSharp.Entities
NullableParameters = method.GetAnnotatedTypeArguments().Select(a => new Nullability(a)).ToArray();
}
public override bool Equals(object other)
public override bool Equals(object? other)
{
return other is Nullability n && Annotation == n.Annotation && NullableParameters.SequenceEqual(n.NullableParameters);
}

View File

@@ -10,9 +10,10 @@ namespace Semmle.Extraction.CSharp.Entities
{
internal abstract class Type : CachedSymbol<ITypeSymbol>
{
protected Type(Context cx, ITypeSymbol init)
#nullable disable warnings
protected Type(Context cx, ITypeSymbol? init)
: base(cx, init) { }
#nullable restore warnings
public override bool NeedsPopulation =>
base.NeedsPopulation || Symbol.TypeKind == TypeKind.Dynamic || Symbol.TypeKind == TypeKind.TypeParameter;
@@ -132,7 +133,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
// This is a delegate.
// The method "Invoke" has the return type.
var invokeMethod = ((INamedTypeSymbol)Symbol).DelegateInvokeMethod;
var invokeMethod = ((INamedTypeSymbol)Symbol).DelegateInvokeMethod!;
ExtractParametersForDelegateLikeType(trapFile, invokeMethod,
t => trapFile.delegate_return_type(this, t));
}
@@ -155,7 +156,7 @@ namespace Semmle.Extraction.CSharp.Entities
baseLists
.Where(bl => bl != null)
.SelectMany(bl => bl.Types)
.SelectMany(bl => bl!.Types)
.Zip(
baseTypes.Where(bt => bt.Symbol.SpecialType != SpecialType.System_Object),
(s, t) => TypeMention.Create(Context, s.Type, this, t))
@@ -258,7 +259,7 @@ namespace Semmle.Extraction.CSharp.Entities
ExtractRecursive();
}
public static Type Create(Context cx, ITypeSymbol type)
public static Type Create(Context cx, ITypeSymbol? type)
{
type = type.DisambiguateType();
return type == null
@@ -271,7 +272,7 @@ namespace Semmle.Extraction.CSharp.Entities
public virtual int Dimension => 0;
public static bool IsDelegate(ITypeSymbol symbol) =>
public static bool IsDelegate(ITypeSymbol? symbol) =>
symbol != null && symbol.TypeKind == TypeKind.Delegate;
/// <summary>
@@ -279,19 +280,19 @@ namespace Semmle.Extraction.CSharp.Entities
/// </summary>
private class DelegateTypeParameter : Parameter
{
private DelegateTypeParameter(Context cx, IParameterSymbol init, IEntity parent, Parameter original)
private DelegateTypeParameter(Context cx, IParameterSymbol init, IEntity parent, Parameter? original)
: base(cx, init, parent, original) { }
public static new DelegateTypeParameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter original = null) =>
public static new DelegateTypeParameter Create(Context cx, IParameterSymbol param, IEntity parent, Parameter? original = null) =>
// We need to use a different cache key than `param` to avoid mixing up
// `DelegateTypeParameter`s and `Parameter`s
DelegateTypeParameterFactory.Instance.CreateEntity(cx, (typeof(DelegateTypeParameter), new SymbolEqualityWrapper(param)), (param, parent, original));
private class DelegateTypeParameterFactory : CachedEntityFactory<(IParameterSymbol, IEntity, Parameter), DelegateTypeParameter>
private class DelegateTypeParameterFactory : CachedEntityFactory<(IParameterSymbol, IEntity, Parameter?), DelegateTypeParameter>
{
public static DelegateTypeParameterFactory Instance { get; } = new DelegateTypeParameterFactory();
public override DelegateTypeParameter Create(Context cx, (IParameterSymbol, IEntity, Parameter) init) =>
public override DelegateTypeParameter Create(Context cx, (IParameterSymbol, IEntity, Parameter?) init) =>
new DelegateTypeParameter(cx, init.Item1, init.Item2, init.Item3);
}
}
@@ -312,7 +313,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NoLabel;
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
var other = obj as Type;
return other?.GetType() == GetType() && SymbolEqualityComparer.Default.Equals(other.Symbol, Symbol);
@@ -326,7 +327,6 @@ namespace Semmle.Extraction.CSharp.Entities
protected Type(Context cx, T init)
: base(cx, init) { }
// todo: change this with .net 5 to be an override
public new T Symbol => (T)base.Symbol;
}
}

View File

@@ -63,7 +63,7 @@ namespace Semmle.Extraction.CSharp.Entities
.Select(d => d.GetSyntax())
.Select(s => s.Parent)
.Where(p => p != null)
.Select(p => p.Parent)
.Select(p => p!.Parent)
.ToArray();
var clauses = declSyntaxReferences.OfType<MethodDeclarationSyntax>().SelectMany(m => m.ConstraintClauses);
clauses = clauses.Concat(declSyntaxReferences.OfType<ClassDeclarationSyntax>().SelectMany(c => c.ConstraintClauses));

View File

@@ -42,7 +42,7 @@ namespace Semmle.Extraction.CSharp.Entities
else
{
// A "using static"
var m = Type.Create(Context, (ITypeSymbol)info.Symbol);
var m = Type.Create(Context, (ITypeSymbol?)info.Symbol);
trapFile.using_static_directives(this, m.TypeRef);
trapFile.using_directive_location(this, Context.CreateLocation(ReportingLocation));
}

View File

@@ -0,0 +1,311 @@
using System;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using System.IO;
using System.Linq;
using Semmle.Extraction.CSharp.Populators;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Diagnostics;
using Semmle.Util.Logging;
namespace Semmle.Extraction.CSharp
{
/// <summary>
/// Encapsulates a C# analysis task.
/// </summary>
public class Analyser : IDisposable
{
protected Extraction.Extractor? extractor;
protected CSharpCompilation? compilation;
protected Layout? layout;
protected CommonOptions? options;
private readonly object progressMutex = new object();
// The bulk of the extraction work, potentially executed in parallel.
protected readonly List<Action> extractionTasks = new List<Action>();
private int taskCount = 0;
private readonly Stopwatch stopWatch = new Stopwatch();
private readonly IProgressMonitor progressMonitor;
public ILogger Logger { get; }
protected readonly bool addAssemblyTrapPrefix;
public PathTransformer PathTransformer { get; }
protected Analyser(IProgressMonitor pm, ILogger logger, bool addAssemblyTrapPrefix, PathTransformer pathTransformer)
{
Logger = logger;
this.addAssemblyTrapPrefix = addAssemblyTrapPrefix;
Logger.Log(Severity.Info, "EXTRACTION STARTING at {0}", DateTime.Now);
stopWatch.Start();
progressMonitor = pm;
PathTransformer = pathTransformer;
}
/// <summary>
/// Perform an analysis on a source file/syntax tree.
/// </summary>
/// <param name="tree">Syntax tree to analyse.</param>
public void AnalyseTree(SyntaxTree tree)
{
extractionTasks.Add(() => DoExtractTree(tree));
}
#nullable disable warnings
/// <summary>
/// Enqueue all reference analysis tasks.
/// </summary>
public void AnalyseReferences()
{
foreach (var assembly in compilation.References.OfType<PortableExecutableReference>())
{
// CIL first - it takes longer.
if (options.CIL)
extractionTasks.Add(() => DoExtractCIL(assembly));
extractionTasks.Add(() => DoAnalyseReferenceAssembly(assembly));
}
}
/// <summary>
/// Constructs the map from assembly string to its filename.
///
/// Roslyn doesn't record the relationship between a filename and its assembly
/// information, so we need to retrieve this information manually.
/// </summary>
protected void SetReferencePaths()
{
foreach (var reference in compilation.References.OfType<PortableExecutableReference>())
{
try
{
var refPath = reference.FilePath!;
/* This method is significantly faster and more lightweight than using
* System.Reflection.Assembly.ReflectionOnlyLoadFrom. It is also allows
* loading the same assembly from different locations.
*/
using var pereader = new System.Reflection.PortableExecutable.PEReader(new FileStream(refPath, FileMode.Open, FileAccess.Read, FileShare.Read));
var metadata = pereader.GetMetadata();
string assemblyIdentity;
unsafe
{
var reader = new System.Reflection.Metadata.MetadataReader(metadata.Pointer, metadata.Length);
var def = reader.GetAssemblyDefinition();
assemblyIdentity = reader.GetString(def.Name) + " " + def.Version;
}
extractor.SetAssemblyFile(assemblyIdentity, refPath);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
extractor.Message(new Message("Exception reading reference file", reference.FilePath, null, ex.StackTrace));
}
}
}
/// <summary>
/// Extract an assembly to a new trap file.
/// If the trap file exists, skip extraction to avoid duplicating
/// extraction within the snapshot.
/// </summary>
/// <param name="r">The assembly to extract.</param>
private void DoAnalyseReferenceAssembly(PortableExecutableReference r)
{
try
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var assemblyPath = r.FilePath!;
var transformedAssemblyPath = PathTransformer.Transform(assemblyPath);
var projectLayout = layout.LookupProjectOrDefault(transformedAssemblyPath);
using var trapWriter = projectLayout.CreateTrapWriter(Logger, transformedAssemblyPath, options.TrapCompression, discardDuplicates: true);
var skipExtraction = options.Cache && File.Exists(trapWriter.TrapFile);
if (!skipExtraction)
{
/* Note on parallel builds:
*
* The trap writer and source archiver both perform atomic moves
* of the file to the final destination.
*
* If the same source file or trap file are generated concurrently
* (by different parallel invocations of the extractor), then
* last one wins.
*
* Specifically, if two assemblies are analysed concurrently in a build,
* then there is a small amount of duplicated work but the output should
* still be correct.
*/
// compilation.Clone() reduces memory footprint by allowing the symbols
// in c to be garbage collected.
Compilation c = compilation.Clone();
if (c.GetAssemblyOrModuleSymbol(r) is IAssemblySymbol assembly)
{
var cx = new Context(extractor, c, trapWriter, new AssemblyScope(assembly, assemblyPath), addAssemblyTrapPrefix);
foreach (var module in assembly.Modules)
{
AnalyseNamespace(cx, module.GlobalNamespace);
}
Entities.Attribute.ExtractAttributes(cx, assembly, Entities.Assembly.Create(cx, assembly.GetSymbolLocation()));
cx.PopulateAll();
}
}
ReportProgress(assemblyPath, trapWriter.TrapFile, stopwatch.Elapsed, skipExtraction ? AnalysisAction.UpToDate : AnalysisAction.Extracted);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
Logger.Log(Severity.Error, " Unhandled exception analyzing {0}: {1}", r.FilePath, ex);
}
}
private void DoExtractCIL(PortableExecutableReference r)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
CIL.Analyser.ExtractCIL(layout, r.FilePath!, Logger, !options.Cache, options.PDB, options.TrapCompression, out var trapFile, out var extracted);
stopwatch.Stop();
ReportProgress(r.FilePath, trapFile, stopwatch.Elapsed, extracted ? AnalysisAction.Extracted : AnalysisAction.UpToDate);
}
private void DoExtractTree(SyntaxTree tree)
{
try
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var sourcePath = tree.FilePath;
var transformedSourcePath = PathTransformer.Transform(sourcePath);
var projectLayout = layout.LookupProjectOrNull(transformedSourcePath);
var excluded = projectLayout == null;
var trapPath = excluded ? "" : projectLayout!.GetTrapPath(Logger, transformedSourcePath, options.TrapCompression);
var upToDate = false;
if (!excluded)
{
// compilation.Clone() is used to allow symbols to be garbage collected.
using var trapWriter = projectLayout!.CreateTrapWriter(Logger, transformedSourcePath, options.TrapCompression, discardDuplicates: false);
upToDate = options.Fast && FileIsUpToDate(sourcePath, trapWriter.TrapFile);
if (!upToDate)
{
var cx = new Context(extractor, compilation.Clone(), trapWriter, new SourceScope(tree), addAssemblyTrapPrefix);
// Ensure that the file itself is populated in case the source file is totally empty
var root = tree.GetRoot();
Entities.File.Create(cx, root.SyntaxTree.FilePath);
var csNode = (CSharpSyntaxNode)root;
csNode.Accept(new CompilationUnitVisitor(cx));
csNode.Accept(new DirectiveVisitor(cx));
cx.PopulateAll();
CommentPopulator.ExtractCommentBlocks(cx, cx.CommentGenerator);
cx.PopulateAll();
}
}
ReportProgress(sourcePath, trapPath, stopwatch.Elapsed, excluded
? AnalysisAction.Excluded
: upToDate
? AnalysisAction.UpToDate
: AnalysisAction.Extracted);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
extractor.Message(new Message($"Unhandled exception processing syntax tree. {ex.Message}", tree.FilePath, null, ex.StackTrace));
}
}
#nullable restore warnings
private static bool FileIsUpToDate(string src, string dest)
{
return File.Exists(dest) &&
File.GetLastWriteTime(dest) >= File.GetLastWriteTime(src);
}
private void AnalyseNamespace(Context cx, INamespaceSymbol ns)
{
foreach (var memberNamespace in ns.GetNamespaceMembers())
{
AnalyseNamespace(cx, memberNamespace);
}
foreach (var memberType in ns.GetTypeMembers())
{
Entities.Type.Create(cx, memberType).ExtractRecursive();
}
}
private void ReportProgress(string src, string output, TimeSpan time, AnalysisAction action)
{
lock (progressMutex)
progressMonitor.Analysed(++taskCount, extractionTasks.Count, src, output, time, action);
}
/// <summary>
/// Run all extraction tasks.
/// </summary>
/// <param name="numberOfThreads">The number of threads to use.</param>
public void PerformExtraction(int numberOfThreads)
{
Parallel.Invoke(
new ParallelOptions { MaxDegreeOfParallelism = numberOfThreads },
extractionTasks.ToArray());
}
public virtual void Dispose()
{
stopWatch.Stop();
Logger.Log(Severity.Info, " Peak working set = {0} MB", Process.GetCurrentProcess().PeakWorkingSet64 / (1024 * 1024));
if (TotalErrors > 0)
Logger.Log(Severity.Info, "EXTRACTION FAILED with {0} error{1} in {2}", TotalErrors, TotalErrors == 1 ? "" : "s", stopWatch.Elapsed);
else
Logger.Log(Severity.Info, "EXTRACTION SUCCEEDED in {0}", stopWatch.Elapsed);
Logger.Dispose();
}
/// <summary>
/// Number of errors encountered during extraction.
/// </summary>
private int ExtractorErrors => extractor?.Errors ?? 0;
/// <summary>
/// Number of errors encountered by the compiler.
/// </summary>
public int CompilationErrors { get; set; }
/// <summary>
/// Total number of errors reported.
/// </summary>
public int TotalErrors => CompilationErrors + ExtractorErrors;
/// <summary>
/// Logs information about the extractor.
/// </summary>
public void LogExtractorInfo(string extractorVersion)
{
Logger.Log(Severity.Info, " Extractor: {0}", Environment.GetCommandLineArgs().First());
Logger.Log(Severity.Info, " Extractor version: {0}", extractorVersion);
Logger.Log(Severity.Info, " Current working directory: {0}", Directory.GetCurrentDirectory());
}
}
}

View File

@@ -0,0 +1,12 @@
namespace Semmle.Extraction.CSharp
{
/// <summary>
/// What action was performed when extracting a file.
/// </summary>
public enum AnalysisAction
{
Extracted,
UpToDate,
Excluded
}
}

View File

@@ -14,12 +14,12 @@ namespace Semmle.Extraction.CSharp
public class CompilerVersion
{
private const string csc_rsp = "csc.rsp";
private readonly string specifiedFramework = null;
private readonly string? specifiedFramework = null;
/// <summary>
/// The value specified by --compiler, or null.
/// </summary>
public string SpecifiedCompiler
public string? SpecifiedCompiler
{
get;
private set;
@@ -28,12 +28,20 @@ namespace Semmle.Extraction.CSharp
/// <summary>
/// Why was the candidate exe rejected as a compiler?
/// </summary>
public string SkipReason
public string? SkipReason
{
get;
private set;
}
private static readonly Dictionary<string, string> knownCompilerNames = new Dictionary<string, string>
{
{ "csc.exe", "Microsoft" },
{ "csc2.exe", "Microsoft" },
{ "csc.dll", "Microsoft" },
{ "mcs.exe", "Novell" }
};
/// <summary>
/// Probes the compiler (if specified).
/// </summary>
@@ -52,16 +60,13 @@ namespace Semmle.Extraction.CSharp
}
// Reads the file details from the .exe
var versionInfo = FileVersionInfo.GetVersionInfo(SpecifiedCompiler);
var compilerDir = Path.GetDirectoryName(SpecifiedCompiler);
var knownCompilerNames = new Dictionary<string, string>
if (compilerDir is null)
{
{ "csc.exe", "Microsoft" },
{ "csc2.exe", "Microsoft" },
{ "csc.dll", "Microsoft" },
{ "mcs.exe", "Novell" }
};
SkipExtractionBecause("the compiler directory could not be retrieved");
return;
}
var mscorlibExists = File.Exists(Path.Combine(compilerDir, "mscorlib.dll"));
if (specifiedFramework == null && mscorlibExists)
@@ -69,7 +74,8 @@ namespace Semmle.Extraction.CSharp
specifiedFramework = compilerDir;
}
if (!knownCompilerNames.TryGetValue(versionInfo.OriginalFilename, out var vendor))
var versionInfo = FileVersionInfo.GetVersionInfo(SpecifiedCompiler);
if (!knownCompilerNames.TryGetValue(versionInfo.OriginalFilename ?? string.Empty, out var vendor))
{
SkipExtractionBecause("the compiler name is not recognised");
return;
@@ -114,7 +120,7 @@ namespace Semmle.Extraction.CSharp
/// <summary>
/// Gets additional reference directories - the compiler directory.
/// </summary>
public string AdditionalReferenceDirectories => SpecifiedCompiler != null ? Path.GetDirectoryName(SpecifiedCompiler) : null;
public string? AdditionalReferenceDirectories => SpecifiedCompiler != null ? Path.GetDirectoryName(SpecifiedCompiler) : null;
/// <summary>
/// Adds @csc.rsp to the argument list to mimic csc.exe.
@@ -134,6 +140,6 @@ namespace Semmle.Extraction.CSharp
return args.Any(arg => new[] { "/noconfig", "-noconfig" }.Contains(arg.ToLowerInvariant()));
}
public IEnumerable<string> ArgsWithResponse { get; }
public IEnumerable<string> ArgsWithResponse { get; } = Enumerable.Empty<string>();
}
}

View File

@@ -29,7 +29,7 @@ namespace Semmle.Extraction.CSharp
return cachedModel;
}
private SemanticModel cachedModel;
private SemanticModel? cachedModel;
/// <summary>
/// The current compilation unit.
@@ -51,7 +51,7 @@ namespace Semmle.Extraction.CSharp
public bool IsAssemblyScope => scope is AssemblyScope;
private SyntaxTree SourceTree => scope is SourceScope sc ? sc.SourceTree : null;
private SyntaxTree? SourceTree => scope is SourceScope sc ? sc.SourceTree : null;
/// <summary>
/// Whether the given symbol needs to be defined in this context.
@@ -85,7 +85,7 @@ namespace Semmle.Extraction.CSharp
: CreateLocation(Microsoft.CodeAnalysis.Location.Create(SourceTree, Microsoft.CodeAnalysis.Text.TextSpan.FromBounds(0, 0)));
}
public override Extraction.Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location location)
public override Extraction.Entities.Location CreateLocation(Microsoft.CodeAnalysis.Location? location)
{
return (location == null || location.Kind == LocationKind.None)
? GeneratedLocation.Create(this)
@@ -100,13 +100,13 @@ namespace Semmle.Extraction.CSharp
/// <param name="cx">Extractor context.</param>
/// <param name="entity">Program entity.</param>
/// <param name="l">Location of the entity.</param>
public void BindComments(Entity entity, Microsoft.CodeAnalysis.Location l)
public void BindComments(Entity entity, Microsoft.CodeAnalysis.Location? l)
{
var duplicationGuardKey = GetCurrentTagStackKey();
CommentGenerator.AddElement(entity.Label, duplicationGuardKey, l);
}
protected override bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(true)] out Extraction.Entities.Location loc)
protected override bool IsEntityDuplicationGuarded(IEntity entity, [NotNullWhen(true)] out Extraction.Entities.Location? loc)
{
if (CreateLocation(entity.ReportingLocation) is Entities.NonGeneratedSourceLocation l)
{

View File

@@ -71,13 +71,13 @@ namespace Semmle.Extraction.CSharp
Entities.Compilation.Settings = (Directory.GetCurrentDirectory(), args);
var commandLineArguments = Options.CreateWithEnvironment(Entities.Compilation.Settings.Args);
var fileLogger = new FileLogger(commandLineArguments.Verbosity, GetCSharpLogPath());
using var logger = commandLineArguments.Console
? new CombinedLogger(new ConsoleLogger(commandLineArguments.Verbosity), fileLogger)
var options = Options.CreateWithEnvironment(Entities.Compilation.Settings.Args);
var fileLogger = new FileLogger(options.Verbosity, GetCSharpLogPath());
using var logger = options.Console
? new CombinedLogger(new ConsoleLogger(options.Verbosity), fileLogger)
: (ILogger)fileLogger;
if (Environment.GetEnvironmentVariable("SEMMLE_CLRTRACER") == "1" && !commandLineArguments.ClrTracer)
if (Environment.GetEnvironmentVariable("SEMMLE_CLRTRACER") == "1" && !options.ClrTracer)
{
logger.Log(Severity.Info, "Skipping extraction since already extracted from the CLR tracer");
return ExitCode.Ok;
@@ -86,11 +86,11 @@ namespace Semmle.Extraction.CSharp
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
var pathTransformer = new PathTransformer(canonicalPathCache);
using var analyser = new Analyser(new LogProgressMonitor(logger), logger, commandLineArguments.AssemblySensitiveTrap, pathTransformer);
using var references = new BlockingCollection<MetadataReference>();
using var analyser = new TracingAnalyser(new LogProgressMonitor(logger), logger, options.AssemblySensitiveTrap, pathTransformer);
try
{
var compilerVersion = new CompilerVersion(commandLineArguments);
var compilerVersion = new CompilerVersion(options);
if (compilerVersion.SkipExtraction)
{
@@ -120,80 +120,7 @@ namespace Semmle.Extraction.CSharp
return ExitCode.Ok;
}
var referenceTasks = ResolveReferences(compilerArguments, analyser, canonicalPathCache, references);
var syntaxTrees = new List<SyntaxTree>();
var syntaxTreeTasks = ReadSyntaxTrees(
compilerArguments.SourceFiles.
Select(src => canonicalPathCache.GetCanonicalPath(src.Path)),
analyser,
compilerArguments.ParseOptions,
compilerArguments.Encoding,
syntaxTrees);
var sw1 = new Stopwatch();
sw1.Start();
Parallel.Invoke(
new ParallelOptions { MaxDegreeOfParallelism = commandLineArguments.Threads },
referenceTasks.Interleave(syntaxTreeTasks).ToArray());
if (syntaxTrees.Count == 0)
{
logger.Log(Severity.Error, " No source files");
++analyser.CompilationErrors;
return ExitCode.Failed;
}
// csc.exe (CSharpCompiler.cs) also provides CompilationOptions
// .WithMetadataReferenceResolver(),
// .WithXmlReferenceResolver() and
// .WithSourceReferenceResolver().
// These would be needed if we hadn't explicitly provided the source/references
// already.
var compilation = CSharpCompilation.Create(
compilerArguments.CompilationName,
syntaxTrees,
references,
compilerArguments.CompilationOptions.
WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default).
WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths))
);
analyser.EndInitialize(compilerArguments, commandLineArguments, compilation);
analyser.AnalyseCompilation();
analyser.AnalyseReferences();
foreach (var tree in compilation.SyntaxTrees)
{
analyser.AnalyseTree(tree);
}
var currentProcess = Process.GetCurrentProcess();
var cpuTime1 = currentProcess.TotalProcessorTime;
var userTime1 = currentProcess.UserProcessorTime;
sw1.Stop();
logger.Log(Severity.Info, " Models constructed in {0}", sw1.Elapsed);
var sw2 = new Stopwatch();
sw2.Start();
analyser.PerformExtraction(commandLineArguments.Threads);
sw2.Stop();
var cpuTime2 = currentProcess.TotalProcessorTime;
var userTime2 = currentProcess.UserProcessorTime;
var performance = new Entities.PerformanceMetrics()
{
Frontend = new Entities.Timings() { Elapsed = sw1.Elapsed, Cpu = cpuTime1, User = userTime1 },
Extractor = new Entities.Timings() { Elapsed = sw2.Elapsed, Cpu = cpuTime2 - cpuTime1, User = userTime2 - userTime1 },
Total = new Entities.Timings() { Elapsed = stopwatch.Elapsed, Cpu = cpuTime2, User = userTime2 },
PeakWorkingSet = currentProcess.PeakWorkingSet64
};
analyser.LogPerformance(performance);
logger.Log(Severity.Info, " Extraction took {0}", sw2.Elapsed);
return analyser.TotalErrors == 0 ? ExitCode.Ok : ExitCode.Errors;
return AnalyseTracing(analyser, compilerArguments, options, canonicalPathCache, stopwatch);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
@@ -216,7 +143,10 @@ namespace Semmle.Extraction.CSharp
// 3) Directories specified by / lib.
// 4) Directories specified by the LIB environment variable.
yield return args.BaseDirectory;
if (args.BaseDirectory is object)
{
yield return args.BaseDirectory;
}
foreach (var r in args.ReferencePaths)
yield return r;
@@ -289,7 +219,7 @@ namespace Semmle.Extraction.CSharp
/// The constructed syntax trees will be added (thread-safely) to the supplied
/// list <paramref name="ret"/>.
/// </summary>
private static IEnumerable<Action> ReadSyntaxTrees(IEnumerable<string> sources, Analyser analyser, CSharpParseOptions parseOptions, Encoding encoding, IList<SyntaxTree> ret)
private static IEnumerable<Action> ReadSyntaxTrees(IEnumerable<string> sources, Analyser analyser, CSharpParseOptions? parseOptions, Encoding? encoding, IList<SyntaxTree> ret)
{
return sources.Select<string, Action>(path => () =>
{
@@ -318,68 +248,16 @@ namespace Semmle.Extraction.CSharp
ILogger logger,
CommonOptions options)
{
var stopwatch = new Stopwatch();
stopwatch.Start();
var canonicalPathCache = CanonicalPathCache.Create(logger, 1000);
var pathTransformer = new PathTransformer(canonicalPathCache);
using var analyser = new Analyser(pm, logger, false, pathTransformer);
using var references = new BlockingCollection<MetadataReference>();
using var analyser = new StandaloneAnalyser(pm, logger, false, pathTransformer);
try
{
var referenceTasks = referencePaths.Select<string, Action>(path => () =>
{
var reference = MetadataReference.CreateFromFile(path);
references.Add(reference);
});
var syntaxTrees = new List<SyntaxTree>();
var syntaxTreeTasks = ReadSyntaxTrees(sources, analyser, null, null, syntaxTrees);
var sw = new Stopwatch();
sw.Start();
Parallel.Invoke(
new ParallelOptions { MaxDegreeOfParallelism = options.Threads },
referenceTasks.Interleave(syntaxTreeTasks).ToArray());
if (syntaxTrees.Count == 0)
{
analyser.Logger.Log(Severity.Error, " No source files");
++analyser.CompilationErrors;
}
var compilation = CSharpCompilation.Create(
"csharp.dll",
syntaxTrees,
references
);
analyser.InitializeStandalone(compilation, options);
analyser.AnalyseReferences();
foreach (var tree in compilation.SyntaxTrees)
{
analyser.AnalyseTree(tree);
}
sw.Stop();
analyser.Logger.Log(Severity.Info, " Models constructed in {0}", sw.Elapsed);
sw.Restart();
analyser.PerformExtraction(options.Threads);
sw.Stop();
analyser.Logger.Log(Severity.Info, " Extraction took {0}", sw.Elapsed);
foreach (var type in analyser.MissingNamespaces)
{
pm.MissingNamespace(type);
}
foreach (var type in analyser.MissingTypes)
{
pm.MissingType(type);
}
pm.MissingSummary(analyser.MissingTypes.Count(), analyser.MissingNamespaces.Count());
AnalyseStandalone(analyser, sources, referencePaths, options, pm, stopwatch);
}
catch (Exception ex) // lgtm[cs/catch-of-all-exceptions]
{
@@ -387,6 +265,160 @@ namespace Semmle.Extraction.CSharp
}
}
private static ExitCode Analyse(Stopwatch stopwatch, Analyser analyser, CommonOptions options,
Func<BlockingCollection<MetadataReference>, IEnumerable<Action>> getResolvedReferenceTasks,
Func<Analyser, List<SyntaxTree>, IEnumerable<Action>> getSyntaxTreeTasks,
Func<IEnumerable<SyntaxTree>, IEnumerable<MetadataReference>, CSharpCompilation> getCompilation,
Action<CSharpCompilation, CommonOptions> initializeAnalyser,
Action analyseCompilation,
Action<Entities.PerformanceMetrics> logPerformance,
Action postProcess)
{
using var references = new BlockingCollection<MetadataReference>();
var referenceTasks = getResolvedReferenceTasks(references);
var syntaxTrees = new List<SyntaxTree>();
var syntaxTreeTasks = getSyntaxTreeTasks(analyser, syntaxTrees);
var sw = new Stopwatch();
sw.Start();
Parallel.Invoke(
new ParallelOptions { MaxDegreeOfParallelism = options.Threads },
referenceTasks.Interleave(syntaxTreeTasks).ToArray());
if (syntaxTrees.Count == 0)
{
analyser.Logger.Log(Severity.Error, " No source files");
++analyser.CompilationErrors;
if (analyser is TracingAnalyser)
{
return ExitCode.Failed;
}
}
var compilation = getCompilation(syntaxTrees, references);
initializeAnalyser(compilation, options);
analyseCompilation();
analyser.AnalyseReferences();
foreach (var tree in compilation.SyntaxTrees)
{
analyser.AnalyseTree(tree);
}
sw.Stop();
analyser.Logger.Log(Severity.Info, " Models constructed in {0}", sw.Elapsed);
var elapsed = sw.Elapsed;
var currentProcess = Process.GetCurrentProcess();
var cpuTime1 = currentProcess.TotalProcessorTime;
var userTime1 = currentProcess.UserProcessorTime;
sw.Restart();
analyser.PerformExtraction(options.Threads);
sw.Stop();
var cpuTime2 = currentProcess.TotalProcessorTime;
var userTime2 = currentProcess.UserProcessorTime;
var performance = new Entities.PerformanceMetrics()
{
Frontend = new Entities.Timings() { Elapsed = elapsed, Cpu = cpuTime1, User = userTime1 },
Extractor = new Entities.Timings() { Elapsed = sw.Elapsed, Cpu = cpuTime2 - cpuTime1, User = userTime2 - userTime1 },
Total = new Entities.Timings() { Elapsed = stopwatch.Elapsed, Cpu = cpuTime2, User = userTime2 },
PeakWorkingSet = currentProcess.PeakWorkingSet64
};
logPerformance(performance);
analyser.Logger.Log(Severity.Info, " Extraction took {0}", sw.Elapsed);
postProcess();
return analyser.TotalErrors == 0 ? ExitCode.Ok : ExitCode.Errors;
}
private static void AnalyseStandalone(
StandaloneAnalyser analyser,
IEnumerable<string> sources,
IEnumerable<string> referencePaths,
CommonOptions options,
IProgressMonitor progressMonitor,
Stopwatch stopwatch)
{
Analyse(stopwatch, analyser, options,
references => GetResolvedReferencesStandalone(referencePaths, references),
(analyser, syntaxTrees) => ReadSyntaxTrees(sources, analyser, null, null, syntaxTrees),
(syntaxTrees, references) => CSharpCompilation.Create("csharp.dll", syntaxTrees, references),
(compilation, options) => analyser.InitializeStandalone(compilation, options),
() => { },
_ => { },
() =>
{
foreach (var type in analyser.MissingNamespaces)
{
progressMonitor.MissingNamespace(type);
}
foreach (var type in analyser.MissingTypes)
{
progressMonitor.MissingType(type);
}
progressMonitor.MissingSummary(analyser.MissingTypes.Count(), analyser.MissingNamespaces.Count());
});
}
private static ExitCode AnalyseTracing(
TracingAnalyser analyser,
CSharpCommandLineArguments compilerArguments,
Options options,
CanonicalPathCache canonicalPathCache,
Stopwatch stopwatch)
{
return Analyse(stopwatch, analyser, options,
references => ResolveReferences(compilerArguments, analyser, canonicalPathCache, references),
(analyser, syntaxTrees) =>
{
return ReadSyntaxTrees(
compilerArguments.SourceFiles.Select(src => canonicalPathCache.GetCanonicalPath(src.Path)),
analyser,
compilerArguments.ParseOptions,
compilerArguments.Encoding,
syntaxTrees);
},
(syntaxTrees, references) =>
{
// csc.exe (CSharpCompiler.cs) also provides CompilationOptions
// .WithMetadataReferenceResolver(),
// .WithXmlReferenceResolver() and
// .WithSourceReferenceResolver().
// These would be needed if we hadn't explicitly provided the source/references
// already.
return CSharpCompilation.Create(
compilerArguments.CompilationName,
syntaxTrees,
references,
compilerArguments.CompilationOptions.
WithAssemblyIdentityComparer(DesktopAssemblyIdentityComparer.Default).
WithStrongNameProvider(new DesktopStrongNameProvider(compilerArguments.KeyFileSearchPaths))
);
},
(compilation, options) => analyser.EndInitialize(compilerArguments, options, compilation),
() => analyser.AnalyseCompilation(),
performance => analyser.LogPerformance(performance),
() => { });
}
private static IEnumerable<Action> GetResolvedReferencesStandalone(IEnumerable<string> referencePaths, BlockingCollection<MetadataReference> references)
{
return referencePaths.Select<string, Action>(path => () =>
{
var reference = MetadataReference.CreateFromFile(path);
references.Add(reference);
});
}
/// <summary>
/// Gets the path to the `csharp.log` file written to by the C# extractor.
/// </summary>

Some files were not shown because too many files have changed in this diff Show More