mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
C#: Remove ITrapBuilder in favour of TextWriter.
This commit is contained in:
@@ -5,6 +5,7 @@ using Microsoft.CodeAnalysis;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
@@ -38,6 +39,16 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public IId Id => ShortId + IdSuffix;
|
||||
|
||||
public void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteIId(Id);
|
||||
}
|
||||
|
||||
public void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
WriteId(trapFile);
|
||||
}
|
||||
|
||||
public Id IdSuffix => fieldSuffix;
|
||||
|
||||
static readonly StringId fieldSuffix = new StringId(";cil-field");
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata.Ecma335;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
|
||||
@@ -6,6 +6,8 @@ using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Semmle.Util;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Semmle.Extraction.CIL.Entities
|
||||
{
|
||||
@@ -55,6 +57,22 @@ namespace Semmle.Extraction.CIL.Entities
|
||||
|
||||
public virtual IId Id { get { return ShortId + IdSuffix; } }
|
||||
|
||||
public void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
// TODO: Specialise this
|
||||
trapFile.WriteIId(Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For debugging purposes.
|
||||
/// </summary>
|
||||
string DebugId => this.GetDebugLabel();
|
||||
|
||||
public void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
WriteId(trapFile);
|
||||
}
|
||||
|
||||
public Id ShortId { get; set; }
|
||||
public abstract Id IdSuffix { get; }
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
{
|
||||
@@ -45,6 +46,16 @@ namespace Semmle.Extraction.CIL
|
||||
public abstract IEnumerable<IExtractionProduct> Contents { get; }
|
||||
public Label Label { get; set; }
|
||||
|
||||
public void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write('*');
|
||||
}
|
||||
|
||||
public void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
WriteId(trapFile);
|
||||
}
|
||||
|
||||
public Microsoft.CodeAnalysis.Location ReportingLocation => throw new NotImplementedException();
|
||||
|
||||
public virtual IId Id => FreshId.Instance;
|
||||
@@ -79,6 +90,16 @@ namespace Semmle.Extraction.CIL
|
||||
public abstract Id IdSuffix { get; }
|
||||
public IId Id => ShortId + IdSuffix;
|
||||
|
||||
public void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteIId(Id);
|
||||
}
|
||||
|
||||
public void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
WriteId(trapFile);
|
||||
}
|
||||
|
||||
public void Extract(Context cx2)
|
||||
{
|
||||
cx2.Populate(this);
|
||||
|
||||
@@ -23,7 +23,8 @@ namespace Semmle.Extraction.CIL
|
||||
}
|
||||
else
|
||||
{
|
||||
cx.DefineLabel(e);
|
||||
e.Label = cx.GetNewLabel();
|
||||
cx.DefineLabel(e, cx.TrapWriter.Writer);
|
||||
ids.Add(id, (e.Label, id));
|
||||
cx.PopulateLater(() =>
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection.Metadata;
|
||||
|
||||
namespace Semmle.Extraction.CIL
|
||||
@@ -9,14 +10,14 @@ namespace Semmle.Extraction.CIL
|
||||
/// </summary>
|
||||
public abstract class Id : IId
|
||||
{
|
||||
public void AppendTo(ITrapBuilder tb)
|
||||
public void AppendTo(System.IO.TextWriter tb)
|
||||
{
|
||||
tb.Append("@\"");
|
||||
tb.Write("@\"");
|
||||
BuildParts(tb);
|
||||
tb.Append("\"");
|
||||
tb.Write("\"");
|
||||
}
|
||||
|
||||
public abstract void BuildParts(ITrapBuilder tb);
|
||||
public abstract void BuildParts(System.IO.TextWriter tb);
|
||||
|
||||
public static Id operator +(Id l1, Id l2) => Create(l1, l2);
|
||||
|
||||
@@ -76,7 +77,7 @@ namespace Semmle.Extraction.CIL
|
||||
hash = unchecked(12 + 3 * (left.GetHashCode() + 51 * right.GetHashCode()));
|
||||
}
|
||||
|
||||
public override void BuildParts(ITrapBuilder tb)
|
||||
public override void BuildParts(System.IO.TextWriter tb)
|
||||
{
|
||||
left.BuildParts(tb);
|
||||
right.BuildParts(tb);
|
||||
@@ -112,9 +113,9 @@ namespace Semmle.Extraction.CIL
|
||||
value = s;
|
||||
}
|
||||
|
||||
public override void BuildParts(ITrapBuilder tb)
|
||||
public override void BuildParts(System.IO.TextWriter tw)
|
||||
{
|
||||
tb.Append(value);
|
||||
tw.Write(value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
@@ -138,9 +139,9 @@ namespace Semmle.Extraction.CIL
|
||||
value = i;
|
||||
}
|
||||
|
||||
public override void BuildParts(ITrapBuilder tb)
|
||||
public override void BuildParts(System.IO.TextWriter tw)
|
||||
{
|
||||
tb.Append(value);
|
||||
tw.Write(value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
|
||||
@@ -375,6 +375,7 @@ namespace Semmle.Extraction.CSharp
|
||||
Populators.CompilationUnit.Extract(cx, tree.GetRoot());
|
||||
cx.PopulateAll();
|
||||
cx.ExtractComments(cx.CommentGenerator);
|
||||
cx.PopulateAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Semmle.Extraction.CommentProcessing;
|
||||
using Semmle.Extraction.Entities;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
@@ -21,13 +22,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter tw)
|
||||
{
|
||||
get
|
||||
{
|
||||
var loc = Context.Create(symbol.Location);
|
||||
return new Key(loc, ";commentblock");
|
||||
}
|
||||
tw.WriteSubId(Context.Create(symbol.Location));
|
||||
tw.Write(";commentblock");
|
||||
}
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => symbol.Location;
|
||||
|
||||
@@ -2,6 +2,7 @@ using Semmle.Extraction.CommentProcessing;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Semmle.Extraction.Entities;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
@@ -122,13 +123,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter tw)
|
||||
{
|
||||
get
|
||||
{
|
||||
var loc = Context.Create(Location);
|
||||
return new Key(loc, ";commentline");
|
||||
}
|
||||
tw.WriteSubId(Context.Create(Location));
|
||||
tw.Write(";commentline");
|
||||
}
|
||||
|
||||
static CommentLine Create(Context cx, Microsoft.CodeAnalysis.Location loc, CommentLineType type, string text, string raw) => CommentLineFactory.Instance.CreateEntity(cx, loc, type, text, raw);
|
||||
|
||||
@@ -5,6 +5,7 @@ using Semmle.Util;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Semmle.Extraction.Entities;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
@@ -109,18 +110,12 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
if (symbol.IsStatic) tb.Append("static");
|
||||
tb.Append(ContainingType);
|
||||
AddParametersToId(Context, tb, symbol);
|
||||
tb.Append(";constructor");
|
||||
});
|
||||
}
|
||||
if (symbol.IsStatic) trapFile.Write("static");
|
||||
trapFile.WriteSubId(ContainingType);
|
||||
AddParametersToId(Context, trapFile, symbol);
|
||||
trapFile.Write(";constructor");
|
||||
}
|
||||
|
||||
ConstructorDeclarationSyntax GetSyntax() =>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -9,19 +10,13 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
Event(Context cx, IEventSymbol init)
|
||||
: base(cx, init) { }
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
tb.Append(ContainingType);
|
||||
tb.Append(".");
|
||||
Method.AddExplicitInterfaceQualifierToId(Context, tb, symbol.ExplicitInterfaceImplementations);
|
||||
tb.Append(symbol.Name);
|
||||
tb.Append(";event");
|
||||
});
|
||||
}
|
||||
trapFile.WriteSubId(ContainingType);
|
||||
trapFile.Write('.');
|
||||
Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations);
|
||||
trapFile.Write(symbol.Name);
|
||||
trapFile.Write(";event");
|
||||
}
|
||||
|
||||
public override void Populate()
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Extraction.Kinds;
|
||||
using Semmle.Extraction.CSharp.Entities.Expressions;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
@@ -98,7 +99,13 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
readonly Lazy<AnnotatedType> type;
|
||||
public AnnotatedType Type => type.Value;
|
||||
|
||||
public override IId Id => new Key(ContainingType, ".", symbol.Name, ";field");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(ContainingType);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(symbol.Name);
|
||||
trapFile.Write(";field");
|
||||
}
|
||||
|
||||
bool IExpressionParentEntity.IsTopLevelParent => true;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -73,20 +74,14 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public static new Indexer Create(Context cx, IPropertySymbol prop) => IndexerFactory.Instance.CreateEntity(cx, prop);
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
tb.Append(ContainingType);
|
||||
tb.Append(".");
|
||||
tb.Append(symbol.MetadataName);
|
||||
tb.Append("(");
|
||||
tb.BuildList(",", symbol.Parameters, (p, tb0) => tb0.Append(Type.Create(Context, p.Type)));
|
||||
tb.Append(");indexer");
|
||||
});
|
||||
}
|
||||
trapFile.WriteSubId(ContainingType);
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(symbol.MetadataName);
|
||||
trapFile.Write('(');
|
||||
trapFile.BuildList(",", symbol.Parameters, (p, tb0) => tb0.WriteSubId(Type.Create(Context, p.Type)));
|
||||
trapFile.Write(");indexer");
|
||||
}
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location FullLocation
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -10,23 +11,16 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
}
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
trapFile.WriteSubId(Location);
|
||||
if (symbol.IsGenericMethod && !IsSourceDeclaration)
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
tb.Append(Location);
|
||||
if (symbol.IsGenericMethod && !IsSourceDeclaration)
|
||||
{
|
||||
tb.Append("<");
|
||||
tb.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta));
|
||||
tb.Append(">");
|
||||
}
|
||||
|
||||
tb.Append(";localfunction");
|
||||
});
|
||||
trapFile.Write('<');
|
||||
trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta));
|
||||
trapFile.Write('>');
|
||||
}
|
||||
trapFile.Write(";localfunction");
|
||||
}
|
||||
|
||||
public static new LocalFunction Create(Context cx, IMethodSymbol field) => LocalFunctionFactory.Instance.CreateEntity(cx, field);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Semmle.Extraction.Entities;
|
||||
|
||||
@@ -18,7 +19,13 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
readonly bool IsVar;
|
||||
readonly Extraction.Entities.Location DeclLocation;
|
||||
|
||||
public override IId Id => new Key(Parent, "_", symbol.Name, ";localvar");
|
||||
public override void WriteId(TextWriter tw)
|
||||
{
|
||||
tw.WriteSubId(Parent);
|
||||
tw.Write('_');
|
||||
tw.Write(symbol.Name);
|
||||
tw.Write(";localvar");
|
||||
}
|
||||
|
||||
public override void Populate()
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.CSharp.Populators;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -105,57 +106,62 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
/// <summary>
|
||||
/// Factored out to share logic between `Method` and `UserOperator`.
|
||||
/// </summary>
|
||||
protected static void BuildMethodId(Method m, ITrapBuilder tb)
|
||||
protected static void BuildMethodId(Method m, TextWriter tw)
|
||||
{
|
||||
tb.Append(m.ContainingType);
|
||||
tw.WriteSubId(m.ContainingType);
|
||||
|
||||
AddExplicitInterfaceQualifierToId(m.Context, tb, m.symbol.ExplicitInterfaceImplementations);
|
||||
AddExplicitInterfaceQualifierToId(m.Context, tw, m.symbol.ExplicitInterfaceImplementations);
|
||||
|
||||
tb.Append(".").Append(m.symbol.Name);
|
||||
tw.Write(".");
|
||||
tw.Write(m.symbol.Name);
|
||||
|
||||
if (m.symbol.IsGenericMethod)
|
||||
{
|
||||
if (Equals(m.symbol, m.symbol.OriginalDefinition))
|
||||
{
|
||||
tb.Append("`").Append(m.symbol.TypeParameters.Length);
|
||||
tw.Write('`');
|
||||
tw.Write(m.symbol.TypeParameters.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
tb.Append("<");
|
||||
tw.Write('<');
|
||||
// Encode the nullability of the type arguments in the label.
|
||||
// Type arguments with different nullability can result in
|
||||
// a constructed method with different nullability of its parameters and return type,
|
||||
// so we need to create a distinct database entity for it.
|
||||
tb.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); tb.Append((int)ta.Nullability); });
|
||||
tb.Append(">");
|
||||
tw.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); tw.Write((int)ta.Nullability); });
|
||||
tw.Write('>');
|
||||
}
|
||||
}
|
||||
|
||||
AddParametersToId(m.Context, tb, m.symbol);
|
||||
AddParametersToId(m.Context, tw, m.symbol);
|
||||
switch (m.symbol.MethodKind)
|
||||
{
|
||||
case MethodKind.PropertyGet:
|
||||
tb.Append(";getter");
|
||||
tw.Write(";getter");
|
||||
break;
|
||||
case MethodKind.PropertySet:
|
||||
tb.Append(";setter");
|
||||
tw.Write(";setter");
|
||||
break;
|
||||
case MethodKind.EventAdd:
|
||||
tb.Append(";adder");
|
||||
tw.Write(";adder");
|
||||
break;
|
||||
case MethodKind.EventRaise:
|
||||
tb.Append(";raiser");
|
||||
tw.Write(";raiser");
|
||||
break;
|
||||
case MethodKind.EventRemove:
|
||||
tb.Append(";remover");
|
||||
tw.Write(";remover");
|
||||
break;
|
||||
default:
|
||||
tb.Append(";method");
|
||||
tw.Write(";method");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override IId Id => new Key(tb => BuildMethodId(this, tb));
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
BuildMethodId(this, trapFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an appropriate label ID to the trap builder <paramref name="tb"/>
|
||||
@@ -193,58 +199,54 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
/// to make the reference to <code>#3</code> in the label definition <code>#4</code> for
|
||||
/// <code>T</code> valid.
|
||||
/// </summary>
|
||||
protected static void AddSignatureTypeToId(Context cx, ITrapBuilder tb, IMethodSymbol method, ITypeSymbol type)
|
||||
protected static void AddSignatureTypeToId(Context cx, TextWriter tb, IMethodSymbol method, ITypeSymbol type)
|
||||
{
|
||||
if (type.ContainsTypeParameters(cx, method))
|
||||
type.BuildTypeId(cx, tb, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0));
|
||||
else
|
||||
tb.Append(Type.Create(cx, type));
|
||||
tb.WriteSubId(Type.Create(cx, type));
|
||||
}
|
||||
|
||||
protected static void AddParametersToId(Context cx, ITrapBuilder tb, IMethodSymbol method)
|
||||
protected static void AddParametersToId(Context cx, TextWriter tb, IMethodSymbol method)
|
||||
{
|
||||
tb.Append("(");
|
||||
tb.AppendList(",", AddParameterPartsToId(cx, tb, method));
|
||||
tb.Append(")");
|
||||
}
|
||||
tb.Write('(');
|
||||
int index = 0;
|
||||
|
||||
// This is a slight abuse of ITrapBuilder.AppendList().
|
||||
// yield return "" is used to insert a list separator
|
||||
// at the desired location.
|
||||
static IEnumerable<object> AddParameterPartsToId(Context cx, ITrapBuilder tb, IMethodSymbol method)
|
||||
{
|
||||
if (method.MethodKind == MethodKind.ReducedExtension)
|
||||
{
|
||||
tb.WriteSeparator(",", index++);
|
||||
AddSignatureTypeToId(cx, tb, method, method.ReceiverType);
|
||||
yield return ""; // The next yield return outputs a ","
|
||||
}
|
||||
|
||||
foreach (var param in method.Parameters)
|
||||
{
|
||||
yield return ""; // Maybe print ","
|
||||
tb.WriteSeparator(",", index++);
|
||||
AddSignatureTypeToId(cx, tb, method, param.Type);
|
||||
switch (param.RefKind)
|
||||
{
|
||||
case RefKind.Out:
|
||||
yield return " out";
|
||||
tb.Write(" out");
|
||||
break;
|
||||
case RefKind.Ref:
|
||||
yield return " ref";
|
||||
tb.Write(" ref");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (method.IsVararg)
|
||||
{
|
||||
yield return "__arglist";
|
||||
tb.WriteSeparator(",", index++);
|
||||
tb.Write("__arglist");
|
||||
}
|
||||
|
||||
tb.Write(')');
|
||||
}
|
||||
|
||||
public static void AddExplicitInterfaceQualifierToId(Context cx, ITrapBuilder tb, IEnumerable<ISymbol> explicitInterfaceImplementations)
|
||||
public static void AddExplicitInterfaceQualifierToId(Context cx, System.IO.TextWriter tw, IEnumerable<ISymbol> explicitInterfaceImplementations)
|
||||
{
|
||||
if (explicitInterfaceImplementations.Any())
|
||||
{
|
||||
tb.AppendList(",", explicitInterfaceImplementations.Select(impl => cx.CreateEntity(impl.ContainingType)));
|
||||
tw.AppendList(",", explicitInterfaceImplementations.Select(impl => cx.CreateEntity(impl.ContainingType)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -32,7 +33,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => null;
|
||||
|
||||
public override IId Id => new Key(symbol.name, ";modifier");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(symbol.name);
|
||||
trapFile.Write(";modifier");
|
||||
}
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -22,13 +23,15 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
if (!symbol.IsGlobalNamespace)
|
||||
{
|
||||
return symbol.IsGlobalNamespace ? new Key(";namespace") :
|
||||
new Key(Create(Context, symbol.ContainingNamespace), ".", symbol.Name, ";namespace");
|
||||
trapFile.WriteSubId(Create(Context, symbol.ContainingNamespace));
|
||||
trapFile.Write('.');
|
||||
trapFile.Write(symbol.Name);
|
||||
}
|
||||
trapFile.Write(";namespace");
|
||||
}
|
||||
|
||||
public static Namespace Create(Context cx, INamespaceSymbol ns) => NamespaceFactory.Instance.CreateEntity2(cx, ns);
|
||||
|
||||
@@ -4,6 +4,7 @@ using Semmle.Extraction.CSharp.Populators;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.Entities;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
@@ -75,16 +76,14 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
public static Parameter GetAlreadyCreated(Context cx, IParameterSymbol param) =>
|
||||
ParameterFactory.Instance.CreateEntity(cx, param, null, null);
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
// This is due to a bug in Roslyn when ValueTuple.cs is extracted.
|
||||
// The parameter symbols don't match up properly so we don't have a parent.
|
||||
if (Parent == null)
|
||||
Parent = Method.Create(Context, symbol.ContainingSymbol as IMethodSymbol);
|
||||
return new Key(Parent, "_", Ordinal, ";parameter");
|
||||
}
|
||||
if (Parent == null)
|
||||
Parent = Method.Create(Context, symbol.ContainingSymbol as IMethodSymbol);
|
||||
trapFile.WriteSubId(Parent);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(Ordinal);
|
||||
trapFile.Write(";parameter");
|
||||
}
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
@@ -193,7 +192,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public sealed override IId Id => new Key("__arglist;type");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("__arglist;type");
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.CSharp.Entities.Expressions;
|
||||
using Semmle.Extraction.Entities;
|
||||
using Semmle.Extraction.Kinds;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -12,19 +13,13 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
protected Property(Context cx, IPropertySymbol init)
|
||||
: base(cx, init) { }
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
tb.Append(ContainingType);
|
||||
tb.Append(".");
|
||||
Method.AddExplicitInterfaceQualifierToId(Context, tb, symbol.ExplicitInterfaceImplementations);
|
||||
tb.Append(symbol.Name);
|
||||
tb.Append(";property");
|
||||
});
|
||||
}
|
||||
trapFile.WriteSubId(ContainingType);
|
||||
trapFile.Write('.');
|
||||
Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations);
|
||||
trapFile.Write(symbol.Name);
|
||||
trapFile.Write(";property");
|
||||
}
|
||||
|
||||
public override void Populate()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -29,18 +30,12 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
ExtractNullability(symbol.ElementNullableAnnotation);
|
||||
}
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
tb.Append(element.Type);
|
||||
tb.Append((int)symbol.ElementNullableAnnotation);
|
||||
symbol.BuildArraySuffix(tb);
|
||||
tb.Append(";type");
|
||||
});
|
||||
}
|
||||
trapFile.WriteSubId(element.Type);
|
||||
trapFile.Write((int)symbol.ElementNullableAnnotation);
|
||||
symbol.BuildArraySuffix(trapFile);
|
||||
trapFile.Write(";type");
|
||||
}
|
||||
|
||||
public static ArrayType Create(Context cx, IArrayTypeSymbol symbol) => ArrayTypeFactory.Instance.CreateEntity(cx, symbol);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -21,9 +22,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
Context.Emit(Tuples.parent_namespace(this, Namespace.Create(Context, Context.Compilation.GlobalNamespace)));
|
||||
}
|
||||
|
||||
static readonly Key id = new Key("dynamic;type");
|
||||
|
||||
public override IId Id => id;
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("dynamic;type");
|
||||
}
|
||||
|
||||
class DynamicTypeFactory : ICachedEntityFactory<IDynamicTypeSymbol, DynamicType>
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using Semmle.Extraction.CSharp.Populators;
|
||||
using Semmle.Extraction.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -111,17 +112,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override Microsoft.CodeAnalysis.Location ReportingLocation => GetLocations(symbol).FirstOrDefault();
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
// All syntactic sub terms (types) are referenced by key in the ID
|
||||
symbol.BuildTypeId(Context, tb, (cx0, tb0, sub) => tb0.Append(Create(cx0, sub)));
|
||||
tb.Append(";type");
|
||||
});
|
||||
}
|
||||
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
|
||||
trapFile.Write(";type");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -183,15 +177,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
tb.Append(referencedType).Append(";typeref");
|
||||
});
|
||||
}
|
||||
trapFile.WriteSubId(referencedType);
|
||||
trapFile.Write(";typeRef");
|
||||
}
|
||||
|
||||
public override void Populate()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -12,7 +13,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
Context.Emit(Tuples.types(this, Kinds.TypeKind.NULL, "null"));
|
||||
}
|
||||
|
||||
public override IId Id => new Key("<null>;type");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("<null>;type");
|
||||
}
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -10,7 +11,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
PointedAtType = Create(cx, symbol.PointedAtType);
|
||||
}
|
||||
|
||||
public override IId Id => new Key(PointedAtType, "*;type");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteSubId(PointedAtType);
|
||||
trapFile.Write("*;type");
|
||||
}
|
||||
|
||||
// All pointer types are extracted because they won't
|
||||
// be extracted in their defining assembly.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Semmle.Extraction.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -29,16 +30,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
// All tuple types are "local types"
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
symbol.BuildTypeId(Context, tb, (cx0, tb0, sub) => tb0.Append(Create(cx0, sub)));
|
||||
tb.Append(";tuple");
|
||||
});
|
||||
}
|
||||
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
|
||||
trapFile.Write(";tuple");
|
||||
}
|
||||
|
||||
public override void Populate()
|
||||
|
||||
@@ -4,6 +4,7 @@ using Semmle.Extraction.CSharp.Populators;
|
||||
using Semmle.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -77,36 +78,14 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
class DisplayNameTrapBuilder : ITrapBuilder
|
||||
{
|
||||
public readonly List<string> Fragments = new List<string>();
|
||||
|
||||
public ITrapBuilder Append(object arg)
|
||||
{
|
||||
Fragments.Add(arg.ToString());
|
||||
return this;
|
||||
}
|
||||
|
||||
public ITrapBuilder Append(string arg)
|
||||
{
|
||||
Fragments.Add(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ITrapBuilder AppendLine()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
protected void ExtractType()
|
||||
{
|
||||
ExtractMetadataHandle();
|
||||
ExtractAttributes();
|
||||
|
||||
var tb = new DisplayNameTrapBuilder();
|
||||
var tb = new StringWriter();
|
||||
symbol.BuildDisplayName(Context, tb);
|
||||
Context.Emit(Tuples.types(this, GetClassType(Context, symbol), tb.Fragments.ToArray()));
|
||||
Context.Emit(Tuples.types(this, GetClassType(Context, symbol), tb.ToString()));
|
||||
|
||||
// Visit base types
|
||||
var baseTypes = new List<Type>();
|
||||
|
||||
@@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Extraction.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -107,27 +108,28 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
string kind;
|
||||
IEntity containingEntity;
|
||||
switch (symbol.TypeParameterKind)
|
||||
{
|
||||
string kind;
|
||||
IEntity containingEntity;
|
||||
switch (symbol.TypeParameterKind)
|
||||
{
|
||||
case TypeParameterKind.Method:
|
||||
kind = "methodtypeparameter";
|
||||
containingEntity = Method.Create(Context, (IMethodSymbol)symbol.ContainingSymbol);
|
||||
break;
|
||||
case TypeParameterKind.Type:
|
||||
kind = "typeparameter";
|
||||
containingEntity = Create(Context, symbol.ContainingType);
|
||||
break;
|
||||
default:
|
||||
throw new InternalError(symbol, $"Unhandled type parameter kind {symbol.TypeParameterKind}");
|
||||
}
|
||||
return new Key(containingEntity, "_", symbol.Ordinal, ";", kind);
|
||||
case TypeParameterKind.Method:
|
||||
kind = "methodtypeparameter";
|
||||
containingEntity = Method.Create(Context, (IMethodSymbol)symbol.ContainingSymbol);
|
||||
break;
|
||||
case TypeParameterKind.Type:
|
||||
kind = "typeparameter";
|
||||
containingEntity = Create(Context, symbol.ContainingType);
|
||||
break;
|
||||
default:
|
||||
throw new InternalError(symbol, $"Unhandled type parameter kind {symbol.TypeParameterKind}");
|
||||
}
|
||||
trapFile.WriteSubId(containingEntity);
|
||||
trapFile.Write('_');
|
||||
trapFile.Write(symbol.Ordinal);
|
||||
trapFile.Write(';');
|
||||
trapFile.Write(kind);
|
||||
}
|
||||
|
||||
class TypeParameterFactory : ICachedEntityFactory<ITypeParameterSymbol, TypeParameter>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
@@ -48,17 +49,11 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Key(tb =>
|
||||
{
|
||||
AddSignatureTypeToId(Context, tb, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type.
|
||||
tb.Append(" ");
|
||||
BuildMethodId(this, tb);
|
||||
});
|
||||
}
|
||||
AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type.
|
||||
trapFile.Write(' ');
|
||||
BuildMethodId(this, trapFile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,6 +2,7 @@ using Microsoft.CodeAnalysis;
|
||||
using Semmle.Extraction.CSharp.Entities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction.CSharp
|
||||
@@ -128,9 +129,9 @@ namespace Semmle.Extraction.CSharp
|
||||
/// syntactic sub terms of this type (if any).
|
||||
/// </summary>
|
||||
/// <param name="cx">The extraction context.</param>
|
||||
/// <param name="tb">The trap builder used to store the result.</param>
|
||||
/// <param name="tw">The trap builder used to store the result.</param>
|
||||
/// <param name="subTermAction">The action to apply to syntactic sub terms of this type.</param>
|
||||
public static void BuildTypeId(this ITypeSymbol type, Context cx, ITrapBuilder tb, Action<Context, ITrapBuilder, ITypeSymbol> subTermAction)
|
||||
public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter tw, Action<Context, TextWriter, ITypeSymbol> subTermAction)
|
||||
{
|
||||
if (type.SpecialType != SpecialType.None)
|
||||
{
|
||||
@@ -139,7 +140,7 @@ namespace Semmle.Extraction.CSharp
|
||||
* This makes the IDs shorter and means that all built-in types map to
|
||||
* the same entities (even when using multiple versions of mscorlib).
|
||||
*/
|
||||
tb.Append(type.ToDisplayString());
|
||||
tw.Write(type.ToDisplayString());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -149,8 +150,8 @@ namespace Semmle.Extraction.CSharp
|
||||
{
|
||||
case TypeKind.Array:
|
||||
var array = (IArrayTypeSymbol)type;
|
||||
subTermAction(cx, tb, array.ElementType);
|
||||
array.BuildArraySuffix(tb);
|
||||
subTermAction(cx, tw, array.ElementType);
|
||||
array.BuildArraySuffix(tw);
|
||||
return;
|
||||
case TypeKind.Class:
|
||||
case TypeKind.Interface:
|
||||
@@ -159,19 +160,19 @@ namespace Semmle.Extraction.CSharp
|
||||
case TypeKind.Delegate:
|
||||
case TypeKind.Error:
|
||||
var named = (INamedTypeSymbol)type;
|
||||
named.BuildNamedTypeId(cx, tb, subTermAction);
|
||||
named.BuildNamedTypeId(cx, tw, subTermAction);
|
||||
return;
|
||||
case TypeKind.Pointer:
|
||||
var ptr = (IPointerTypeSymbol)type;
|
||||
subTermAction(cx, tb, ptr.PointedAtType);
|
||||
tb.Append("*");
|
||||
subTermAction(cx, tw, ptr.PointedAtType);
|
||||
tw.Write('*');
|
||||
return;
|
||||
case TypeKind.TypeParameter:
|
||||
var tp = (ITypeParameterSymbol)type;
|
||||
tb.Append(tp.Name);
|
||||
tw.Write(tp.Name);
|
||||
return;
|
||||
case TypeKind.Dynamic:
|
||||
tb.Append("dynamic");
|
||||
tw.Write("dynamic");
|
||||
return;
|
||||
default:
|
||||
throw new InternalError(type, $"Unhandled type kind '{type.TypeKind}'");
|
||||
@@ -179,64 +180,70 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an array suffix string for this array type symbol.
|
||||
/// </summary>
|
||||
/// <param name="tb">The trap builder used to store the result.</param>
|
||||
public static void BuildArraySuffix(this IArrayTypeSymbol array, ITrapBuilder tb)
|
||||
public static void BuildArraySuffix(this IArrayTypeSymbol array, TextWriter tb)
|
||||
{
|
||||
tb.Append("[");
|
||||
tb.Write('[');
|
||||
for (int i = 0; i < array.Rank - 1; i++)
|
||||
tb.Append(",");
|
||||
tb.Append("]");
|
||||
tb.Write(',');
|
||||
tb.Write(']');
|
||||
}
|
||||
|
||||
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, ITrapBuilder tb, Action<Context, ITrapBuilder, ITypeSymbol> subTermAction)
|
||||
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter tw, Action<Context, TextWriter, ITypeSymbol> subTermAction)
|
||||
{
|
||||
if (named.IsTupleType)
|
||||
{
|
||||
tb.Append("(");
|
||||
tb.BuildList(",", named.TupleElements,
|
||||
tw.Write('(');
|
||||
tw.BuildList(",", named.TupleElements,
|
||||
(f, tb0) =>
|
||||
{
|
||||
tb.Append(f.Name).Append(":");
|
||||
tw.Write(f.Name);
|
||||
tw.Write(":");
|
||||
subTermAction(cx, tb0, f.Type);
|
||||
}
|
||||
);
|
||||
tb.Append(")");
|
||||
tw.Write(")");
|
||||
return;
|
||||
}
|
||||
|
||||
if (named.ContainingType != null)
|
||||
{
|
||||
subTermAction(cx, tb, named.ContainingType);
|
||||
tb.Append(".");
|
||||
subTermAction(cx, tw, named.ContainingType);
|
||||
tw.Write('.');
|
||||
}
|
||||
else if (named.ContainingNamespace != null)
|
||||
{
|
||||
named.ContainingNamespace.BuildNamespace(cx, tb);
|
||||
named.ContainingNamespace.BuildNamespace(cx, tw);
|
||||
}
|
||||
|
||||
if (named.IsAnonymousType)
|
||||
named.BuildAnonymousName(cx, tb, subTermAction, true);
|
||||
named.BuildAnonymousName(cx, tw, subTermAction, true);
|
||||
else if (named.TypeParameters.IsEmpty)
|
||||
tb.Append(named.Name);
|
||||
tw.Write(named.Name);
|
||||
else if (IsReallyUnbound(named))
|
||||
tb.Append(named.Name).Append("`").Append(named.TypeParameters.Length);
|
||||
{
|
||||
tw.Write(named.Name);
|
||||
tw.Write("`");
|
||||
tw.Write(named.TypeParameters.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
subTermAction(cx, tb, named.ConstructedFrom);
|
||||
tb.Append("<");
|
||||
subTermAction(cx, tw, named.ConstructedFrom);
|
||||
tw.Write('<');
|
||||
// Encode the nullability of the type arguments in the label.
|
||||
// Type arguments with different nullability can result in
|
||||
// a constructed type with different nullability of its members and methods,
|
||||
// so we need to create a distinct database entity for it.
|
||||
tb.BuildList(",", named.GetAnnotatedTypeArguments(), (ta, tb0) => { subTermAction(cx, tb0, ta.Symbol); tb.Append((int)ta.Nullability); });
|
||||
tb.Append(">");
|
||||
tw.BuildList(",", named.GetAnnotatedTypeArguments(), (ta, tb0) => { subTermAction(cx, tb0, ta.Symbol); tw.Write((int)ta.Nullability); });
|
||||
tw.Write('>');
|
||||
}
|
||||
}
|
||||
|
||||
static void BuildNamespace(this INamespaceSymbol ns, Context cx, ITrapBuilder tb)
|
||||
static void BuildNamespace(this INamespaceSymbol ns, Context cx, TextWriter tw)
|
||||
{
|
||||
// Only include the assembly information in each type ID
|
||||
// for normal extractions. This is because standalone extractions
|
||||
@@ -248,38 +255,44 @@ namespace Semmle.Extraction.CSharp
|
||||
// Note that we exclude the revision number as this has
|
||||
// been observed to be unstable.
|
||||
var assembly = ns.ContainingAssembly.Identity;
|
||||
tb.Append(assembly.Name).Append("_").
|
||||
Append(assembly.Version.Major).Append(".").
|
||||
Append(assembly.Version.Minor).Append(".").
|
||||
Append(assembly.Version.Build).Append("::");
|
||||
tw.Write(assembly.Name);
|
||||
tw.Write('_');
|
||||
tw.Write(assembly.Version.Major);
|
||||
tw.Write('.');
|
||||
tw.Write(assembly.Version.Minor);
|
||||
tw.Write('.');
|
||||
tw.Write(assembly.Version.Build);
|
||||
tw.Write("::");
|
||||
}
|
||||
|
||||
tb.Append(Namespace.Create(cx, ns)).Append(".");
|
||||
tw.WriteSubId(Namespace.Create(cx, ns));
|
||||
tw.Write('.');
|
||||
}
|
||||
|
||||
static void BuildAnonymousName(this ITypeSymbol type, Context cx, ITrapBuilder tb, Action<Context, ITrapBuilder, ITypeSymbol> subTermAction, bool includeParamName)
|
||||
static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter tw, Action<Context, TextWriter, ITypeSymbol> subTermAction, bool includeParamName)
|
||||
{
|
||||
var buildParam = includeParamName
|
||||
? (prop, tb0) =>
|
||||
{
|
||||
tb0.Append(prop.Name).Append(" ");
|
||||
tb0.Write(prop.Name);
|
||||
tw.Write(' ');
|
||||
subTermAction(cx, tb0, prop.Type);
|
||||
}
|
||||
: (Action<IPropertySymbol, ITrapBuilder>)((prop, tb0) => subTermAction(cx, tb0, prop.Type));
|
||||
: (Action<IPropertySymbol, TextWriter>)((prop, tb0) => subTermAction(cx, tb0, prop.Type));
|
||||
int memberCount = type.GetMembers().OfType<IPropertySymbol>().Count();
|
||||
int hackTypeNumber = memberCount == 1 ? 1 : 0;
|
||||
tb.Append("<>__AnonType");
|
||||
tb.Append(hackTypeNumber);
|
||||
tb.Append("<");
|
||||
tb.BuildList(",", type.GetMembers().OfType<IPropertySymbol>(), buildParam);
|
||||
tb.Append(">");
|
||||
tw.Write("<>__AnonType");
|
||||
tw.Write(hackTypeNumber);
|
||||
tw.Write('<');
|
||||
tw.BuildList(",", type.GetMembers().OfType<IPropertySymbol>(), buildParam);
|
||||
tw.Write('>');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a display name string for this type symbol.
|
||||
/// </summary>
|
||||
/// <param name="tb">The trap builder used to store the result.</param>
|
||||
public static void BuildDisplayName(this ITypeSymbol type, Context cx, ITrapBuilder tb)
|
||||
/// <param name="tw">The trap builder used to store the result.</param>
|
||||
public static void BuildDisplayName(this ITypeSymbol type, Context cx, TextWriter tw)
|
||||
{
|
||||
using (cx.StackGuard)
|
||||
{
|
||||
@@ -290,11 +303,11 @@ namespace Semmle.Extraction.CSharp
|
||||
var elementType = array.ElementType;
|
||||
if (elementType.MetadataName.IndexOf("`") >= 0)
|
||||
{
|
||||
tb.Append(elementType.Name);
|
||||
tw.Write(elementType.Name);
|
||||
return;
|
||||
}
|
||||
elementType.BuildDisplayName(cx, tb);
|
||||
array.BuildArraySuffix(tb);
|
||||
elementType.BuildDisplayName(cx, tw);
|
||||
array.BuildArraySuffix(tw);
|
||||
return;
|
||||
case TypeKind.Class:
|
||||
case TypeKind.Interface:
|
||||
@@ -303,18 +316,18 @@ namespace Semmle.Extraction.CSharp
|
||||
case TypeKind.Delegate:
|
||||
case TypeKind.Error:
|
||||
var named = (INamedTypeSymbol)type;
|
||||
named.BuildNamedTypeDisplayName(cx, tb);
|
||||
named.BuildNamedTypeDisplayName(cx, tw);
|
||||
return;
|
||||
case TypeKind.Pointer:
|
||||
var ptr = (IPointerTypeSymbol)type;
|
||||
ptr.PointedAtType.BuildDisplayName(cx, tb);
|
||||
tb.Append("*");
|
||||
ptr.PointedAtType.BuildDisplayName(cx, tw);
|
||||
tw.Write('*');
|
||||
return;
|
||||
case TypeKind.TypeParameter:
|
||||
tb.Append(type.Name);
|
||||
tw.Write(type.Name);
|
||||
return;
|
||||
case TypeKind.Dynamic:
|
||||
tb.Append("dynamic");
|
||||
tw.Write("dynamic");
|
||||
return;
|
||||
default:
|
||||
throw new InternalError(type, $"Unhandled type kind '{type.TypeKind}'");
|
||||
@@ -322,34 +335,34 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
}
|
||||
|
||||
public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, ITrapBuilder tb)
|
||||
public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, TextWriter tw)
|
||||
{
|
||||
if (namedType.IsTupleType)
|
||||
{
|
||||
tb.Append("(");
|
||||
tb.BuildList(",", namedType.TupleElements.Select(f => f.Type),
|
||||
tw.Write('(');
|
||||
tw.BuildList(",", namedType.TupleElements.Select(f => f.Type),
|
||||
(t, tb0) => t.BuildDisplayName(cx, tb0)
|
||||
);
|
||||
|
||||
tb.Append(")");
|
||||
tw.Write(")");
|
||||
return;
|
||||
}
|
||||
|
||||
if (namedType.IsAnonymousType)
|
||||
{
|
||||
namedType.BuildAnonymousName(cx, tb, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false);
|
||||
namedType.BuildAnonymousName(cx, tw, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false);
|
||||
}
|
||||
|
||||
tb.Append(namedType.Name);
|
||||
tw.Write(namedType.Name);
|
||||
if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any())
|
||||
{
|
||||
tb.Append("<");
|
||||
tb.BuildList(",", namedType.TypeArguments, (p, tb0) =>
|
||||
tw.Write('<');
|
||||
tw.BuildList(",", namedType.TypeArguments, (p, tb0) =>
|
||||
{
|
||||
if (IsReallyBound(namedType))
|
||||
p.BuildDisplayName(cx, tb0);
|
||||
});
|
||||
tb.Append(">");
|
||||
tw.Write('>');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -191,9 +191,9 @@ namespace Semmle.Extraction.Tests
|
||||
Content = content;
|
||||
}
|
||||
|
||||
public void EmitToTrapBuilder(ITrapBuilder tb)
|
||||
public void EmitToTrapBuilder(TextWriter tb)
|
||||
{
|
||||
tb.Append(Content);
|
||||
tb.Write(Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using Semmle.Extraction.Entities;
|
||||
using Semmle.Util.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
@@ -53,6 +54,28 @@ namespace Semmle.Extraction
|
||||
return init == null ? CreateEntity2(factory, init) : CreateNonNullEntity(factory, init);
|
||||
}
|
||||
|
||||
bool DefiningLabel = false;
|
||||
|
||||
public void DefineLabel(IEntity entity, TextWriter trapFile)
|
||||
{
|
||||
if (DefiningLabel)
|
||||
{
|
||||
PopulateLater(() => DefineLabel(entity, trapFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
DefiningLabel = true;
|
||||
entity.DefineLabel(trapFile);
|
||||
}
|
||||
finally
|
||||
{
|
||||
DefiningLabel = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new entity using the factory.
|
||||
/// Uses a different cache to <see cref="CreateEntity{Type, Entity}(ICachedEntityFactory{Type, Entity}, Type)"/>,
|
||||
@@ -73,23 +96,27 @@ namespace Semmle.Extraction
|
||||
}
|
||||
else
|
||||
{
|
||||
var id = entity.Id;
|
||||
#if DEBUG_LABELS
|
||||
CheckEntityHasUniqueLabel(id, entity);
|
||||
#endif
|
||||
label = new Label(GetNewId());
|
||||
label = GetNewLabel();
|
||||
entity.Label = label;
|
||||
entityLabelCache[entity] = label;
|
||||
DefineLabel(label, id);
|
||||
|
||||
DefineLabel(entity, TrapWriter.Writer);
|
||||
|
||||
if (entity.NeedsPopulation)
|
||||
Populate(init as ISymbol, entity);
|
||||
#if DEBUG_LABELS
|
||||
var id = new StringWriter();
|
||||
entity.WriteId(id);
|
||||
CheckEntityHasUniqueLabel(id.ToString(), entity);
|
||||
#endif
|
||||
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG_LABELS
|
||||
private void CheckEntityHasUniqueLabel(IId id, ICachedEntity entity)
|
||||
private void CheckEntityHasUniqueLabel(string id, ICachedEntity entity)
|
||||
{
|
||||
if (idLabelCache.TryGetValue(id, out var originalEntity))
|
||||
{
|
||||
@@ -102,6 +129,8 @@ namespace Semmle.Extraction
|
||||
}
|
||||
#endif
|
||||
|
||||
public Label GetNewLabel() => new Label(GetNewId());
|
||||
|
||||
private Entity CreateNonNullEntity<Type, Entity>(ICachedEntityFactory<Type, Entity> factory, Type init) where Entity : ICachedEntity
|
||||
{
|
||||
if (objectEntityCache.TryGetValue(init, out var cached))
|
||||
@@ -109,22 +138,22 @@ namespace Semmle.Extraction
|
||||
|
||||
using (StackGuard)
|
||||
{
|
||||
var label = new Label(GetNewId());
|
||||
var label = GetNewLabel();
|
||||
var entity = factory.Create(this, init);
|
||||
entity.Label = label;
|
||||
|
||||
objectEntityCache[init] = entity;
|
||||
|
||||
var id = entity.Id;
|
||||
DefineLabel(label, id);
|
||||
|
||||
#if DEBUG_LABELS
|
||||
CheckEntityHasUniqueLabel(id, entity);
|
||||
#endif
|
||||
|
||||
DefineLabel(entity, TrapWriter.Writer);
|
||||
if (entity.NeedsPopulation)
|
||||
Populate(init as ISymbol, entity);
|
||||
|
||||
#if DEBUG_LABELS
|
||||
var id = new StringWriter();
|
||||
entity.WriteId(id);
|
||||
CheckEntityHasUniqueLabel(id.ToString(), entity);
|
||||
#endif
|
||||
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -158,29 +187,17 @@ namespace Semmle.Extraction
|
||||
/// </summary>
|
||||
public void AddFreshLabel(IEntity entity)
|
||||
{
|
||||
var label = new Label(GetNewId());
|
||||
TrapWriter.Emit(new DefineFreshLabelEmitter(label));
|
||||
entity.Label = label;
|
||||
entity.Label = GetNewLabel();
|
||||
entity.DefineFreshLabel(TrapWriter.Writer);
|
||||
}
|
||||
|
||||
#if DEBUG_LABELS
|
||||
readonly Dictionary<IId, ICachedEntity> idLabelCache = new Dictionary<IId, ICachedEntity>();
|
||||
readonly Dictionary<string, ICachedEntity> idLabelCache = new Dictionary<string, ICachedEntity>();
|
||||
#endif
|
||||
readonly Dictionary<object, ICachedEntity> objectEntityCache = new Dictionary<object, ICachedEntity>();
|
||||
readonly Dictionary<ICachedEntity, Label> entityLabelCache = new Dictionary<ICachedEntity, Label>();
|
||||
readonly HashSet<Label> extractedGenerics = new HashSet<Label>();
|
||||
|
||||
public void DefineLabel(IEntity entity)
|
||||
{
|
||||
entity.Label = new Label(GetNewId());
|
||||
DefineLabel(entity.Label, entity.Id);
|
||||
}
|
||||
|
||||
void DefineLabel(Label label, IId id)
|
||||
{
|
||||
TrapWriter.Emit(new DefineLabelEmitter(label, id));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Queue of items to populate later.
|
||||
/// The only reason for this is so that the call stack does not
|
||||
@@ -300,43 +317,6 @@ namespace Semmle.Extraction
|
||||
}
|
||||
}
|
||||
|
||||
class DefineLabelEmitter : ITrapEmitter
|
||||
{
|
||||
readonly Label label;
|
||||
readonly IId id;
|
||||
|
||||
public DefineLabelEmitter(Label label, IId id)
|
||||
{
|
||||
this.label = label;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void EmitToTrapBuilder(ITrapBuilder tb)
|
||||
{
|
||||
label.AppendTo(tb);
|
||||
tb.Append("=");
|
||||
id.AppendTo(tb);
|
||||
tb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
class DefineFreshLabelEmitter : ITrapEmitter
|
||||
{
|
||||
readonly Label Label;
|
||||
|
||||
public DefineFreshLabelEmitter(Label label)
|
||||
{
|
||||
Label = label;
|
||||
}
|
||||
|
||||
public void EmitToTrapBuilder(ITrapBuilder tb)
|
||||
{
|
||||
Label.AppendTo(tb);
|
||||
tb.Append("=*");
|
||||
tb.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
class PushEmitter : ITrapEmitter
|
||||
{
|
||||
readonly Key Key;
|
||||
@@ -346,20 +326,19 @@ namespace Semmle.Extraction
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public void EmitToTrapBuilder(ITrapBuilder tb)
|
||||
public void EmitToTrapBuilder(TextWriter tw)
|
||||
{
|
||||
tb.Append(".push ");
|
||||
Key.AppendTo(tb);
|
||||
tb.AppendLine();
|
||||
tw.Write(".push ");
|
||||
Key.AppendTo(tw);
|
||||
tw.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
class PopEmitter : ITrapEmitter
|
||||
{
|
||||
public void EmitToTrapBuilder(ITrapBuilder tb)
|
||||
public void EmitToTrapBuilder(TextWriter tw)
|
||||
{
|
||||
tb.Append(".pop");
|
||||
tb.AppendLine();
|
||||
tw.WriteLine(".pop");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,6 +352,13 @@ namespace Semmle.Extraction
|
||||
/// <exception cref="InternalError">Thrown on invalid trap stack behaviour.</exception>
|
||||
public void Populate(ISymbol optionalSymbol, ICachedEntity entity)
|
||||
{
|
||||
if (DefiningLabel)
|
||||
{
|
||||
// Don't write tuples etc if we're currently defining a label
|
||||
PopulateLater(() => Populate(optionalSymbol, entity));
|
||||
return;
|
||||
}
|
||||
|
||||
bool duplicationGuard;
|
||||
bool deferred;
|
||||
|
||||
|
||||
@@ -65,14 +65,15 @@ namespace Semmle.Extraction.Entities
|
||||
return AssemblyConstructorFactory.Instance.CreateEntity(cx, null);
|
||||
}
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
trapFile.Write(assembly.ToString());
|
||||
if (assemblyPath is null)
|
||||
{
|
||||
return assemblyPath == null
|
||||
? new Key(assembly, ";assembly")
|
||||
: new Key(assembly, "#file:///", assemblyPath.Replace("\\", "/"), ";assembly");
|
||||
trapFile.Write("#file:///");
|
||||
trapFile.Write(assemblyPath.Replace("\\", "/"));
|
||||
}
|
||||
trapFile.Write(";assembly");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,13 +63,14 @@ namespace Semmle.Extraction.Entities
|
||||
}
|
||||
}
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
if (Path is null)
|
||||
trapFile.Write("GENERATED;sourcefile");
|
||||
else
|
||||
{
|
||||
return Path == null ?
|
||||
new Key("GENERATED;sourcefile") :
|
||||
new Key(DatabasePath, ";sourcefile");
|
||||
trapFile.Write(DatabasePath);
|
||||
trapFile.Write(";sourcefile");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +105,10 @@ namespace Semmle.Extraction.Entities
|
||||
Context.TrapWriter.files(this, "", "", "");
|
||||
}
|
||||
|
||||
public override IId Id => new Key("GENERATED;sourcefile");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("GENERATED;sourcefile");
|
||||
}
|
||||
|
||||
public static GeneratedFile Create(Context cx) =>
|
||||
GeneratedFileFactory.Instance.CreateEntity(cx, null);
|
||||
|
||||
@@ -36,7 +36,11 @@ namespace Semmle.Extraction.Entities
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public override IId Id => new Key(DatabasePath, ";folder");
|
||||
public override void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write(DatabasePath);
|
||||
trapFile.Write(";folder");
|
||||
}
|
||||
|
||||
public static Folder Create(Context cx, DirectoryInfo folder) =>
|
||||
FolderFactory.Instance.CreateEntity2(cx, folder);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
{
|
||||
public class GeneratedLocation : SourceLocation
|
||||
@@ -15,7 +17,12 @@ namespace Semmle.Extraction.Entities
|
||||
Context.TrapWriter.locations_default(this, GeneratedFile, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public override IId Id => new Key("loc,", GeneratedFile, ",0,0,0,0");
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("loc,");
|
||||
trapFile.WriteSubId(GeneratedFile);
|
||||
trapFile.Write(",0,0,0,0");
|
||||
}
|
||||
|
||||
public override int GetHashCode() => 98732567;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.IO;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.Entities
|
||||
@@ -31,15 +32,20 @@ namespace Semmle.Extraction.Entities
|
||||
private set;
|
||||
}
|
||||
|
||||
public override IId Id
|
||||
public override void WriteId(System.IO.TextWriter trapFile)
|
||||
{
|
||||
get
|
||||
{
|
||||
FileLinePositionSpan l = symbol.GetLineSpan();
|
||||
FileEntity = Entities.File.Create(Context, l.Path);
|
||||
return new Key("loc,", FileEntity, ",", l.Span.Start.Line + 1, ",",
|
||||
l.Span.Start.Character + 1, ",", l.Span.End.Line + 1, ",", l.Span.End.Character);
|
||||
}
|
||||
FileLinePositionSpan l = symbol.GetLineSpan();
|
||||
FileEntity = Entities.File.Create(Context, l.Path);
|
||||
trapFile.Write("loc,");
|
||||
trapFile.WriteSubId(FileEntity);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(l.Span.Start.Line + 1);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(l.Span.Start.Character + 1);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(l.Span.End.Line + 1);
|
||||
trapFile.Write(',');
|
||||
trapFile.Write(l.Span.End.Character);
|
||||
}
|
||||
|
||||
class SourceLocationFactory : ICachedEntityFactory<Microsoft.CodeAnalysis.Location, SourceLocation>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
@@ -26,10 +26,17 @@ namespace Semmle.Extraction
|
||||
Label Label { set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID used for the entity, as it is in the trap file.
|
||||
/// Could be '*'.
|
||||
/// Writes the unique identifier of this entitiy to a trap file.
|
||||
/// </summary>
|
||||
IId Id { get; }
|
||||
/// <param name="writer"></param>
|
||||
void WriteId(TextWriter writer);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the quoted identifier of this entity,
|
||||
/// which could be @"..." or *
|
||||
/// </summary>
|
||||
/// <param name="writer"></param>
|
||||
void WriteQuotedId(TextWriter writer);
|
||||
|
||||
/// <summary>
|
||||
/// The location for reporting purposes.
|
||||
@@ -133,5 +140,34 @@ namespace Semmle.Extraction
|
||||
/// <returns>The entity.</returns>
|
||||
public static Entity CreateEntity2<Type, Entity>(this ICachedEntityFactory<Type, Entity> factory, Context cx, Type init)
|
||||
where Entity : ICachedEntity => cx.CreateEntity2(factory, init);
|
||||
|
||||
public static void DefineLabel(this IEntity entity, TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteLabel(entity);
|
||||
trapFile.Write("=");
|
||||
entity.WriteQuotedId(trapFile);
|
||||
trapFile.WriteLine();
|
||||
}
|
||||
|
||||
public static void DefineFreshLabel(this IEntity entity, TextWriter trapFile)
|
||||
{
|
||||
trapFile.WriteLabel(entity);
|
||||
trapFile.WriteLine("=*");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates a debug string for this entity.
|
||||
/// </summary>
|
||||
/// <param name="entity">The entity to view.</param>
|
||||
/// <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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Semmle.Extraction.Entities;
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
@@ -20,6 +21,16 @@ namespace Semmle.Extraction
|
||||
get; set;
|
||||
}
|
||||
|
||||
public void WriteId(TextWriter writer)
|
||||
{
|
||||
writer.Write('*');
|
||||
}
|
||||
|
||||
public void WriteQuotedId(TextWriter writer)
|
||||
{
|
||||
WriteId(writer);
|
||||
}
|
||||
|
||||
public override string ToString() => Label.ToString();
|
||||
|
||||
public IId Id => FreshId.Instance;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
@@ -16,7 +17,7 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// Appends this ID to the supplied trap builder.
|
||||
/// </summary>
|
||||
void AppendTo(ITrapBuilder tb);
|
||||
void AppendTo(TextWriter tw);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -37,9 +38,9 @@ namespace Semmle.Extraction
|
||||
|
||||
public override int GetHashCode() => 0;
|
||||
|
||||
public void AppendTo(ITrapBuilder tb)
|
||||
public void AppendTo(System.IO.TextWriter tw)
|
||||
{
|
||||
tb.Append("*");
|
||||
tw.Write('*');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,34 +50,41 @@ namespace Semmle.Extraction
|
||||
/// </summary>
|
||||
public class Key : IId
|
||||
{
|
||||
readonly IdTrapBuilder TrapBuilder;
|
||||
readonly StringWriter TrapBuilder = new StringWriter();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new key by concatenating the contents of the supplied arguments.
|
||||
/// </summary>
|
||||
public Key(params object[] args)
|
||||
{
|
||||
TrapBuilder = new IdTrapBuilder();
|
||||
TrapBuilder = new StringWriter();
|
||||
foreach (var arg in args)
|
||||
TrapBuilder.Append(arg);
|
||||
{
|
||||
if (arg is IEntity)
|
||||
{
|
||||
var key = ((IEntity)arg).Label;
|
||||
TrapBuilder.Write("{#");
|
||||
TrapBuilder.Write(key.Value.ToString());
|
||||
TrapBuilder.Write("}");
|
||||
}
|
||||
else
|
||||
TrapBuilder.Write(arg.ToString());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new key by applying the supplied action to an empty
|
||||
/// trap builder.
|
||||
/// </summary>
|
||||
public Key(Action<ITrapBuilder> action)
|
||||
public Key(Action<TextWriter> action)
|
||||
{
|
||||
TrapBuilder = new IdTrapBuilder();
|
||||
action(TrapBuilder);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
// Only implemented for debugging purposes
|
||||
var tsb = new TrapStringBuilder();
|
||||
AppendTo(tsb);
|
||||
return tsb.ToString();
|
||||
return TrapBuilder.ToString();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
@@ -84,37 +92,23 @@ namespace Semmle.Extraction
|
||||
if (obj.GetType() != GetType())
|
||||
return false;
|
||||
var id = (Key)obj;
|
||||
return id.TrapBuilder.Fragments.SequenceEqual(TrapBuilder.Fragments);
|
||||
return TrapBuilder.ToString() == id.TrapBuilder.ToString();
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
public override int GetHashCode() => TrapBuilder.ToString().GetHashCode();
|
||||
|
||||
public void AppendTo(TextWriter tb)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
|
||||
foreach (var fragment in TrapBuilder.Fragments)
|
||||
{
|
||||
hash = hash * 23 + fragment.GetHashCode();
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
tb.Write("@\"");
|
||||
tb.Write(TrapBuilder.ToString());
|
||||
tb.Write("\"");
|
||||
}
|
||||
|
||||
public void AppendTo(ITrapBuilder tb)
|
||||
{
|
||||
tb.Append("@\"");
|
||||
foreach (var fragment in TrapBuilder.Fragments)
|
||||
tb.Append(fragment);
|
||||
tb.Append("\"");
|
||||
}
|
||||
|
||||
class IdTrapBuilder : ITrapBuilder
|
||||
class IdTrapBuilder
|
||||
{
|
||||
readonly public List<string> Fragments = new List<string>();
|
||||
|
||||
public ITrapBuilder Append(object arg)
|
||||
public void Append(object arg)
|
||||
{
|
||||
if (arg is IEntity)
|
||||
{
|
||||
@@ -125,17 +119,14 @@ namespace Semmle.Extraction
|
||||
}
|
||||
else
|
||||
Fragments.Add(arg.ToString());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public ITrapBuilder Append(string arg)
|
||||
public void Append(string arg)
|
||||
{
|
||||
Fragments.Add(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ITrapBuilder AppendLine()
|
||||
public void AppendLine()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
@@ -145,7 +136,7 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// A label referencing an entity, of the form "#123".
|
||||
/// </summary>
|
||||
public struct Label : IId
|
||||
public struct Label
|
||||
{
|
||||
public Label(int value) : this()
|
||||
{
|
||||
@@ -181,12 +172,13 @@ namespace Semmle.Extraction
|
||||
/// Constructs a unique string for this label.
|
||||
/// </summary>
|
||||
/// <param name="tb">The trap builder used to store the result.</param>
|
||||
public void AppendTo(ITrapBuilder tb)
|
||||
public void AppendTo(System.IO.TextWriter tw)
|
||||
{
|
||||
if (!Valid)
|
||||
throw new NullReferenceException("Attempt to use an invalid label");
|
||||
|
||||
tb.Append("#").Append(Value);
|
||||
tw.Write('#');
|
||||
tw.Write(Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.IO;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
/// <summary>
|
||||
@@ -34,9 +36,13 @@ namespace Semmle.Extraction
|
||||
|
||||
public Initializer UnderlyingObject => symbol;
|
||||
|
||||
public abstract IId Id
|
||||
public abstract void WriteId(System.IO.TextWriter trapFile);
|
||||
|
||||
public void WriteQuotedId(TextWriter trapFile)
|
||||
{
|
||||
get;
|
||||
trapFile.Write("@\"");
|
||||
WriteId(trapFile);
|
||||
trapFile.Write('\"');
|
||||
}
|
||||
|
||||
public abstract bool NeedsPopulation
|
||||
|
||||
@@ -1,35 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
{
|
||||
/// <summary>
|
||||
/// A trap builder.
|
||||
///
|
||||
/// A trap builder is used to construct a string that is to be
|
||||
/// persisted in a trap file (similar to how a <see cref="StringBuilder"/>
|
||||
/// can be used to construct a string).
|
||||
/// </summary>
|
||||
public interface ITrapBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Append the given object to this trap builder.
|
||||
/// </summary>
|
||||
ITrapBuilder Append(object arg);
|
||||
|
||||
/// <summary>
|
||||
/// Append the given string to this trap builder.
|
||||
/// </summary>
|
||||
ITrapBuilder Append(string arg);
|
||||
|
||||
/// <summary>
|
||||
/// Append a newline to this trap builder.
|
||||
/// </summary>
|
||||
ITrapBuilder AppendLine();
|
||||
}
|
||||
|
||||
public static class ITrapBuilderExtensions
|
||||
public static class TrapBuilderExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Appends a [comma] separated list to a trap builder.
|
||||
@@ -39,9 +15,9 @@ namespace Semmle.Extraction
|
||||
/// <param name="separator">The separator string (e.g. ",")</param>
|
||||
/// <param name="items">The list of items.</param>
|
||||
/// <returns>The original trap builder (fluent interface).</returns>
|
||||
public static ITrapBuilder AppendList<T>(this ITrapBuilder tb, string separator, IEnumerable<T> items)
|
||||
public static TextWriter AppendList<T>(this TextWriter tb, string separator, IEnumerable<T> items) where T:IEntity
|
||||
{
|
||||
return tb.BuildList(separator, items, (x, tb0) => { tb0.Append(x); });
|
||||
return tb.BuildList(separator, items, (x, tb0) => { tb0.WriteSubId(x); });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,44 +29,15 @@ namespace Semmle.Extraction
|
||||
/// <param name="items">The list of items.</param>
|
||||
/// <param name="action">The action on each item.</param>
|
||||
/// <returns>The original trap builder (fluent interface).</returns>
|
||||
public static ITrapBuilder BuildList<T>(this ITrapBuilder tb, string separator, IEnumerable<T> items, Action<T, ITrapBuilder> action)
|
||||
public static TextWriter BuildList<T>(this TextWriter tb, string separator, IEnumerable<T> items, Action<T, TextWriter> action)
|
||||
{
|
||||
bool first = true;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (first) first = false; else tb.Append(separator);
|
||||
if (first) first = false; else tb.Write(separator);
|
||||
action(item, tb);
|
||||
}
|
||||
return tb;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="StringBuilder"/> implementation of <see cref="ITrapBuilder"/>,
|
||||
/// used for debugging only.
|
||||
/// </summary>
|
||||
public class TrapStringBuilder : ITrapBuilder
|
||||
{
|
||||
readonly StringBuilder StringBuilder = new StringBuilder();
|
||||
|
||||
public ITrapBuilder Append(object arg)
|
||||
{
|
||||
StringBuilder.Append(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ITrapBuilder Append(string arg)
|
||||
{
|
||||
StringBuilder.Append(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ITrapBuilder AppendLine()
|
||||
{
|
||||
StringBuilder.AppendLine();
|
||||
return this;
|
||||
}
|
||||
|
||||
public override string ToString() => StringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Semmle.Extraction
|
||||
{
|
||||
public interface ITrapEmitter
|
||||
{
|
||||
void EmitToTrapBuilder(ITrapBuilder tb);
|
||||
void EmitToTrapBuilder(TextWriter tw);
|
||||
}
|
||||
|
||||
public sealed class TrapWriter : IDisposable
|
||||
@@ -35,9 +35,6 @@ namespace Semmle.Extraction
|
||||
|
||||
public StreamWriter Writer => WriterLazy.Value;
|
||||
|
||||
readonly Lazy<TrapBuilder> BuilderLazy;
|
||||
TrapBuilder Builder => BuilderLazy.Value;
|
||||
|
||||
readonly ILogger Logger;
|
||||
|
||||
public TrapWriter(ILogger logger, string outputfile, string trap, string archive, bool discardDuplicates)
|
||||
@@ -68,7 +65,6 @@ namespace Semmle.Extraction
|
||||
var compressionStream = new GZipStream(fileStream, CompressionMode.Compress);
|
||||
return new StreamWriter(compressionStream, UTF8, 2000000);
|
||||
});
|
||||
BuilderLazy = new Lazy<TrapBuilder>(() => new TrapBuilder(WriterLazy.Value));
|
||||
this.archive = archive;
|
||||
this.discardDuplicates = discardDuplicates;
|
||||
}
|
||||
@@ -177,7 +173,7 @@ namespace Semmle.Extraction
|
||||
|
||||
public void Emit(ITrapEmitter emitter)
|
||||
{
|
||||
emitter.EmitToTrapBuilder(Builder);
|
||||
emitter.EmitToTrapBuilder(Writer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -196,34 +192,6 @@ namespace Semmle.Extraction
|
||||
}
|
||||
}
|
||||
|
||||
class TrapBuilder : ITrapBuilder
|
||||
{
|
||||
readonly StreamWriter StreamWriter;
|
||||
|
||||
public TrapBuilder(StreamWriter sw)
|
||||
{
|
||||
StreamWriter = sw;
|
||||
}
|
||||
|
||||
public ITrapBuilder Append(object arg)
|
||||
{
|
||||
StreamWriter.Write(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ITrapBuilder Append(string arg)
|
||||
{
|
||||
StreamWriter.Write(arg);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ITrapBuilder AppendLine()
|
||||
{
|
||||
StreamWriter.WriteLine();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to archive the specified input file to the normal area of the source archive.
|
||||
/// The file's path must be sufficiently short so as to render the path of its copy in the
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Semmle.Extraction
|
||||
@@ -35,7 +36,7 @@ namespace Semmle.Extraction
|
||||
array.Sum(encoding.GetByteCount) > maxStringBytes;
|
||||
}
|
||||
|
||||
private static void WriteString(ITrapBuilder tb, string s) => tb.Append(EncodeString(s));
|
||||
private static void WriteString(TextWriter tb, string s) => tb.Write(EncodeString(s));
|
||||
|
||||
/// <summary>
|
||||
/// Truncates a string such that the output UTF8 does not exceed <paramref name="bytesRemaining"/> bytes.
|
||||
@@ -73,7 +74,7 @@ namespace Semmle.Extraction
|
||||
/// <param name="tb">The trapbuilder</param>
|
||||
/// <param name="s">The string to output.</param>
|
||||
/// <param name="bytesRemaining">The remaining bytes available to output.</param>
|
||||
private static void WriteTruncatedString(ITrapBuilder tb, string s, ref int bytesRemaining)
|
||||
private static void WriteTruncatedString(TextWriter tb, string s, ref int bytesRemaining)
|
||||
{
|
||||
WriteString(tb, TruncateString(s, ref bytesRemaining));
|
||||
}
|
||||
@@ -81,63 +82,64 @@ namespace Semmle.Extraction
|
||||
/// <summary>
|
||||
/// Constructs a unique string for this tuple.
|
||||
/// </summary>
|
||||
/// <param name="tb">The trap builder used to store the result.</param>
|
||||
public void EmitToTrapBuilder(ITrapBuilder tb)
|
||||
/// <param name="tw">The trap builder used to store the result.</param>
|
||||
public void EmitToTrapBuilder(TextWriter tw)
|
||||
{
|
||||
tb.Append(Name).Append("(");
|
||||
tw.Write(Name);
|
||||
tw.Write("(");
|
||||
|
||||
int column = 0;
|
||||
foreach (var a in Args)
|
||||
{
|
||||
if (column > 0) tb.Append(", ");
|
||||
tw.WriteSeparator(", ", column++);
|
||||
switch(a)
|
||||
{
|
||||
case Label l:
|
||||
l.AppendTo(tb);
|
||||
l.AppendTo(tw);
|
||||
break;
|
||||
case IEntity e:
|
||||
e.Label.AppendTo(tb);
|
||||
e.Label.AppendTo(tw);
|
||||
break;
|
||||
case string s:
|
||||
tb.Append("\"");
|
||||
tw.Write("\"");
|
||||
if (NeedsTruncation(s))
|
||||
{
|
||||
// Slow path
|
||||
int remaining = maxStringBytes;
|
||||
WriteTruncatedString(tb, s, ref remaining);
|
||||
WriteTruncatedString(tw, s, ref remaining);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fast path
|
||||
WriteString(tb, s);
|
||||
WriteString(tw, s);
|
||||
}
|
||||
tb.Append("\"");
|
||||
tw.Write("\"");
|
||||
break;
|
||||
case System.Enum _:
|
||||
tb.Append((int)a);
|
||||
tw.Write((int)a);
|
||||
break;
|
||||
case int i:
|
||||
tb.Append(i);
|
||||
tw.Write(i);
|
||||
break;
|
||||
case float f:
|
||||
tb.Append(f.ToString("0.#####e0")); // Trap importer won't accept ints
|
||||
tw.Write(f.ToString("0.#####e0")); // Trap importer won't accept ints
|
||||
break;
|
||||
case string[] array:
|
||||
tb.Append("\"");
|
||||
tw.Write('\"');
|
||||
if (NeedsTruncation(array))
|
||||
{
|
||||
// Slow path
|
||||
int remaining = maxStringBytes;
|
||||
foreach (var element in array)
|
||||
WriteTruncatedString(tb, element, ref remaining);
|
||||
WriteTruncatedString(tw, element, ref remaining);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fast path
|
||||
foreach (var element in array)
|
||||
WriteString(tb, element);
|
||||
WriteString(tw, element);
|
||||
}
|
||||
tb.Append("\"");
|
||||
tw.Write('\"');
|
||||
break;
|
||||
case null:
|
||||
throw new InternalError($"Attempt to write a null argument tuple {Name} at column {column}");
|
||||
@@ -147,14 +149,13 @@ namespace Semmle.Extraction
|
||||
|
||||
++column;
|
||||
}
|
||||
tb.Append(")");
|
||||
tb.AppendLine();
|
||||
tw.WriteLine(")");
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
// Only implemented for debugging purposes
|
||||
var tsb = new TrapStringBuilder();
|
||||
var tsb = new StringWriter();
|
||||
EmitToTrapBuilder(tsb);
|
||||
return tsb.ToString();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user