C#: Address review comments. Tidy up tuple generation, consolidating code and use run-time type information instead of FirstParam/NextParam.

This commit is contained in:
Calum Grant
2019-08-28 12:21:27 +01:00
parent 40f56ff4b3
commit 7df90f13ed
10 changed files with 159 additions and 327 deletions

View File

@@ -247,7 +247,7 @@ namespace Semmle.Extraction.CIL.Entities
} }
} }
public bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code) private bool TryGetPrimitiveTypeCode(out PrimitiveTypeCode code)
{ {
if (ContainingType == null && Namespace.Name == cx.SystemNamespace.Name) if (ContainingType == null && Namespace.Name == cx.SystemNamespace.Name)
{ {
@@ -314,7 +314,7 @@ namespace Semmle.Extraction.CIL.Entities
return false; return false;
} }
public bool IsPrimitiveType => TryGetPrimitiveTypeCode(out _); protected bool IsPrimitiveType => TryGetPrimitiveTypeCode(out _);
public static Type DecodeType(GenericContext gc, TypeSpecificationHandle handle) => public static Type DecodeType(GenericContext gc, TypeSpecificationHandle handle) =>
gc.cx.mdReader.GetTypeSpecification(handle).DecodeSignature(gc.cx.TypeSignatureDecoder, gc); gc.cx.mdReader.GetTypeSpecification(handle).DecodeSignature(gc.cx.TypeSignatureDecoder, gc);

View File

@@ -15,7 +15,7 @@ namespace Semmle.Extraction.CIL
public T Populate<T>(T e) where T : IExtractedEntity public T Populate<T>(T e) where T : IExtractedEntity
{ {
if(e.Label.Valid) if (e.Label.Valid)
{ {
return e; // Already populated return e; // Already populated
} }
@@ -72,7 +72,7 @@ namespace Semmle.Extraction.CIL
{ {
PrimitiveType e = primitiveTypes[(int)code]; PrimitiveType e = primitiveTypes[(int)code];
if(e is null) if (e is null)
{ {
e = new PrimitiveType(this, code); e = new PrimitiveType(this, code);
e.Label = cx.GetNewLabel(); e.Label = cx.GetNewLabel();
@@ -157,7 +157,7 @@ namespace Semmle.Extraction.CIL
/// <returns>The string.</returns> /// <returns>The string.</returns>
public string GetString(StringHandle h) => mdReader.GetString(h); public string GetString(StringHandle h) => mdReader.GetString(h);
#region Namespaces #region Namespaces
readonly CachedFunction<StringHandle, Namespace> namespaceFactory; readonly CachedFunction<StringHandle, Namespace> namespaceFactory;
@@ -197,9 +197,9 @@ namespace Semmle.Extraction.CIL
NamespaceDefinition nd = mdReader.GetNamespaceDefinition(handle); NamespaceDefinition nd = mdReader.GetNamespaceDefinition(handle);
return Populate(new Namespace(this, GetString(nd.Name), Create(nd.Parent))); return Populate(new Namespace(this, GetString(nd.Name), Create(nd.Parent)));
} }
#endregion #endregion
#region Locations #region Locations
readonly CachedFunction<PDB.ISourceFile, PdbSourceFile> sourceFiles; readonly CachedFunction<PDB.ISourceFile, PdbSourceFile> sourceFiles;
readonly CachedFunction<string, Folder> folders; readonly CachedFunction<string, Folder> folders;
readonly CachedFunction<PDB.Location, PdbSourceLocation> sourceLocations; readonly CachedFunction<PDB.Location, PdbSourceLocation> sourceLocations;
@@ -225,7 +225,7 @@ namespace Semmle.Extraction.CIL
/// <returns>A source location entity.</returns> /// <returns>A source location entity.</returns>
public PdbSourceLocation CreateSourceLocation(PDB.Location loc) => sourceLocations[loc]; public PdbSourceLocation CreateSourceLocation(PDB.Location loc) => sourceLocations[loc];
#endregion #endregion
readonly CachedFunction<GenericContext, Handle, IExtractedEntity> genericHandleFactory; readonly CachedFunction<GenericContext, Handle, IExtractedEntity> genericHandleFactory;

View File

@@ -23,12 +23,12 @@ namespace Semmle.Extraction.CSharp
internal static void accessors(this TextWriter trapFile, Accessor accessorKey, int kind, string name, Property propKey, Accessor unboundAccessor) internal static void accessors(this TextWriter trapFile, Accessor accessorKey, int kind, string name, Property propKey, Accessor unboundAccessor)
{ {
trapFile.BeginTuple("accessors").Param(accessorKey).Param(kind).Param(name).Param(propKey).Param(unboundAccessor).EndTuple(); trapFile.WriteTuple("accessors", accessorKey, kind, name, propKey, unboundAccessor);
} }
internal static void array_element_type(this TextWriter trapFile, ArrayType array, int dimension, int rank, Type elementType) internal static void array_element_type(this TextWriter trapFile, ArrayType array, int dimension, int rank, Type elementType)
{ {
trapFile.BeginTuple("array_element_type").Param(array).Param(dimension).Param(rank).Param(elementType).EndTuple(); trapFile.WriteTuple("array_element_type", array, dimension, rank, elementType);
} }
internal static void attributes(this TextWriter trapFile, Attribute attribute, Type attributeType, IEntity entity) internal static void attributes(this TextWriter trapFile, Attribute attribute, Type attributeType, IEntity entity)
@@ -43,7 +43,7 @@ namespace Semmle.Extraction.CSharp
internal static void catch_type(this TextWriter trapFile, Entities.Statements.Catch @catch, Type type, bool explicityCaught) internal static void catch_type(this TextWriter trapFile, Entities.Statements.Catch @catch, Type type, bool explicityCaught)
{ {
trapFile.BeginTuple("catch_type").Param(@catch).Param(type).Param(explicityCaught ? 1 : 2).EndTuple(); trapFile.WriteTuple("catch_type", @catch, type, explicityCaught ? 1 : 2);
} }
internal static void commentblock(this TextWriter trapFile, CommentBlock k) internal static void commentblock(this TextWriter trapFile, CommentBlock k)
@@ -53,12 +53,12 @@ namespace Semmle.Extraction.CSharp
internal static void commentblock_binding(this TextWriter trapFile, CommentBlock commentBlock, Label entity, CommentBinding binding) internal static void commentblock_binding(this TextWriter trapFile, CommentBlock commentBlock, Label entity, CommentBinding binding)
{ {
trapFile.BeginTuple("commentblock_binding").Param(commentBlock).Param(entity).Param((int)binding).EndTuple(); trapFile.WriteTuple("commentblock_binding", commentBlock, entity, (int)binding);
} }
internal static void commentblock_child(this TextWriter trapFile, CommentBlock commentBlock, CommentLine commentLine, int child) internal static void commentblock_child(this TextWriter trapFile, CommentBlock commentBlock, CommentLine commentLine, int child)
{ {
trapFile.BeginTuple("commentblock_child").Param(commentBlock).Param(commentLine).Param(child).EndTuple(); trapFile.WriteTuple("commentblock_child", commentBlock, commentLine, child);
} }
internal static void commentblock_location(this TextWriter trapFile, CommentBlock k, Location l) internal static void commentblock_location(this TextWriter trapFile, CommentBlock k, Location l)
@@ -68,7 +68,7 @@ namespace Semmle.Extraction.CSharp
internal static void commentline(this TextWriter trapFile, CommentLine commentLine, CommentLineType type, string text, string rawtext) internal static void commentline(this TextWriter trapFile, CommentLine commentLine, CommentLineType type, string text, string rawtext)
{ {
trapFile.BeginTuple("commentline").Param(commentLine).Param((int)type).Param(text).Param(rawtext).EndTuple(); trapFile.WriteTuple("commentline", commentLine, (int)type, text, rawtext);
} }
internal static void commentline_location(this TextWriter trapFile, CommentLine commentLine, Location location) internal static void commentline_location(this TextWriter trapFile, CommentLine commentLine, Location location)
@@ -78,32 +78,32 @@ namespace Semmle.Extraction.CSharp
internal static void compilation_args(this TextWriter trapFile, Compilation compilation, int index, string arg) internal static void compilation_args(this TextWriter trapFile, Compilation compilation, int index, string arg)
{ {
trapFile.BeginTuple("compilation_args").Param(compilation).Param(index).Param(arg).EndTuple(); trapFile.WriteTuple("compilation_args", compilation, index, arg);
} }
internal static void compilation_compiling_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file) internal static void compilation_compiling_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file)
{ {
trapFile.BeginTuple("compilation_compiling_files").Param(compilation).Param(index).Param(file).EndTuple(); trapFile.WriteTuple("compilation_compiling_files", compilation, index, file);
} }
internal static void compilation_referencing_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file) internal static void compilation_referencing_files(this TextWriter trapFile, Compilation compilation, int index, Extraction.Entities.File file)
{ {
trapFile.BeginTuple("compilation_referencing_files").Param(compilation).Param(index).Param(file).EndTuple(); trapFile.WriteTuple("compilation_referencing_files", compilation, index, file);
} }
internal static void compilation_finished(this TextWriter trapFile, Compilation compilation, float cpuSeconds, float elapsedSeconds) internal static void compilation_finished(this TextWriter trapFile, Compilation compilation, float cpuSeconds, float elapsedSeconds)
{ {
trapFile.BeginTuple("compilation_finished").Param(compilation).Param(cpuSeconds).Param(elapsedSeconds).EndTuple(); trapFile.WriteTuple("compilation_finished", compilation, cpuSeconds, elapsedSeconds);
} }
internal static void compilation_time(this TextWriter trapFile, Compilation compilation, int num, int index, float metric) internal static void compilation_time(this TextWriter trapFile, Compilation compilation, int num, int index, float metric)
{ {
trapFile.BeginTuple("compilation_time").Param(compilation).Param(num).Param(index).Param(metric).EndTuple(); trapFile.WriteTuple("compilation_time", compilation, num, index, metric);
} }
internal static void compilations(this TextWriter trapFile, Compilation compilation, string cwd) internal static void compilations(this TextWriter trapFile, Compilation compilation, string cwd)
{ {
trapFile.BeginTuple("compilations").Param(compilation).Param(cwd).EndTuple(); trapFile.WriteTuple("compilations", compilation, cwd);
} }
internal static void compiler_generated(this TextWriter trapFile, IEntity entity) internal static void compiler_generated(this TextWriter trapFile, IEntity entity)
@@ -118,7 +118,7 @@ namespace Semmle.Extraction.CSharp
internal static void constant_value(this TextWriter trapFile, IEntity field, string value) internal static void constant_value(this TextWriter trapFile, IEntity field, string value)
{ {
trapFile.BeginTuple("constant_value").Param(field).Param(value).EndTuple(); trapFile.WriteTuple("constant_value", field, value);
} }
internal static void constructed_generic(this TextWriter trapFile, IEntity constructedTypeOrMethod, IEntity unboundTypeOrMethod) internal static void constructed_generic(this TextWriter trapFile, IEntity constructedTypeOrMethod, IEntity unboundTypeOrMethod)
@@ -153,17 +153,17 @@ namespace Semmle.Extraction.CSharp
internal static void diagnostic_for(this TextWriter trapFile, Diagnostic diag, Compilation comp, int fileNo, int index) internal static void diagnostic_for(this TextWriter trapFile, Diagnostic diag, Compilation comp, int fileNo, int index)
{ {
trapFile.BeginTuple("diagnostic_for").Param(diag).Param(comp).Param(fileNo).Param(index).EndTuple(); trapFile.WriteTuple("diagnostic_for", diag, comp, fileNo, index);
} }
internal static void diagnostics(this TextWriter trapFile, Diagnostic diag, int severity, string errorTag, string errorMessage, string fullErrorMessage, Location location) internal static void diagnostics(this TextWriter trapFile, Diagnostic diag, int severity, string errorTag, string errorMessage, string fullErrorMessage, Location location)
{ {
trapFile.BeginTuple("diagnostics").Param(diag).Param(severity).Param(errorTag).Param(errorMessage).Param(fullErrorMessage).Param(location).EndTuple(); trapFile.WriteTuple("diagnostics", diag, severity, errorTag, errorMessage, fullErrorMessage, location);
} }
internal static void dynamic_member_name(this TextWriter trapFile, Expression e, string name) internal static void dynamic_member_name(this TextWriter trapFile, Expression e, string name)
{ {
trapFile.BeginTuple("dynamic_member_name").Param(e).Param(name).EndTuple(); trapFile.WriteTuple("dynamic_member_name", e, name);
} }
internal static void enum_underlying_type(this TextWriter trapFile, Type @enum, Type type) internal static void enum_underlying_type(this TextWriter trapFile, Type @enum, Type type)
@@ -178,7 +178,7 @@ namespace Semmle.Extraction.CSharp
internal static void event_accessors(this TextWriter trapFile, EventAccessor accessorKey, int type, string name, Event eventKey, EventAccessor unboundAccessor) internal static void event_accessors(this TextWriter trapFile, EventAccessor accessorKey, int type, string name, Event eventKey, EventAccessor unboundAccessor)
{ {
trapFile.BeginTuple("event_accessors").Param(accessorKey).Param(type).Param(name).Param(eventKey).Param(unboundAccessor).EndTuple(); trapFile.WriteTuple("event_accessors", accessorKey, type, name, eventKey, unboundAccessor);
} }
internal static void event_location(this TextWriter trapFile, Event eventKey, Location locationKey) internal static void event_location(this TextWriter trapFile, Event eventKey, Location locationKey)
@@ -268,7 +268,7 @@ namespace Semmle.Extraction.CSharp
internal static void fields(this TextWriter trapFile, Field field, int @const, string name, Type declaringType, Type fieldType, Field unboundKey) internal static void fields(this TextWriter trapFile, Field field, int @const, string name, Type declaringType, Type fieldType, Field unboundKey)
{ {
trapFile.BeginTuple("fields").Param(field).Param(@const).Param(name).Param(declaringType).Param(fieldType).Param(unboundKey).EndTuple(); trapFile.WriteTuple("fields", field, @const, name, declaringType, fieldType, unboundKey);
} }
internal static void general_type_parameter_constraints(this TextWriter trapFile, TypeParameterConstraints constraints, int hasKind) internal static void general_type_parameter_constraints(this TextWriter trapFile, TypeParameterConstraints constraints, int hasKind)
@@ -328,7 +328,7 @@ namespace Semmle.Extraction.CSharp
internal static void localvars(this TextWriter trapFile, LocalVariable key, int @const, string name, int @var, Type type, Expression expr) internal static void localvars(this TextWriter trapFile, LocalVariable key, int @const, string name, int @var, Type type, Expression expr)
{ {
trapFile.BeginTuple("localvars").Param(key).Param(@const).Param(name).Param(@var).Param(type).Param(expr).EndTuple(); trapFile.WriteTuple("localvars", key, @const, name, @var, type, expr);
} }
public static void metadata_handle(this TextWriter trapFile, IEntity entity, Location assembly, int handleValue) public static void metadata_handle(this TextWriter trapFile, IEntity entity, Location assembly, int handleValue)
@@ -348,7 +348,7 @@ namespace Semmle.Extraction.CSharp
internal static void modifiers(this TextWriter trapFile, Label entity, string modifier) internal static void modifiers(this TextWriter trapFile, Label entity, string modifier)
{ {
trapFile.BeginTuple("modifiers").Param(entity).Param(modifier).EndTuple(); trapFile.WriteTuple("modifiers", entity, modifier);
} }
internal static void mutator_invocation_mode(this TextWriter trapFile, Expression expr, int mode) internal static void mutator_invocation_mode(this TextWriter trapFile, Expression expr, int mode)
@@ -383,7 +383,7 @@ namespace Semmle.Extraction.CSharp
internal static void numlines(this TextWriter trapFile, IEntity label, LineCounts lineCounts) internal static void numlines(this TextWriter trapFile, IEntity label, LineCounts lineCounts)
{ {
trapFile.BeginTuple("numlines").Param(label).Param(lineCounts.Total).Param(lineCounts.Code).Param(lineCounts.Comment).EndTuple(); trapFile.WriteTuple("numlines", label, lineCounts.Total, lineCounts.Code, lineCounts.Comment);
} }
internal static void operator_location(this TextWriter trapFile, UserOperator @operator, Location location) internal static void operator_location(this TextWriter trapFile, UserOperator @operator, Location location)
@@ -393,7 +393,7 @@ namespace Semmle.Extraction.CSharp
internal static void operators(this TextWriter trapFile, UserOperator method, string methodName, string symbol, Type classKey, Type returnType, UserOperator originalDefinition) internal static void operators(this TextWriter trapFile, UserOperator method, string methodName, string symbol, Type classKey, Type returnType, UserOperator originalDefinition)
{ {
trapFile.BeginTuple("operators").Param(method).Param(methodName).Param(symbol).Param(classKey).Param(returnType).Param(originalDefinition).EndTuple(); trapFile.WriteTuple("operators", method, methodName, symbol, classKey, returnType, originalDefinition);
} }
internal static void overrides(this TextWriter trapFile, Method overriding, Method overridden) internal static void overrides(this TextWriter trapFile, Method overriding, Method overridden)
@@ -408,7 +408,7 @@ namespace Semmle.Extraction.CSharp
internal static void @params(this TextWriter trapFile, Parameter param, string name, Type type, int child, Parameter.Kind mode, IEntity method, Parameter originalDefinition) internal static void @params(this TextWriter trapFile, Parameter param, string name, Type type, int child, Parameter.Kind mode, IEntity method, Parameter originalDefinition)
{ {
trapFile.BeginTuple("params").Param(param).Param(name).Param(type).Param(child).Param((int)mode).Param(method).Param(originalDefinition).EndTuple(); trapFile.WriteTuple("params", param, name, type, child, (int)mode, method, originalDefinition);
} }
internal static void parent_namespace(this TextWriter trapFile, IEntity type, Namespace parent) internal static void parent_namespace(this TextWriter trapFile, IEntity type, Namespace parent)
@@ -513,7 +513,7 @@ namespace Semmle.Extraction.CSharp
internal static void type_parameters(this TextWriter trapFile, TypeParameter param, int child, IEntity typeOrMethod) internal static void type_parameters(this TextWriter trapFile, TypeParameter param, int child, IEntity typeOrMethod)
{ {
trapFile.BeginTuple("type_parameters").Param(param).Param(child).Param(typeOrMethod).Param((int)param.Variance).EndTuple(); trapFile.WriteTuple("type_parameters", param, child, typeOrMethod, (int)param.Variance);
} }
internal static void typeref_type(this TextWriter trapFile, NamedTypeRef typeref, Type type) internal static void typeref_type(this TextWriter trapFile, NamedTypeRef typeref, Type type)
@@ -528,7 +528,7 @@ namespace Semmle.Extraction.CSharp
internal static void types(this TextWriter trapFile, Type type, TypeKind kind, string name) internal static void types(this TextWriter trapFile, Type type, TypeKind kind, string name)
{ {
trapFile.BeginTuple("types").Param(type).Param((int)kind).Param(name).EndTuple(); trapFile.WriteTuple("types", type, (int)kind, name);
} }
internal static void using_namespace_directives(this TextWriter trapFile, UsingDirective @using, Namespace ns) internal static void using_namespace_directives(this TextWriter trapFile, UsingDirective @using, Namespace ns)

View File

@@ -191,7 +191,7 @@ namespace Semmle.Extraction.Tests
Content = content; Content = content;
} }
public void EmitToTrapBuilder(TextWriter trapFile) public void EmitTrap(TextWriter trapFile)
{ {
trapFile.Write(Content); trapFile.Write(Content);
} }

View File

@@ -332,7 +332,7 @@ namespace Semmle.Extraction
Key = key; Key = key;
} }
public void EmitToTrapBuilder(TextWriter trapFile) public void EmitTrap(TextWriter trapFile)
{ {
trapFile.Write(".push "); trapFile.Write(".push ");
Key.AppendTo(trapFile); Key.AppendTo(trapFile);
@@ -342,7 +342,7 @@ namespace Semmle.Extraction
class PopEmitter : ITrapEmitter class PopEmitter : ITrapEmitter
{ {
public void EmitToTrapBuilder(TextWriter trapFile) public void EmitTrap(TextWriter trapFile)
{ {
trapFile.WriteLine(".pop"); trapFile.WriteLine(".pop");
} }

View File

@@ -1,43 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Semmle.Extraction
{
public static class TrapBuilderExtensions
{
/// <summary>
/// Appends a [comma] separated list to a trap builder.
/// </summary>
/// <typeparam name="T">The type of the list.</typeparam>
/// <param name="trapFile">The trap builder to append to.</param>
/// <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 TextWriter AppendList<T>(this TextWriter trapFile, string separator, IEnumerable<T> items) where T:IEntity
{
return trapFile.BuildList(separator, items, (x, tb0) => { tb0.WriteSubId(x); });
}
/// <summary>
/// Builds a trap builder using a separator and an action for each item in the list.
/// </summary>
/// <typeparam name="T">The type of the items.</typeparam>
/// <param name="trapFile">The trap builder to append to.</param>
/// <param name="separator">The separator string (e.g. ",")</param>
/// <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 TextWriter BuildList<T>(this TextWriter trapFile, string separator, IEnumerable<T> items, Action<T, TextWriter> action)
{
bool first = true;
foreach (var item in items)
{
if (first) first = false; else trapFile.Write(separator);
action(item, trapFile);
}
return trapFile;
}
}
}

View File

@@ -1,4 +1,6 @@
using System.IO; using System;
using System.Collections.Generic;
using System.IO;
namespace Semmle.Extraction namespace Semmle.Extraction
{ {
@@ -27,85 +29,57 @@ namespace Semmle.Extraction
if (index++ > 0) trapFile.Write(separator); if (index++ > 0) trapFile.Write(separator);
} }
public struct FirstParam
public static TextWriter WriteColumn(this TextWriter trapFile, int i)
{ {
private readonly TextWriter Writer; trapFile.Write(i);
return trapFile;
public FirstParam(TextWriter trapFile)
{
Writer = trapFile;
}
public NextParam Param(IEntity entity)
{
Writer.WriteLabel(entity.Label.Value);
return new NextParam(Writer);
}
public NextParam Param(Label label)
{
Writer.WriteLabel(label.Value);
return new NextParam(Writer);
}
public void EndTuple()
{
Writer.WriteLine(')');
}
} }
public struct NextParam public static TextWriter WriteColumn(this TextWriter trapFile, string s)
{ {
private readonly TextWriter Writer; trapFile.WriteTrapString(s);
return trapFile;
}
public NextParam(TextWriter trapFile) public static TextWriter WriteColumn(this TextWriter trapFile, IEntity entity)
{ {
Writer = trapFile; trapFile.WriteLabel(entity.Label.Value);
} return trapFile;
}
private void WriteComma() public static TextWriter WriteColumn(this TextWriter trapFile, Label label)
{ {
Writer.Write(", "); trapFile.WriteLabel(label.Value);
} return trapFile;
}
public NextParam Param(string str)
{
WriteComma();
Writer.WriteTrapString(str);
return this;
}
public NextParam Param(float f) public static TextWriter WriteColumn(this TextWriter trapFile, float f)
{ {
WriteComma(); trapFile.WriteTrapFloat(f);
Writer.WriteTrapFloat(f); return trapFile;
return this; }
}
public NextParam Param(Label label)
{
WriteComma();
Writer.WriteLabel(label.Value);
return this;
}
public NextParam Param(int i) public static TextWriter WriteColumn(this TextWriter trapFile, object o)
{
switch (o)
{ {
WriteComma(); case int i:
Writer.Write(i); return trapFile.WriteColumn(i);
return this; case float f:
} return trapFile.WriteColumn(f);
case string s:
public NextParam Param(IEntity e) return trapFile.WriteColumn(s);
{ case IEntity e:
WriteComma(); return trapFile.WriteColumn(e);
Writer.WriteLabel(e.Label.Value); case Label l:
return this; return trapFile.WriteColumn(l);
} case Enum _:
return trapFile.WriteColumn((int)o);
public void EndTuple() default:
{ throw new ArgumentException(nameof(o));
Writer.WriteLine(')');
} }
} }
@@ -185,66 +159,94 @@ namespace Semmle.Extraction
trapFile.Write(f.ToString("0.#####e0")); // Trap importer won't accept ints trapFile.Write(f.ToString("0.#####e0")); // Trap importer won't accept ints
} }
public static FirstParam BeginTuple(this TextWriter trapFile, string name) public static void WriteTuple(this TextWriter trapFile, string name, params object[] @params)
{ {
trapFile.Write(name); trapFile.Write(name);
trapFile.Write('('); trapFile.Write('(');
return new FirstParam(trapFile); int index = 0;
foreach (var p in @params)
{
trapFile.WriteSeparator(",", ref index);
trapFile.WriteColumn(p);
}
trapFile.WriteLine(')');
} }
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1) public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1)
{ {
trapFile.BeginTuple(name).Param(p1).EndTuple(); trapFile.Write(name);
trapFile.Write('(');
trapFile.WriteColumn(p1);
trapFile.WriteLine(')');
} }
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, IEntity p2) public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, object p2)
{ {
trapFile.BeginTuple(name).Param(p1).Param(p2).EndTuple(); trapFile.Write(name);
trapFile.Write('(');
trapFile.WriteColumn(p1);
trapFile.Write(',');
trapFile.WriteColumn(p2);
trapFile.WriteLine(')');
} }
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, string p2, IEntity p3, IEntity p4) public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, object p2, object p3)
{ {
trapFile.BeginTuple(name).Param(p1).Param(p2).Param(p3).Param(p4).EndTuple(); trapFile.Write(name);
trapFile.Write('(');
trapFile.WriteColumn(p1);
trapFile.Write(',');
trapFile.WriteColumn(p2);
trapFile.Write(',');
trapFile.WriteColumn(p3);
trapFile.WriteLine(')');
} }
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, string p2, IEntity p3) public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, object p2, object p3, object p4)
{ {
trapFile.BeginTuple(name).Param(p1).Param(p2).Param(p3).EndTuple(); trapFile.Write(name);
trapFile.Write('(');
trapFile.WriteColumn(p1);
trapFile.Write(',');
trapFile.WriteColumn(p2);
trapFile.Write(',');
trapFile.WriteColumn(p3);
trapFile.Write(',');
trapFile.WriteColumn(p4);
trapFile.WriteLine(')');
} }
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, int p2, IEntity p3) /// <summary>
/// Appends a [comma] separated list to a trap builder.
/// </summary>
/// <typeparam name="T">The type of the list.</typeparam>
/// <param name="trapFile">The trap builder to append to.</param>
/// <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 TextWriter AppendList<T>(this TextWriter trapFile, string separator, IEnumerable<T> items) where T : IEntity
{ {
trapFile.BeginTuple(name).Param(p1).Param(p2).Param(p3).EndTuple(); return trapFile.BuildList(separator, items, (x, tb0) => { tb0.WriteSubId(x); });
} }
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, int p2, int p3) /// <summary>
/// Builds a trap builder using a separator and an action for each item in the list.
/// </summary>
/// <typeparam name="T">The type of the items.</typeparam>
/// <param name="trapFile">The trap builder to append to.</param>
/// <param name="separator">The separator string (e.g. ",")</param>
/// <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 TextWriter BuildList<T>(this TextWriter trapFile, string separator, IEnumerable<T> items, Action<T, TextWriter> action)
{ {
trapFile.BeginTuple(name).Param(p1).Param(p2).Param(p3).EndTuple(); bool first = true;
} foreach (var item in items)
{
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, IEntity p2, int p3) if (first) first = false; else trapFile.Write(separator);
{ action(item, trapFile);
trapFile.BeginTuple(name).Param(p1).Param(p2).Param(p3).EndTuple(); }
} return trapFile;
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, IEntity p2, IEntity p3)
{
trapFile.BeginTuple(name).Param(p1).Param(p2).Param(p3).EndTuple();
}
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, string p2, IEntity p3, IEntity p4, IEntity p5)
{
trapFile.BeginTuple(name).Param(p1).Param(p2).Param(p3).Param(p4).Param(p5).EndTuple();
}
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, int p2)
{
trapFile.BeginTuple(name).Param(p1).Param(p2).EndTuple();
}
public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, string p2)
{
trapFile.BeginTuple(name).Param(p1).Param(p2).EndTuple();
} }
} }
} }

View File

@@ -10,7 +10,7 @@ namespace Semmle.Extraction
{ {
public interface ITrapEmitter public interface ITrapEmitter
{ {
void EmitToTrapBuilder(TextWriter trapFile); void EmitTrap(TextWriter trapFile);
} }
public sealed class TrapWriter : IDisposable public sealed class TrapWriter : IDisposable
@@ -202,7 +202,7 @@ namespace Semmle.Extraction
public void Emit(ITrapEmitter emitter) public void Emit(ITrapEmitter emitter)
{ {
emitter.EmitToTrapBuilder(Writer); emitter.EmitTrap(Writer);
} }
/// <summary> /// <summary>

View File

@@ -1,5 +1,4 @@
using System.IO; using System.IO;
using System.Linq;
namespace Semmle.Extraction namespace Semmle.Extraction
{ {
@@ -17,139 +16,13 @@ namespace Semmle.Extraction
Args = args; Args = args;
} }
const int maxStringBytes = 1<<20; // 1MB
static readonly System.Text.Encoding encoding = System.Text.Encoding.UTF8;
private static bool NeedsTruncation(string s)
{
// Optimization: only count the actual number of bytes if there is the possibility
// of the string exceeding maxStringBytes
return encoding.GetMaxByteCount(s.Length) > maxStringBytes &&
encoding.GetByteCount(s) > maxStringBytes;
}
private static bool NeedsTruncation(string[] array)
{
// Optimization: only count the actual number of bytes if there is the possibility
// of the strings exceeding maxStringBytes
return encoding.GetMaxByteCount(array.Sum(s => s.Length)) > maxStringBytes &&
array.Sum(encoding.GetByteCount) > maxStringBytes;
}
private static void WriteString(TextWriter trapFile, string s) => trapFile.Write(EncodeString(s));
/// <summary>
/// Truncates a string such that the output UTF8 does not exceed <paramref name="bytesRemaining"/> bytes.
/// </summary>
/// <param name="s">The input string to truncate.</param>
/// <param name="bytesRemaining">The number of bytes available.</param>
/// <returns>The truncated string.</returns>
private static string TruncateString(string s, ref int bytesRemaining)
{
int outputLen = encoding.GetByteCount(s);
if (outputLen > bytesRemaining)
{
outputLen = 0;
int chars;
for (chars = 0; chars < s.Length; ++chars)
{
var bytes = encoding.GetByteCount(s, chars, 1);
if (outputLen + bytes <= bytesRemaining)
outputLen += bytes;
else
break;
}
s = s.Substring(0, chars);
}
bytesRemaining -= outputLen;
return s;
}
private static string EncodeString(string s) => s.Replace("\"", "\"\"");
/// <summary>
/// Output a string to the trap file, such that the encoded output does not exceed
/// <paramref name="bytesRemaining"/> bytes.
/// </summary>
/// <param name="trapFile">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(TextWriter trapFile, string s, ref int bytesRemaining)
{
WriteString(trapFile, TruncateString(s, ref bytesRemaining));
}
/// <summary> /// <summary>
/// Constructs a unique string for this tuple. /// Constructs a unique string for this tuple.
/// </summary> /// </summary>
/// <param name="trapFile">The trap builder used to store the result.</param> /// <param name="trapFile">The trap file to write to.</param>
public void EmitToTrapBuilder(TextWriter trapFile) public void EmitTrap(TextWriter trapFile)
{ {
trapFile.Write(Name); trapFile.WriteTuple(Name, Args);
trapFile.Write("(");
int column = 0;
foreach (var a in Args)
{
trapFile.WriteSeparator(", ", ref column);
switch(a)
{
case Label l:
l.AppendTo(trapFile);
break;
case IEntity e:
e.Label.AppendTo(trapFile);
break;
case string s:
trapFile.Write("\"");
if (NeedsTruncation(s))
{
// Slow path
int remaining = maxStringBytes;
WriteTruncatedString(trapFile, s, ref remaining);
}
else
{
// Fast path
WriteString(trapFile, s);
}
trapFile.Write("\"");
break;
case System.Enum _:
trapFile.Write((int)a);
break;
case int i:
trapFile.Write(i);
break;
case float f:
trapFile.Write(f.ToString("0.#####e0")); // Trap importer won't accept ints
break;
case string[] array:
trapFile.Write('\"');
if (NeedsTruncation(array))
{
// Slow path
int remaining = maxStringBytes;
foreach (var element in array)
WriteTruncatedString(trapFile, element, ref remaining);
}
else
{
// Fast path
foreach (var element in array)
WriteString(trapFile, element);
}
trapFile.Write('\"');
break;
case null:
throw new InternalError($"Attempt to write a null argument tuple {Name} at column {column}");
default:
throw new InternalError($"Attempt to write an invalid argument type {a.GetType()} in tuple {Name} at column {column}");
}
++column;
}
trapFile.WriteLine(")");
} }
public override string ToString() public override string ToString()
@@ -157,7 +30,7 @@ namespace Semmle.Extraction
// Only implemented for debugging purposes // Only implemented for debugging purposes
using (var writer = new StringWriter()) using (var writer = new StringWriter())
{ {
EmitToTrapBuilder(writer); EmitTrap(writer);
return writer.ToString(); return writer.ToString();
} }
} }

View File

@@ -10,42 +10,42 @@ namespace Semmle.Extraction
{ {
public static void assemblies(this System.IO.TextWriter trapFile, Assembly assembly, File file, string identifier, string name, string version) public static void assemblies(this System.IO.TextWriter trapFile, Assembly assembly, File file, string identifier, string name, string version)
{ {
trapFile.BeginTuple("assemblies").Param(assembly).Param(file).Param(identifier).Param(name).Param(version).EndTuple(); trapFile.WriteTuple("assemblies", assembly, file, identifier, name, version);
} }
public static void containerparent(this System.IO.TextWriter trapFile, Folder parent, IEntity child) public static void containerparent(this System.IO.TextWriter trapFile, Folder parent, IEntity child)
{ {
trapFile.BeginTuple("containerparent").Param(parent).Param(child).EndTuple(); trapFile.WriteTuple("containerparent", parent, child);
} }
public static void extractor_messages(this System.IO.TextWriter trapFile, ExtractionMessage error, Semmle.Util.Logging.Severity severity, string origin, string errorMessage, string entityText, Location location, string stackTrace) public static void extractor_messages(this System.IO.TextWriter trapFile, ExtractionMessage error, Semmle.Util.Logging.Severity severity, string origin, string errorMessage, string entityText, Location location, string stackTrace)
{ {
trapFile.BeginTuple("extractor_messages").Param(error).Param((int)severity).Param(origin).Param(errorMessage).Param(entityText).Param(location).Param(stackTrace).EndTuple(); trapFile.WriteTuple("extractor_messages", error, (int)severity, origin, errorMessage, entityText, location, stackTrace);
} }
internal static void file_extraction_mode(this System.IO.TextWriter trapFile, Entities.File file, int mode) internal static void file_extraction_mode(this System.IO.TextWriter trapFile, Entities.File file, int mode)
{ {
trapFile.BeginTuple("file_extraction_mode").Param(file).Param(mode).EndTuple(); trapFile.WriteTuple("file_extraction_mode", file, mode);
} }
public static void files(this System.IO.TextWriter trapFile, File file, string fullName, string name, string extension) public static void files(this System.IO.TextWriter trapFile, File file, string fullName, string name, string extension)
{ {
trapFile.BeginTuple("files").Param(file).Param(fullName).Param(name).Param(extension).Param(0).EndTuple(); trapFile.WriteTuple("files", file, fullName, name, extension, 0);
} }
public static void folders(this System.IO.TextWriter trapFile, Folder folder, string path, string name) public static void folders(this System.IO.TextWriter trapFile, Folder folder, string path, string name)
{ {
trapFile.BeginTuple("folders").Param(folder).Param(path).Param(name).EndTuple(); trapFile.WriteTuple("folders", folder, path, name);
} }
public static void locations_default(this System.IO.TextWriter trapFile, SourceLocation label, Entities.File file, int startLine, int startCol, int endLine, int endCol) public static void locations_default(this System.IO.TextWriter trapFile, SourceLocation label, Entities.File file, int startLine, int startCol, int endLine, int endCol)
{ {
trapFile.BeginTuple("locations_default").Param(label).Param(file).Param(startLine).Param(startCol).Param(endLine).Param(endCol).EndTuple(); trapFile.WriteTuple("locations_default", label, file, startLine, startCol, endLine, endCol);
} }
public static void numlines(this System.IO.TextWriter trapFile, IEntity label, LineCounts lineCounts) public static void numlines(this System.IO.TextWriter trapFile, IEntity label, LineCounts lineCounts)
{ {
trapFile.BeginTuple("numlines").Param(label).Param(lineCounts.Total).Param(lineCounts.Code).Param(lineCounts.Comment).EndTuple(); trapFile.WriteTuple("numlines", label, lineCounts.Total, lineCounts.Code, lineCounts.Comment);
} }
} }
} }