зеркало из https://github.com/github/codeql.git
C#: Compare CIL entities directly by handle rather than by label.
C#: Remove IDs from the CIL extractor and make consistent with C# extractor. C#: Fix method collisions.
This commit is contained in:
Родитель
685c494bcb
Коммит
b500a02b1e
|
@ -31,7 +31,7 @@ namespace Semmle.Extraction.CIL
|
|||
mdReader = peReader.GetMetadataReader();
|
||||
TypeSignatureDecoder = new Entities.TypeSignatureDecoder(this);
|
||||
|
||||
globalNamespace = new Lazy<Entities.Namespace>(() => Populate(new Entities.Namespace(this, GetId(""), null)));
|
||||
globalNamespace = new Lazy<Entities.Namespace>(() => Populate(new Entities.Namespace(this, "", null)));
|
||||
systemNamespace = new Lazy<Entities.Namespace>(() => Populate(new Entities.Namespace(this, "System")));
|
||||
genericHandleFactory = new CachedFunction<GenericContext, Handle, ILabelledEntity>(CreateGenericHandle);
|
||||
namespaceFactory = new CachedFunction<StringHandle, Entities.Namespace>(n => CreateNamespace(mdReader.GetString(n)));
|
||||
|
@ -42,9 +42,6 @@ namespace Semmle.Extraction.CIL
|
|||
|
||||
defaultGenericContext = new EmptyContext(this);
|
||||
|
||||
var def = mdReader.GetAssemblyDefinition();
|
||||
AssemblyPrefix = GetId(def.Name) + "_" + def.Version.ToString() + "::";
|
||||
|
||||
if (extractPdbs)
|
||||
{
|
||||
pdb = PDB.PdbReader.Create(assemblyPath, peReader);
|
||||
|
@ -75,7 +72,14 @@ namespace Semmle.Extraction.CIL
|
|||
}
|
||||
}
|
||||
|
||||
public readonly Id AssemblyPrefix;
|
||||
public void WriteAssemblyPrefix(TextWriter trapFile)
|
||||
{
|
||||
var def = mdReader.GetAssemblyDefinition();
|
||||
trapFile.Write(GetString(def.Name));
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(def.Version.ToString());
|
||||
trapFile.Write("::");
|
||||
}
|
||||
|
||||
public readonly Entities.TypeSignatureDecoder TypeSignatureDecoder;
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Collections.Generic;
|
|||
using Semmle.Util.Logging;
|
||||
using System;
|
||||
using Semmle.Extraction.Entities;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
|
@ -20,8 +21,6 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
/// </summary>
|
||||
public class Assembly : LabelledEntity, IAssembly
|
||||
{
|
||||
public override Id IdSuffix => suffix;
|
||||
|
||||
readonly File file;
|
||||
readonly AssemblyName assemblyName;
|
||||
|
||||
|
@ -38,12 +37,24 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
if (!def.PublicKey.IsNil)
|
||||
assemblyName.SetPublicKey(cx.mdReader.GetBlobBytes(def.PublicKey));
|
||||
|
||||
ShortId = cx.GetId(FullName) + "#file:///" + cx.assemblyPath.Replace("\\", "/");
|
||||
|
||||
file = new File(cx, cx.assemblyPath);
|
||||
}
|
||||
|
||||
static readonly Id suffix = new StringId(";assembly");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(FullName);
|
||||
trapFile.Write("#file:///");
|
||||
trapFile.Write(cx.assemblyPath.Replace("\\", "/"));
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return GetType() == obj.GetType() && Equals(file, ((Assembly)obj).file);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 7 * file.GetHashCode();
|
||||
|
||||
public override string IdSuffix => ";assembly";
|
||||
|
||||
string FullName => assemblyName.GetPublicKey() is null ? assemblyName.FullName + ", PublicKeyToken=null" : assemblyName.FullName;
|
||||
|
||||
|
|
|
@ -14,8 +14,9 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
/// <summary>
|
||||
/// Entity representing a CIL attribute.
|
||||
/// </summary>
|
||||
class Attribute : UnlabelledEntity, IAttribute
|
||||
sealed class Attribute : UnlabelledEntity, IAttribute
|
||||
{
|
||||
readonly CustomAttributeHandle handle;
|
||||
readonly CustomAttribute attrib;
|
||||
readonly IEntity @object;
|
||||
|
||||
|
@ -25,6 +26,13 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
this.@object = @object;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Attribute attribute && handle.Equals(attribute.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
|
@ -78,7 +86,7 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
readonly Context cx;
|
||||
public CustomAttributeDecoder(Context cx) { this.cx = cx; }
|
||||
|
||||
public Type GetPrimitiveType(PrimitiveTypeCode typeCode) => cx.Populate(new PrimitiveType(cx, typeCode));
|
||||
public Type GetPrimitiveType(PrimitiveTypeCode typeCode) => cx.Create(typeCode);
|
||||
|
||||
public Type GetSystemType() => throw new NotImplementedException();
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
|
@ -13,19 +14,35 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
/// <summary>
|
||||
/// An event entity.
|
||||
/// </summary>
|
||||
class Event : LabelledEntity, IEvent
|
||||
sealed class Event : LabelledEntity, IEvent
|
||||
{
|
||||
readonly EventDefinitionHandle handle;
|
||||
readonly Type parent;
|
||||
readonly EventDefinition ed;
|
||||
static readonly Id suffix = CIL.Id.Create(";cil-event");
|
||||
|
||||
public Event(Context cx, Type parent, EventDefinitionHandle handle) : base(cx)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.parent = parent;
|
||||
ed = cx.mdReader.GetEventDefinition(handle);
|
||||
ShortId = parent.ShortId + cx.Dot + cx.ShortName(ed.Name) + suffix;
|
||||
}
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
parent.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(cx.ShortName(ed.Name));
|
||||
}
|
||||
|
||||
public override string IdSuffix => ";cil-event";
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Event e && handle.Equals(e.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
|
@ -61,7 +78,5 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
yield return c;
|
||||
}
|
||||
}
|
||||
|
||||
public override Id IdSuffix => suffix;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,28 +37,24 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
|
||||
public Label Label { get; set; }
|
||||
|
||||
public IId Id => ShortId + IdSuffix;
|
||||
|
||||
public void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteIId(Id);
|
||||
trapFile.WriteSubId(DeclaringType);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(Name);
|
||||
}
|
||||
|
||||
public void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("@\"");
|
||||
WriteId(trapFile);
|
||||
trapFile.Write(IdSuffix);
|
||||
trapFile.Write('\"');
|
||||
}
|
||||
|
||||
public Id IdSuffix => fieldSuffix;
|
||||
public string IdSuffix => ";cil-field";
|
||||
|
||||
static readonly StringId fieldSuffix = new StringId(";cil-field");
|
||||
|
||||
public Id ShortId
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public abstract Id Name { get; }
|
||||
public abstract string Name { get; }
|
||||
|
||||
public abstract Type DeclaringType { get; }
|
||||
|
||||
|
@ -70,7 +66,7 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.cil_field(this, DeclaringType, Name.Value, Type);
|
||||
yield return Tuples.cil_field(this, DeclaringType, Name, Type);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -93,9 +89,15 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
this.handle = handle;
|
||||
this.gc = gc;
|
||||
fd = cx.mdReader.GetFieldDefinition(handle);
|
||||
ShortId = DeclaringType.ShortId + cx.Dot + Name;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is DefinitionField field && handle.Equals(field.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
|
@ -125,7 +127,7 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
}
|
||||
}
|
||||
|
||||
public override Id Name => cx.GetId(fd.Name);
|
||||
public override string Name => cx.GetString(fd.Name);
|
||||
|
||||
public override Type DeclaringType => (Type)cx.Create(fd.GetDeclaringType());
|
||||
|
||||
|
@ -138,19 +140,30 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
|
||||
sealed class MemberReferenceField : Field
|
||||
{
|
||||
readonly MemberReferenceHandle Handle;
|
||||
readonly MemberReference mr;
|
||||
readonly GenericContext gc;
|
||||
readonly Type declType;
|
||||
|
||||
public MemberReferenceField(GenericContext gc, MemberReferenceHandle handle) : base(gc.cx)
|
||||
{
|
||||
Handle = handle;
|
||||
this.gc = gc;
|
||||
mr = cx.mdReader.GetMemberReference(handle);
|
||||
declType = (Type)cx.CreateGeneric(gc, mr.Parent);
|
||||
ShortId = declType.ShortId + cx.Dot + Name;
|
||||
}
|
||||
|
||||
public override Id Name => cx.GetId(mr.Name);
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is MemberReferenceField field && Handle.Equals(field.Handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Handle.GetHashCode();
|
||||
}
|
||||
|
||||
public override string Name => cx.GetString(mr.Name);
|
||||
|
||||
public override Type DeclaringType => declType;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
|
@ -17,9 +18,20 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
public File(Context cx, string path) : base(cx)
|
||||
{
|
||||
this.path = Semmle.Extraction.Entities.File.PathAsDatabaseString(path);
|
||||
ShortId = new StringId(Semmle.Extraction.Entities.File.PathAsDatabaseId(path));
|
||||
}
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(Semmle.Extraction.Entities.File.PathAsDatabaseId(path));
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return GetType() == obj.GetType() && path == ((File)obj).path;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 11 * path.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
|
@ -31,9 +43,7 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
}
|
||||
}
|
||||
|
||||
public override Id IdSuffix => suffix;
|
||||
|
||||
static readonly Id suffix = new StringId(";sourcefile");
|
||||
public override string IdSuffix => ";sourcefile";
|
||||
}
|
||||
|
||||
public class PdbSourceFile : File
|
||||
|
|
|
@ -7,17 +7,22 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
{
|
||||
}
|
||||
|
||||
public class Folder : LabelledEntity, IFolder
|
||||
public sealed class Folder : LabelledEntity, IFolder
|
||||
{
|
||||
readonly string path;
|
||||
|
||||
public Folder(Context cx, string path) : base(cx)
|
||||
{
|
||||
this.path = path;
|
||||
ShortId = new StringId(Semmle.Extraction.Entities.File.PathAsDatabaseId(path));
|
||||
}
|
||||
|
||||
static readonly Id suffix = new StringId(";folder");
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(Semmle.Extraction.Entities.File.PathAsDatabaseId(path));
|
||||
}
|
||||
|
||||
public override string IdSuffix => ";folder";
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
|
@ -37,6 +42,11 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
}
|
||||
}
|
||||
|
||||
public override Id IdSuffix => suffix;
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Folder folder && path == folder.path;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => path.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
|
@ -17,12 +18,16 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
method = m;
|
||||
index = i;
|
||||
type = t;
|
||||
ShortId = CIL.Id.Create(method.Label) + underscore + index;
|
||||
}
|
||||
|
||||
static readonly Id underscore = CIL.Id.Create("_");
|
||||
static readonly Id suffix = CIL.Id.Create(";cil-local");
|
||||
public override Id IdSuffix => suffix;
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(method);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(index);
|
||||
}
|
||||
|
||||
public override string IdSuffix => ";cil-local";
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Reflection;
|
|||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.IO;
|
||||
using Semmle.Util;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
|
@ -42,34 +43,40 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
public virtual IList<LocalVariable> LocalVariables => throw new NotImplementedException();
|
||||
public IList<Parameter> Parameters { get; private set; }
|
||||
|
||||
static readonly Id tick = CIL.Id.Create("`");
|
||||
static readonly Id space = CIL.Id.Create(" ");
|
||||
static readonly Id dot = CIL.Id.Create(".");
|
||||
static readonly Id open = CIL.Id.Create("(");
|
||||
static readonly Id close = CIL.Id.Create(")");
|
||||
public override void WriteId(TextWriter trapFile) => MakeMethodId(trapFile, DeclaringType, NameLabel);
|
||||
|
||||
internal protected Id MakeMethodId(Type parent, Id methodName)
|
||||
public abstract string NameLabel { get; }
|
||||
|
||||
internal protected void MakeMethodId(TextWriter trapFile, Type parent, string methodName)
|
||||
{
|
||||
var id = signature.ReturnType.MakeId(this) + space + parent.ShortId + dot + methodName;
|
||||
signature.ReturnType.WriteId(trapFile, this);
|
||||
trapFile.Write(' ');
|
||||
parent.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(methodName);
|
||||
|
||||
if (signature.GenericParameterCount > 0)
|
||||
{
|
||||
id += tick + signature.GenericParameterCount;
|
||||
trapFile.Write('`');
|
||||
trapFile.Write(signature.GenericParameterCount);
|
||||
}
|
||||
|
||||
id += open + CIL.Id.CommaSeparatedList(signature.ParameterTypes.Select(p => p.MakeId(this))) + close;
|
||||
return id;
|
||||
trapFile.Write('(');
|
||||
int index = 0;
|
||||
foreach (var param in signature.ParameterTypes)
|
||||
{
|
||||
trapFile.WriteSeparator(",", index++);
|
||||
param.WriteId(trapFile, this);
|
||||
}
|
||||
trapFile.Write(')');
|
||||
}
|
||||
|
||||
protected MethodTypeParameter[] genericParams;
|
||||
protected Type declaringType;
|
||||
protected GenericContext gc;
|
||||
protected MethodSignature<ITypeSignature> signature;
|
||||
protected Id name;
|
||||
protected string name;
|
||||
|
||||
static readonly StringId methodSuffix = new StringId(";cil-method");
|
||||
|
||||
public override Id IdSuffix => methodSuffix;
|
||||
public override string IdSuffix => ";cil-method";
|
||||
|
||||
protected void PopulateParameters(IEnumerable<Type> parameterTypes)
|
||||
{
|
||||
|
@ -134,7 +141,7 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
/// <summary>
|
||||
/// A definition method - a method defined in the current assembly.
|
||||
/// </summary>
|
||||
class DefinitionMethod : Method, IMember
|
||||
sealed class DefinitionMethod : Method, IMember
|
||||
{
|
||||
readonly Handle handle;
|
||||
readonly MethodDefinition md;
|
||||
|
@ -151,22 +158,30 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
md = cx.mdReader.GetMethodDefinition(handle);
|
||||
this.gc = gc;
|
||||
this.handle = handle;
|
||||
name = cx.GetId(md.Name);
|
||||
name = cx.GetString(md.Name);
|
||||
|
||||
declaringType = (Type)cx.CreateGeneric(this, md.GetDeclaringType());
|
||||
|
||||
signature = md.DecodeSignature(new SignatureDecoder(), this);
|
||||
ShortId = MakeMethodId(declaringType, name);
|
||||
|
||||
methodDebugInformation = cx.GetMethodDebugInformation(handle);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is DefinitionMethod method && handle.Equals(method.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override bool IsStatic => !signature.Header.IsInstance;
|
||||
|
||||
public override Type DeclaringType => declaringType;
|
||||
|
||||
public override string Name => cx.ShortName(md.Name);
|
||||
|
||||
public override string NameLabel => name;
|
||||
|
||||
/// <summary>
|
||||
/// Holds if this method has bytecode.
|
||||
/// </summary>
|
||||
|
@ -382,8 +397,9 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
/// <summary>
|
||||
/// This is a late-bound reference to a method.
|
||||
/// </summary>
|
||||
class MemberReferenceMethod : Method
|
||||
sealed class MemberReferenceMethod : Method
|
||||
{
|
||||
readonly MemberReferenceHandle handle;
|
||||
readonly MemberReference mr;
|
||||
readonly Type declType;
|
||||
readonly GenericContext parent;
|
||||
|
@ -391,6 +407,7 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
|
||||
public MemberReferenceMethod(GenericContext gc, MemberReferenceHandle handle) : base(gc)
|
||||
{
|
||||
this.handle = handle;
|
||||
this.gc = gc;
|
||||
mr = cx.mdReader.GetMemberReference(handle);
|
||||
|
||||
|
@ -399,19 +416,31 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
parent = (GenericContext)cx.CreateGeneric(gc, mr.Parent);
|
||||
|
||||
var parentMethod = parent as Method;
|
||||
var nameLabel = cx.GetId(mr.Name);
|
||||
nameLabel = cx.GetString(mr.Name);
|
||||
|
||||
declType = parentMethod == null ? parent as Type : parentMethod.DeclaringType;
|
||||
|
||||
if (declType is null)
|
||||
throw new InternalError("Parent context of method is not a type");
|
||||
|
||||
ShortId = MakeMethodId(declType, nameLabel);
|
||||
|
||||
var typeSourceDeclaration = declType.SourceDeclaration;
|
||||
sourceDeclaration = typeSourceDeclaration == declType ? (Method)this : typeSourceDeclaration.LookupMethod(mr.Name, mr.Signature);
|
||||
}
|
||||
|
||||
private readonly string nameLabel;
|
||||
|
||||
public override string NameLabel => nameLabel;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is MemberReferenceMethod method && handle.Equals(method.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return handle.GetHashCode();
|
||||
}
|
||||
|
||||
public override Method SourceDeclaration => sourceDeclaration;
|
||||
|
||||
public override bool IsStatic => !signature.Header.IsInstance;
|
||||
|
@ -451,26 +480,46 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
/// <summary>
|
||||
/// A constructed method.
|
||||
/// </summary>
|
||||
class MethodSpecificationMethod : Method
|
||||
sealed class MethodSpecificationMethod : Method
|
||||
{
|
||||
readonly MethodSpecificationHandle handle;
|
||||
readonly MethodSpecification ms;
|
||||
readonly Method unboundMethod;
|
||||
readonly ImmutableArray<Type> typeParams;
|
||||
|
||||
public MethodSpecificationMethod(GenericContext 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);
|
||||
declaringType = unboundMethod.DeclaringType;
|
||||
|
||||
ShortId = unboundMethod.ShortId + openAngle + CIL.Id.CommaSeparatedList(typeParams.Select(p => p.ShortId)) + closeAngle;
|
||||
}
|
||||
|
||||
static readonly Id openAngle = CIL.Id.Create("<");
|
||||
static readonly Id closeAngle = CIL.Id.Create(">");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
unboundMethod.WriteId(trapFile);
|
||||
trapFile.Write('<');
|
||||
int index = 0;
|
||||
foreach(var param in typeParams)
|
||||
{
|
||||
trapFile.WriteSeparator(",", index++);
|
||||
trapFile.WriteSubId(param);
|
||||
}
|
||||
trapFile.Write('>');
|
||||
}
|
||||
|
||||
public override string NameLabel => throw new NotImplementedException();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is MethodSpecificationMethod method && handle.Equals(method.handle) && typeParams.SequenceEqual(method.typeParams);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return handle.GetHashCode() * 11 + typeParams.SequenceHash();
|
||||
}
|
||||
|
||||
public override Method SourceDeclaration => unboundMethod;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
|
@ -14,28 +15,43 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
/// <summary>
|
||||
/// A namespace.
|
||||
/// </summary>
|
||||
public class Namespace : TypeContainer, INamespace
|
||||
public sealed class Namespace : TypeContainer, INamespace
|
||||
{
|
||||
public Namespace ParentNamespace;
|
||||
public readonly StringId Name;
|
||||
public readonly string Name;
|
||||
|
||||
public bool IsGlobalNamespace => ParentNamespace == null;
|
||||
|
||||
static readonly Id suffix = CIL.Id.Create(";namespace");
|
||||
public override string IdSuffix => ";namespace";
|
||||
|
||||
public Id CreateId
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
if (ParentNamespace != null && !ParentNamespace.IsGlobalNamespace)
|
||||
{
|
||||
if (ParentNamespace != null && !ParentNamespace.IsGlobalNamespace)
|
||||
{
|
||||
return ParentNamespace.ShortId + cx.Dot + Name;
|
||||
}
|
||||
return Name;
|
||||
ParentNamespace.WriteId(trapFile);
|
||||
trapFile.Write('.');
|
||||
}
|
||||
trapFile.Write(Name);
|
||||
}
|
||||
|
||||
public override Id IdSuffix => suffix;
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Namespace ns && Name == ns.Name)
|
||||
{
|
||||
if (ParentNamespace is null)
|
||||
return ns.ParentNamespace is null;
|
||||
if (!(ns.ParentNamespace is null))
|
||||
return ParentNamespace.Equals(ns.ParentNamespace);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
int h = ParentNamespace is null ? 19 : ParentNamespace.GetHashCode();
|
||||
return 13 * h + Name.GetHashCode();
|
||||
}
|
||||
|
||||
public override IEnumerable<Type> TypeParameters => throw new NotImplementedException();
|
||||
|
||||
|
@ -54,22 +70,21 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
return i == -1 ? cx.GlobalNamespace : cx.Populate(new Namespace(cx, fqn.Substring(0, i)));
|
||||
}
|
||||
|
||||
public Namespace(Context cx, string fqn) : this(cx, cx.GetId(parseNamespaceName(fqn)), createParentNamespace(cx, fqn))
|
||||
public Namespace(Context cx, string fqn) : this(cx, parseNamespaceName(fqn), createParentNamespace(cx, fqn))
|
||||
{
|
||||
}
|
||||
|
||||
public Namespace(Context cx, StringId name, Namespace parent) : base(cx)
|
||||
public Namespace(Context cx, string name, Namespace parent) : base(cx)
|
||||
{
|
||||
Name = name;
|
||||
ParentNamespace = parent;
|
||||
ShortId = CreateId;
|
||||
}
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return Tuples.namespaces(this, Name.Value);
|
||||
yield return Tuples.namespaces(this, Name);
|
||||
if (!IsGlobalNamespace)
|
||||
yield return Tuples.parent_namespace(this, ParentNamespace);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
|
@ -12,7 +13,7 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
/// <summary>
|
||||
/// A parameter entity.
|
||||
/// </summary>
|
||||
class Parameter : LabelledEntity, IParameter
|
||||
sealed class Parameter : LabelledEntity, IParameter
|
||||
{
|
||||
readonly Method method;
|
||||
readonly int index;
|
||||
|
@ -23,14 +24,26 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
method = m;
|
||||
index = i;
|
||||
type = t;
|
||||
ShortId = openCurly + method.Label.Value + closeCurly + index;
|
||||
}
|
||||
|
||||
static readonly Id parameterSuffix = CIL.Id.Create(";cil-parameter");
|
||||
static readonly Id openCurly = CIL.Id.Create("{#");
|
||||
static readonly Id closeCurly = CIL.Id.Create("}_");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(method);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(index);
|
||||
}
|
||||
|
||||
public override Id IdSuffix => parameterSuffix;
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Parameter param && method.Equals(param.method) && index == param.index;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return 23 * method.GetHashCode() + index;
|
||||
}
|
||||
|
||||
public override string IdSuffix => ";cil-parameter";
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System.Reflection.Metadata;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
|
@ -15,25 +16,44 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
/// <summary>
|
||||
/// A property.
|
||||
/// </summary>
|
||||
class Property : LabelledEntity, IProperty
|
||||
sealed class Property : LabelledEntity, IProperty
|
||||
{
|
||||
readonly Handle handle;
|
||||
readonly Type type;
|
||||
readonly PropertyDefinition pd;
|
||||
static readonly Id suffix = CIL.Id.Create(";cil-property");
|
||||
public override string IdSuffix => ";cil-property";
|
||||
readonly GenericContext gc;
|
||||
|
||||
public Property(GenericContext gc, Type type, PropertyDefinitionHandle handle) : base(gc.cx)
|
||||
{
|
||||
this.gc = gc;
|
||||
this.handle = handle;
|
||||
pd = cx.mdReader.GetPropertyDefinition(handle);
|
||||
this.type = type;
|
||||
|
||||
var id = type.ShortId + gc.cx.Dot + cx.ShortName(pd.Name);
|
||||
var signature = pd.DecodeSignature(new SignatureDecoder(), gc);
|
||||
id += "(" + CIL.Id.CommaSeparatedList(signature.ParameterTypes.Select(p => p.MakeId(gc))) + ")";
|
||||
ShortId = id;
|
||||
}
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(type);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(cx.GetString(pd.Name));
|
||||
trapFile.Write("(");
|
||||
int index=0;
|
||||
var signature = pd.DecodeSignature(new SignatureDecoder(), gc);
|
||||
foreach (var param in signature.ParameterTypes)
|
||||
{
|
||||
trapFile.WriteSeparator(",", index++);
|
||||
param.WriteId(trapFile, gc);
|
||||
}
|
||||
trapFile.Write(")");
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is Property property && Equals(handle, property.handle);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => handle.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
get
|
||||
|
@ -62,7 +82,5 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
yield return c;
|
||||
}
|
||||
}
|
||||
|
||||
public override Id IdSuffix => suffix;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Semmle.Extraction.PDB;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
|
@ -16,12 +17,27 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
{
|
||||
this.location = location;
|
||||
file = cx.CreateSourceFile(location.File);
|
||||
|
||||
ShortId = file.ShortId + separator + new IntId(location.StartLine) + separator + new IntId(location.StartColumn) + separator + new IntId(location.EndLine) + separator + new IntId(location.EndColumn);
|
||||
}
|
||||
|
||||
static readonly Id suffix = new StringId(";sourcelocation");
|
||||
static readonly Id separator = new StringId(",");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
file.WriteId(trapFile);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(location.StartLine);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(location.StartColumn);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(location.EndLine);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(location.EndColumn);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is PdbSourceLocation l && location.Equals(l.location);
|
||||
}
|
||||
|
||||
public override int GetHashCode() => location.GetHashCode();
|
||||
|
||||
public override IEnumerable<IExtractionProduct> Contents
|
||||
{
|
||||
|
@ -32,6 +48,6 @@ namespace Semmle.Extraction.CIL.Entities
|
|||
}
|
||||
}
|
||||
|
||||
public override Id IdSuffix => suffix;
|
||||
public override string IdSuffix => ";sourcelocation";
|
||||
}
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -58,8 +58,6 @@ namespace Semmle.Extraction.CIL
|
|||
|
||||
public Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException();
|
||||
|
||||
public virtual IId Id => FreshId.Instance;
|
||||
|
||||
public virtual void Extract(Context cx2)
|
||||
{
|
||||
cx2.Extract(this);
|
||||
|
@ -86,18 +84,16 @@ namespace Semmle.Extraction.CIL
|
|||
public Label Label { get; set; }
|
||||
public Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException();
|
||||
|
||||
public Id ShortId { get; set; }
|
||||
public abstract Id IdSuffix { get; }
|
||||
public IId Id => ShortId + IdSuffix;
|
||||
public abstract void WriteId(System.IO.TextWriter trapFile);
|
||||
|
||||
public void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteIId(Id);
|
||||
}
|
||||
public abstract string IdSuffix { get; }
|
||||
|
||||
public void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("@\"");
|
||||
WriteId(trapFile);
|
||||
trapFile.Write(IdSuffix);
|
||||
trapFile.Write('\"');
|
||||
}
|
||||
|
||||
public void Extract(Context cx2)
|
||||
|
@ -112,7 +108,14 @@ namespace Semmle.Extraction.CIL
|
|||
this.cx = cx;
|
||||
}
|
||||
|
||||
public override string ToString() => Id.ToString();
|
||||
public override string ToString()
|
||||
{
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
WriteQuotedId(writer);
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
TrapStackBehaviour IEntity.TrapStackBehaviour => TrapStackBehaviour.NoLabel;
|
||||
}
|
||||
|
@ -122,8 +125,6 @@ namespace Semmle.Extraction.CIL
|
|||
/// </summary>
|
||||
public interface ILabelledEntity : IExtractedEntity
|
||||
{
|
||||
Id ShortId { get; set; }
|
||||
Id IdSuffix { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
using System;
|
||||
using Semmle.Extraction.CIL.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
|
@ -9,38 +11,78 @@ namespace Semmle.Extraction.CIL
|
|||
/// </summary>
|
||||
public partial class Context
|
||||
{
|
||||
readonly Dictionary<Id, (Label, Id)> ids = new Dictionary<Id, (Label, Id)>();
|
||||
readonly Dictionary<object, Label> ids = new Dictionary<object, Label>();
|
||||
|
||||
public T Populate<T>(T e) where T : ILabelledEntity
|
||||
{
|
||||
Id id = e.ShortId;
|
||||
if(e.Label.Valid)
|
||||
{
|
||||
return e; // Already populated
|
||||
}
|
||||
|
||||
if (ids.TryGetValue(id, out var existing))
|
||||
if (ids.TryGetValue(e, out var existing))
|
||||
{
|
||||
// It exists already
|
||||
e.Label = existing.Item1;
|
||||
e.ShortId = existing.Item2; // Reuse ID for efficiency
|
||||
e.Label = existing;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Label = cx.GetNewLabel();
|
||||
cx.DefineLabel(e, cx.TrapWriter.Writer);
|
||||
ids.Add(id, (e.Label, id));
|
||||
ids.Add(e, e.Label);
|
||||
cx.PopulateLater(() =>
|
||||
{
|
||||
foreach (var c in e.Contents)
|
||||
c.Extract(this);
|
||||
});
|
||||
#if DEBUG_LABELS
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
e.WriteId(writer);
|
||||
var id = writer.ToString();
|
||||
|
||||
if (debugLabels.TryGetValue(id, out ILabelledEntity previousEntity))
|
||||
{
|
||||
cx.Extractor.Message(new Message("Duplicate trap ID", id, null, severity: Util.Logging.Severity.Warning));
|
||||
}
|
||||
else
|
||||
{
|
||||
debugLabels.Add(id, e);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
#if DEBUG_LABELS
|
||||
Dictionary<string, ILabelledEntity> debugLabels = new Dictionary<string, ILabelledEntity>();
|
||||
#endif
|
||||
|
||||
public IExtractedEntity Create(Handle h)
|
||||
{
|
||||
var entity = CreateGeneric(defaultGenericContext, h);
|
||||
return entity;
|
||||
}
|
||||
|
||||
// Lazily cache primitive types.
|
||||
PrimitiveType[] primitiveTypes = new PrimitiveType[(int)PrimitiveTypeCode.Object + 1];
|
||||
|
||||
public PrimitiveType Create(PrimitiveTypeCode code)
|
||||
{
|
||||
PrimitiveType e = primitiveTypes[(int)code];
|
||||
|
||||
if(e is null)
|
||||
{
|
||||
e = new PrimitiveType(this, code);
|
||||
e.Label = cx.GetNewLabel();
|
||||
cx.DefineLabel(e, cx.TrapWriter.Writer);
|
||||
primitiveTypes[(int)code] = e;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an entity from a Handle in a GenericContext.
|
||||
/// The type of the returned entity depends on the type of the handle.
|
||||
|
@ -63,25 +105,27 @@ namespace Semmle.Extraction.CIL
|
|||
switch (handle.Kind)
|
||||
{
|
||||
case HandleKind.MethodDefinition:
|
||||
entity = new Entities.DefinitionMethod(gc, (MethodDefinitionHandle)handle);
|
||||
entity = new DefinitionMethod(gc, (MethodDefinitionHandle)handle);
|
||||
break;
|
||||
case HandleKind.MemberReference:
|
||||
entity = Create(gc, (MemberReferenceHandle)handle);
|
||||
break;
|
||||
case HandleKind.MethodSpecification:
|
||||
entity = new Entities.MethodSpecificationMethod(gc, (MethodSpecificationHandle)handle);
|
||||
entity = new MethodSpecificationMethod(gc, (MethodSpecificationHandle)handle);
|
||||
break;
|
||||
case HandleKind.FieldDefinition:
|
||||
entity = new Entities.DefinitionField(gc, (FieldDefinitionHandle)handle);
|
||||
entity = new DefinitionField(gc, (FieldDefinitionHandle)handle);
|
||||
break;
|
||||
case HandleKind.TypeReference:
|
||||
entity = new Entities.TypeReferenceType(this, (TypeReferenceHandle)handle);
|
||||
var tr = new TypeReferenceType(this, (TypeReferenceHandle)handle);
|
||||
if (tr.TryGetPrimitiveType(gc.cx, out var pt))
|
||||
return pt;
|
||||
entity = tr;
|
||||
break;
|
||||
case HandleKind.TypeSpecification:
|
||||
entity = new Entities.TypeSpecificationType(gc, (TypeSpecificationHandle)handle);
|
||||
break;
|
||||
return Entities.Type.DecodeType(gc, (TypeSpecificationHandle)handle);
|
||||
case HandleKind.TypeDefinition:
|
||||
entity = new Entities.TypeDefinitionType(this, (TypeDefinitionHandle)handle);
|
||||
entity = new TypeDefinitionType(this, (TypeDefinitionHandle)handle);
|
||||
break;
|
||||
default:
|
||||
throw new InternalError("Unhandled handle kind " + handle.Kind);
|
||||
|
@ -97,123 +141,90 @@ namespace Semmle.Extraction.CIL
|
|||
switch (mr.GetKind())
|
||||
{
|
||||
case MemberReferenceKind.Method:
|
||||
return new Entities.MemberReferenceMethod(gc, handle);
|
||||
return new MemberReferenceMethod(gc, handle);
|
||||
case MemberReferenceKind.Field:
|
||||
return new Entities.MemberReferenceField(gc, handle);
|
||||
return new MemberReferenceField(gc, handle);
|
||||
default:
|
||||
throw new InternalError("Unhandled member reference handle");
|
||||
}
|
||||
}
|
||||
|
||||
#region Strings
|
||||
readonly Dictionary<StringHandle, StringId> stringHandleIds = new Dictionary<StringHandle, StringId>();
|
||||
readonly Dictionary<string, StringId> stringIds = new Dictionary<string, StringId>();
|
||||
|
||||
/// <summary>
|
||||
/// Return an ID containing the given string.
|
||||
/// Gets the string for a string handle.
|
||||
/// </summary>
|
||||
/// <param name="h">The string handle.</param>
|
||||
/// <returns>An ID.</returns>
|
||||
public StringId GetId(StringHandle h)
|
||||
{
|
||||
StringId result;
|
||||
if (!stringHandleIds.TryGetValue(h, out result))
|
||||
{
|
||||
result = new StringId(mdReader.GetString(h));
|
||||
stringHandleIds.Add(h, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// <returns>The string.</returns>
|
||||
public string GetString(StringHandle h) => mdReader.GetString(h);
|
||||
|
||||
public readonly StringId Dot = new StringId(".");
|
||||
#region Namespaces
|
||||
|
||||
/// <summary>
|
||||
/// Gets an ID containing the given string.
|
||||
/// Caches existing IDs for more compact storage.
|
||||
/// </summary>
|
||||
/// <param name="str">The string.</param>
|
||||
/// <returns>An ID containing the string.</returns>
|
||||
public StringId GetId(string str)
|
||||
{
|
||||
StringId result;
|
||||
if (!stringIds.TryGetValue(str, out result))
|
||||
{
|
||||
result = new StringId(str);
|
||||
stringIds.Add(str, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
readonly CachedFunction<StringHandle, Namespace> namespaceFactory;
|
||||
|
||||
#region Namespaces
|
||||
public Namespace CreateNamespace(StringHandle fqn) => namespaceFactory[fqn];
|
||||
|
||||
readonly CachedFunction<StringHandle, Entities.Namespace> namespaceFactory;
|
||||
|
||||
public Entities.Namespace CreateNamespace(StringHandle fqn) => namespaceFactory[fqn];
|
||||
|
||||
readonly Lazy<Entities.Namespace> globalNamespace, systemNamespace;
|
||||
readonly Lazy<Namespace> globalNamespace, systemNamespace;
|
||||
|
||||
/// <summary>
|
||||
/// The entity representing the global namespace.
|
||||
/// </summary>
|
||||
public Entities.Namespace GlobalNamespace => globalNamespace.Value;
|
||||
public Namespace GlobalNamespace => globalNamespace.Value;
|
||||
|
||||
/// <summary>
|
||||
/// The entity representing the System namespace.
|
||||
/// </summary>
|
||||
public Entities.Namespace SystemNamespace => systemNamespace.Value;
|
||||
public Namespace SystemNamespace => systemNamespace.Value;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a namespace from a fully-qualified name.
|
||||
/// </summary>
|
||||
/// <param name="fqn">The fully-qualified namespace name.</param>
|
||||
/// <returns>The namespace entity.</returns>
|
||||
Entities.Namespace CreateNamespace(string fqn) => Populate(new Entities.Namespace(this, fqn));
|
||||
Namespace CreateNamespace(string fqn) => Populate(new Namespace(this, fqn));
|
||||
|
||||
readonly CachedFunction<NamespaceDefinitionHandle, Entities.Namespace> namespaceDefinitionFactory;
|
||||
readonly CachedFunction<NamespaceDefinitionHandle, Namespace> namespaceDefinitionFactory;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a namespace from a namespace handle.
|
||||
/// </summary>
|
||||
/// <param name="handle">The handle of the namespace.</param>
|
||||
/// <returns>The namespace entity.</returns>
|
||||
public Entities.Namespace Create(NamespaceDefinitionHandle handle) => namespaceDefinitionFactory[handle];
|
||||
public Namespace Create(NamespaceDefinitionHandle handle) => namespaceDefinitionFactory[handle];
|
||||
|
||||
Entities.Namespace CreateNamespace(NamespaceDefinitionHandle handle)
|
||||
Namespace CreateNamespace(NamespaceDefinitionHandle handle)
|
||||
{
|
||||
if (handle.IsNil) return GlobalNamespace;
|
||||
NamespaceDefinition nd = mdReader.GetNamespaceDefinition(handle);
|
||||
return Populate(new Entities.Namespace(this, GetId(nd.Name), Create(nd.Parent)));
|
||||
return Populate(new Namespace(this, GetString(nd.Name), Create(nd.Parent)));
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Locations
|
||||
readonly CachedFunction<PDB.ISourceFile, Entities.PdbSourceFile> sourceFiles;
|
||||
readonly CachedFunction<string, Entities.Folder> folders;
|
||||
readonly CachedFunction<PDB.Location, Entities.PdbSourceLocation> sourceLocations;
|
||||
#region Locations
|
||||
readonly CachedFunction<PDB.ISourceFile, PdbSourceFile> sourceFiles;
|
||||
readonly CachedFunction<string, Folder> folders;
|
||||
readonly CachedFunction<PDB.Location, PdbSourceLocation> sourceLocations;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a source file entity from a PDB source file.
|
||||
/// </summary>
|
||||
/// <param name="file">The PDB source file.</param>
|
||||
/// <returns>A source file entity.</returns>
|
||||
public Entities.PdbSourceFile CreateSourceFile(PDB.ISourceFile file) => sourceFiles[file];
|
||||
public PdbSourceFile CreateSourceFile(PDB.ISourceFile file) => sourceFiles[file];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a folder entitiy with the given path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path of the folder.</param>
|
||||
/// <returns>A folder entity.</returns>
|
||||
public Entities.Folder CreateFolder(string path) => folders[path];
|
||||
public Folder CreateFolder(string path) => folders[path];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a source location.
|
||||
/// </summary>
|
||||
/// <param name="loc">The source location from PDB.</param>
|
||||
/// <returns>A source location entity.</returns>
|
||||
public Entities.PdbSourceLocation CreateSourceLocation(PDB.Location loc) => sourceLocations[loc];
|
||||
public PdbSourceLocation CreateSourceLocation(PDB.Location loc) => sourceLocations[loc];
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
readonly CachedFunction<GenericContext, Handle, ILabelledEntity> genericHandleFactory;
|
||||
|
||||
|
|
|
@ -1,202 +1,31 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
/// <summary>
|
||||
/// An ID fragment which is designed to be shared, reused
|
||||
/// and composed using the + operator.
|
||||
/// </summary>
|
||||
public abstract class Id : IId
|
||||
{
|
||||
public void AppendTo(System.IO.TextWriter tb)
|
||||
{
|
||||
tb.Write("@\"");
|
||||
BuildParts(tb);
|
||||
tb.Write("\"");
|
||||
}
|
||||
|
||||
public abstract void BuildParts(System.IO.TextWriter tb);
|
||||
|
||||
public static Id operator +(Id l1, Id l2) => Create(l1, l2);
|
||||
|
||||
public static Id operator +(Id l1, string l2) => Create(l1, Create(l2));
|
||||
|
||||
public static Id operator +(Id l1, int l2) => Create(l1, Create(l2));
|
||||
|
||||
public static Id operator +(string l1, Id l2) => Create(Create(l1), l2);
|
||||
|
||||
public static Id operator +(int l1, Id l2) => Create(Create(l1), l2);
|
||||
|
||||
public static Id Create(string s) => s == null ? null : new StringId(s);
|
||||
|
||||
public static Id Create(int i) => new IntId(i);
|
||||
|
||||
static readonly Id openCurly = Create("{#");
|
||||
static readonly Id closeCurly = Create("}");
|
||||
|
||||
public static Id Create(Label l) => openCurly + l.Value + closeCurly;
|
||||
|
||||
static readonly Id comma = Id.Create(",");
|
||||
|
||||
public static Id CommaSeparatedList(IEnumerable<Id> items)
|
||||
{
|
||||
Id result = null;
|
||||
bool first = true;
|
||||
foreach (var i in items)
|
||||
{
|
||||
if (first) first = false; else result += comma;
|
||||
result += i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Id Create(Id l1, Id l2)
|
||||
{
|
||||
return l1 == null ? l2 : l2 == null ? l1 : new ConsId(l1, l2);
|
||||
}
|
||||
|
||||
public abstract string Value { get; }
|
||||
|
||||
public override string ToString() => Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An ID concatenating two other IDs.
|
||||
/// </summary>
|
||||
public sealed class ConsId : Id
|
||||
{
|
||||
readonly Id left, right;
|
||||
readonly int hash;
|
||||
|
||||
public ConsId(Id l1, Id l2)
|
||||
{
|
||||
left = l1;
|
||||
right = l2;
|
||||
hash = unchecked(12 + 3 * (left.GetHashCode() + 51 * right.GetHashCode()));
|
||||
}
|
||||
|
||||
public override void BuildParts(System.IO.TextWriter tb)
|
||||
{
|
||||
left.BuildParts(tb);
|
||||
right.BuildParts(tb);
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
return other is ConsId && Equals((ConsId)other);
|
||||
}
|
||||
|
||||
public bool Equals(ConsId other)
|
||||
{
|
||||
return this == other ||
|
||||
(hash == other.hash && left.Equals(other.left) && right.Equals(other.right));
|
||||
}
|
||||
|
||||
public override int GetHashCode() => hash;
|
||||
|
||||
public override string Value => left.Value + right.Value;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A leaf ID storing a string.
|
||||
/// </summary>
|
||||
public sealed class StringId : Id
|
||||
{
|
||||
readonly string value;
|
||||
public override string Value => value;
|
||||
|
||||
public StringId(string s)
|
||||
{
|
||||
value = s;
|
||||
}
|
||||
|
||||
public override void BuildParts(System.IO.TextWriter tw)
|
||||
{
|
||||
tw.Write(value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is StringId && ((StringId)obj).value == value;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => Value.GetHashCode() * 31 + 9;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A leaf ID storing an integer.
|
||||
/// </summary>
|
||||
public sealed class IntId : Id
|
||||
{
|
||||
readonly int value;
|
||||
public override string Value => value.ToString();
|
||||
|
||||
public IntId(int i)
|
||||
{
|
||||
value = i;
|
||||
}
|
||||
|
||||
public override void BuildParts(System.IO.TextWriter tw)
|
||||
{
|
||||
tw.Write(value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is IntId && ((IntId)obj).value == value;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => unchecked(12 + value * 17);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Some predefined IDs.
|
||||
/// </summary>
|
||||
public static class IdUtils
|
||||
{
|
||||
public static StringId boolId = new StringId("Boolean");
|
||||
public static StringId byteId = new StringId("Byte");
|
||||
public static StringId charId = new StringId("Char");
|
||||
public static StringId doubleId = new StringId("Double");
|
||||
public static StringId shortId = new StringId("Int16");
|
||||
public static StringId intId = new StringId("Int32");
|
||||
public static StringId longId = new StringId("Int64");
|
||||
public static StringId intptrId = new StringId("IntPtr");
|
||||
public static StringId objectId = new StringId("Object");
|
||||
public static StringId sbyteId = new StringId("SByte");
|
||||
public static StringId floatId = new StringId("Single");
|
||||
public static StringId stringId = new StringId("String");
|
||||
public static StringId ushortId = new StringId("UInt16");
|
||||
public static StringId uintId = new StringId("UInt32");
|
||||
public static StringId ulongId = new StringId("UInt64");
|
||||
public static StringId uintptrId = new StringId("UIntPtr");
|
||||
public static StringId voidId = new StringId("Void");
|
||||
public static StringId typedReferenceId = new StringId("TypedReference");
|
||||
|
||||
public static StringId Id(this PrimitiveTypeCode typeCode)
|
||||
public static string Id(this PrimitiveTypeCode typeCode)
|
||||
{
|
||||
switch (typeCode)
|
||||
{
|
||||
case PrimitiveTypeCode.Boolean: return boolId;
|
||||
case PrimitiveTypeCode.Byte: return byteId;
|
||||
case PrimitiveTypeCode.Char: return charId;
|
||||
case PrimitiveTypeCode.Double: return doubleId;
|
||||
case PrimitiveTypeCode.Int16: return shortId;
|
||||
case PrimitiveTypeCode.Int32: return intId;
|
||||
case PrimitiveTypeCode.Int64: return longId;
|
||||
case PrimitiveTypeCode.IntPtr: return intptrId;
|
||||
case PrimitiveTypeCode.Object: return objectId;
|
||||
case PrimitiveTypeCode.SByte: return sbyteId;
|
||||
case PrimitiveTypeCode.Single: return floatId;
|
||||
case PrimitiveTypeCode.String: return stringId;
|
||||
case PrimitiveTypeCode.UInt16: return ushortId;
|
||||
case PrimitiveTypeCode.UInt32: return uintId;
|
||||
case PrimitiveTypeCode.UInt64: return ulongId;
|
||||
case PrimitiveTypeCode.UIntPtr: return uintptrId;
|
||||
case PrimitiveTypeCode.Void: return voidId;
|
||||
case PrimitiveTypeCode.TypedReference: return typedReferenceId;
|
||||
case PrimitiveTypeCode.Boolean: return "Boolean";
|
||||
case PrimitiveTypeCode.Byte: return "Byte";
|
||||
case PrimitiveTypeCode.Char: return "Char";
|
||||
case PrimitiveTypeCode.Double: return "Double";
|
||||
case PrimitiveTypeCode.Int16: return "Int16";
|
||||
case PrimitiveTypeCode.Int32: return "Int32";
|
||||
case PrimitiveTypeCode.Int64: return "Int64";
|
||||
case PrimitiveTypeCode.IntPtr: return "IntPtr";
|
||||
case PrimitiveTypeCode.Object: return "Object";
|
||||
case PrimitiveTypeCode.SByte: return "SByte";
|
||||
case PrimitiveTypeCode.Single: return "Single";
|
||||
case PrimitiveTypeCode.String: return "String";
|
||||
case PrimitiveTypeCode.UInt16: return "UInt16";
|
||||
case PrimitiveTypeCode.UInt32: return "UInt32";
|
||||
case PrimitiveTypeCode.UInt64: return "UInt64";
|
||||
case PrimitiveTypeCode.UIntPtr: return "UIntPtr";
|
||||
case PrimitiveTypeCode.Void: return "Void";
|
||||
case PrimitiveTypeCode.TypedReference: return "TypedReference";
|
||||
default: throw new InternalError($"Unhandled type code {typeCode}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.2</TargetFramework>
|
||||
|
@ -8,6 +8,10 @@
|
|||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<DefineConstants>DEBUG;DEBUG_LABELS</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Semmle.Extraction\Semmle.Extraction.csproj" />
|
||||
<ProjectReference Include="..\Semmle.Util\Semmle.Util.csproj" />
|
||||
|
|
|
@ -8,8 +8,8 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
{
|
||||
class Compilation : FreshEntity
|
||||
{
|
||||
string cwd;
|
||||
string[] args;
|
||||
private readonly string cwd;
|
||||
private readonly string[] args;
|
||||
|
||||
public Compilation(Context cx, string cwd, string[] args) : base(cx)
|
||||
{
|
||||
|
|
|
@ -235,7 +235,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
|
||||
if (method.IsVararg)
|
||||
{
|
||||
tb.WriteSeparator(",", index++);
|
||||
tb.WriteSeparator(",", index);
|
||||
tb.Write("__arglist");
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Emit(new Tuple("modifiers", Label, symbol.name));
|
||||
trapFile.modifiers(Label, symbol.name);
|
||||
}
|
||||
|
||||
public static string AccessbilityModifier(Accessibility access)
|
||||
|
|
|
@ -83,9 +83,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
ExtractMetadataHandle(trapFile);
|
||||
ExtractAttributes();
|
||||
|
||||
var tb = new StringWriter();
|
||||
symbol.BuildDisplayName(Context, tb);
|
||||
trapFile.types(this, GetClassType(Context, symbol), tb.ToString());
|
||||
using (var tb = new StringWriter())
|
||||
{
|
||||
symbol.BuildDisplayName(Context, tb);
|
||||
trapFile.types(this, GetClassType(Context, symbol), tb.ToString());
|
||||
}
|
||||
|
||||
// Visit base types
|
||||
var baseTypes = new List<Type>();
|
||||
|
|
|
@ -16,7 +16,6 @@ namespace Semmle.Extraction.CSharp.Entities
|
|||
public UsingDirective(Context cx, UsingDirectiveSyntax usingDirective, NamespaceDeclaration parent)
|
||||
: base(cx)
|
||||
{
|
||||
var trapFile = cx.TrapWriter.Writer;
|
||||
Node = usingDirective;
|
||||
Parent = parent;
|
||||
TryPopulate();
|
||||
|
|
|
@ -308,6 +308,12 @@ namespace Semmle.Extraction.CSharp
|
|||
{
|
||||
trapFile.WriteTuple("methods", method, name, declType, retType, originalDefinition);
|
||||
}
|
||||
|
||||
internal static void modifiers(this TextWriter trapFile, Label entity, string modifier)
|
||||
{
|
||||
trapFile.BeginTuple("modifiers").Param(entity).Param(modifier).EndTuple();
|
||||
}
|
||||
|
||||
internal static void mutator_invocation_mode(this TextWriter trapFile, Expression expr, int mode)
|
||||
{
|
||||
trapFile.WriteTuple("mutator_invocation_mode", expr, mode);
|
||||
|
|
|
@ -332,7 +332,7 @@ namespace Semmle.Extraction.CommentProcessing
|
|||
|
||||
class CommentBlock : ICommentBlock
|
||||
{
|
||||
private List<ICommentLine> lines = new List<ICommentLine>();
|
||||
private readonly List<ICommentLine> lines = new List<ICommentLine>();
|
||||
|
||||
public IEnumerable<ICommentLine> CommentLines => lines;
|
||||
|
||||
|
|
|
@ -105,9 +105,11 @@ namespace Semmle.Extraction
|
|||
if (entity.NeedsPopulation)
|
||||
Populate(init as ISymbol, entity);
|
||||
#if DEBUG_LABELS
|
||||
var id = new StringWriter();
|
||||
entity.WriteId(id);
|
||||
CheckEntityHasUniqueLabel(id.ToString(), entity);
|
||||
using (var id = new StringWriter())
|
||||
{
|
||||
entity.WriteId(id);
|
||||
CheckEntityHasUniqueLabel(id.ToString(), entity);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
@ -149,9 +151,11 @@ namespace Semmle.Extraction
|
|||
Populate(init as ISymbol, entity);
|
||||
|
||||
#if DEBUG_LABELS
|
||||
var id = new StringWriter();
|
||||
entity.WriteId(id);
|
||||
CheckEntityHasUniqueLabel(id.ToString(), entity);
|
||||
using (var id = new StringWriter())
|
||||
{
|
||||
entity.WriteId(id);
|
||||
CheckEntityHasUniqueLabel(id.ToString(), entity);
|
||||
}
|
||||
#endif
|
||||
|
||||
return entity;
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace Semmle.Extraction.Entities
|
|||
public override void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(assembly.ToString());
|
||||
if (assemblyPath is null)
|
||||
if (!(assemblyPath is null))
|
||||
{
|
||||
trapFile.Write("#file:///");
|
||||
trapFile.Write(assemblyPath.Replace("\\", "/"));
|
||||
|
|
|
@ -162,11 +162,13 @@ namespace Semmle.Extraction
|
|||
/// <returns>The debug string.</returns>
|
||||
public static string GetDebugLabel(this IEntity entity)
|
||||
{
|
||||
var writer = new StringWriter();
|
||||
writer.WriteLabel(entity.Label.Value);
|
||||
writer.Write('=');
|
||||
entity.WriteQuotedId(writer);
|
||||
return writer.ToString();
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
writer.WriteLabel(entity.Label.Value);
|
||||
writer.Write('=');
|
||||
entity.WriteQuotedId(writer);
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace Semmle.Extraction
|
|||
|
||||
class IdTrapBuilder
|
||||
{
|
||||
readonly public List<string> Fragments = new List<string>();
|
||||
public readonly List<string> Fragments = new List<string>();
|
||||
|
||||
public void Append(object arg)
|
||||
{
|
||||
|
|
|
@ -90,6 +90,9 @@ namespace Semmle.Extraction
|
|||
CIL = !value;
|
||||
Fast = value;
|
||||
return true;
|
||||
case "brotli":
|
||||
TrapCompression = value ? TrapWriter.CompressionMode.Brotli : TrapWriter.CompressionMode.Gzip;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -26,9 +26,11 @@ namespace Semmle.Extraction
|
|||
{
|
||||
get
|
||||
{
|
||||
var trap = new StringWriter();
|
||||
Populate(trap);
|
||||
return trap.ToString();
|
||||
using (var trap = new StringWriter())
|
||||
{
|
||||
Populate(trap);
|
||||
return trap.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,12 @@ namespace Semmle.Extraction
|
|||
return new NextParam(Writer);
|
||||
}
|
||||
|
||||
public NextParam Param(Label label)
|
||||
{
|
||||
Writer.WriteLabel(label.Value);
|
||||
return new NextParam(Writer);
|
||||
}
|
||||
|
||||
public void EndTuple()
|
||||
{
|
||||
Writer.WriteLine(')');
|
||||
|
|
|
@ -155,9 +155,11 @@ namespace Semmle.Extraction
|
|||
public override string ToString()
|
||||
{
|
||||
// Only implemented for debugging purposes
|
||||
var tsb = new StringWriter();
|
||||
EmitToTrapBuilder(tsb);
|
||||
return tsb.ToString();
|
||||
using (var writer = new StringWriter())
|
||||
{
|
||||
EmitToTrapBuilder(writer);
|
||||
return writer.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,5 +86,19 @@ namespace Semmle.Util
|
|||
{
|
||||
items.ForEach(_ => { });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes a hash of a sequence.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the item.</typeparam>
|
||||
/// <param name="items">The list of items to hash.</param>
|
||||
/// <returns>The hash code.</returns>
|
||||
public static int SequenceHash<T>(this IEnumerable<T> items)
|
||||
{
|
||||
int h = 0;
|
||||
foreach (var i in items)
|
||||
h = h * 7 + i.GetHashCode();
|
||||
return h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче