mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
Merge pull request #5197 from tamasvajk/feature/refactor-4
C#: Enable nullability in Extraction.CSharp
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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; } }
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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><0 if l1 before l2, >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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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."),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
|
||||
@@ -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('(');
|
||||
|
||||
@@ -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!));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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 { ... }'
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
311
csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs
Normal file
311
csharp/extractor/Semmle.Extraction.CSharp/Extractor/Analyser.cs
Normal 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// What action was performed when extracting a file.
|
||||
/// </summary>
|
||||
public enum AnalysisAction
|
||||
{
|
||||
Extracted,
|
||||
UpToDate,
|
||||
Excluded
|
||||
}
|
||||
}
|
||||
@@ -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>();
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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
Reference in New Issue
Block a user