From 7df90f13ed00c92df0a0d95f8a414b0d9b7a4c24 Mon Sep 17 00:00:00 2001 From: Calum Grant Date: Wed, 28 Aug 2019 12:21:27 +0100 Subject: [PATCH] C#: Address review comments. Tidy up tuple generation, consolidating code and use run-time type information instead of FirstParam/NextParam. --- .../Semmle.Extraction.CIL/Entities/Type.cs | 4 +- .../Semmle.Extraction.CIL/Factories.cs | 12 +- .../Semmle.Extraction.CSharp/Tuples.cs | 50 ++-- .../Semmle.Extraction.Tests/Layout.cs | 2 +- csharp/extractor/Semmle.Extraction/Context.cs | 4 +- .../Semmle.Extraction/TrapBuilder.cs | 43 ---- .../Semmle.Extraction/TrapExtensions.cs | 216 +++++++++--------- .../extractor/Semmle.Extraction/TrapWriter.cs | 4 +- csharp/extractor/Semmle.Extraction/Tuple.cs | 135 +---------- csharp/extractor/Semmle.Extraction/Tuples.cs | 16 +- 10 files changed, 159 insertions(+), 327 deletions(-) delete mode 100644 csharp/extractor/Semmle.Extraction/TrapBuilder.cs diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs index 07286b05102..6537da17dbf 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Type.cs @@ -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) { @@ -314,7 +314,7 @@ namespace Semmle.Extraction.CIL.Entities return false; } - public bool IsPrimitiveType => TryGetPrimitiveTypeCode(out _); + protected bool IsPrimitiveType => TryGetPrimitiveTypeCode(out _); public static Type DecodeType(GenericContext gc, TypeSpecificationHandle handle) => gc.cx.mdReader.GetTypeSpecification(handle).DecodeSignature(gc.cx.TypeSignatureDecoder, gc); diff --git a/csharp/extractor/Semmle.Extraction.CIL/Factories.cs b/csharp/extractor/Semmle.Extraction.CIL/Factories.cs index 933aeb7eb8d..4ef1d178783 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Factories.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Factories.cs @@ -15,7 +15,7 @@ namespace Semmle.Extraction.CIL public T Populate(T e) where T : IExtractedEntity { - if(e.Label.Valid) + if (e.Label.Valid) { return e; // Already populated } @@ -72,7 +72,7 @@ namespace Semmle.Extraction.CIL { PrimitiveType e = primitiveTypes[(int)code]; - if(e is null) + if (e is null) { e = new PrimitiveType(this, code); e.Label = cx.GetNewLabel(); @@ -157,7 +157,7 @@ namespace Semmle.Extraction.CIL /// The string. public string GetString(StringHandle h) => mdReader.GetString(h); -#region Namespaces + #region Namespaces readonly CachedFunction namespaceFactory; @@ -197,9 +197,9 @@ namespace Semmle.Extraction.CIL NamespaceDefinition nd = mdReader.GetNamespaceDefinition(handle); return Populate(new Namespace(this, GetString(nd.Name), Create(nd.Parent))); } -#endregion + #endregion -#region Locations + #region Locations readonly CachedFunction sourceFiles; readonly CachedFunction folders; readonly CachedFunction sourceLocations; @@ -225,7 +225,7 @@ namespace Semmle.Extraction.CIL /// A source location entity. public PdbSourceLocation CreateSourceLocation(PDB.Location loc) => sourceLocations[loc]; -#endregion + #endregion readonly CachedFunction genericHandleFactory; diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs index fa0fe8218a5..836a21312fb 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Tuples.cs @@ -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) { - 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) { - 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) @@ -43,7 +43,7 @@ namespace Semmle.Extraction.CSharp 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) @@ -53,12 +53,12 @@ namespace Semmle.Extraction.CSharp 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) { - 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) @@ -68,7 +68,7 @@ namespace Semmle.Extraction.CSharp 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) @@ -78,32 +78,32 @@ namespace Semmle.Extraction.CSharp 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) { - 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) { - 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) { - 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) { - 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) { - trapFile.BeginTuple("compilations").Param(compilation).Param(cwd).EndTuple(); + trapFile.WriteTuple("compilations", compilation, cwd); } 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) { - 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) @@ -153,17 +153,17 @@ namespace Semmle.Extraction.CSharp 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) { - 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) { - 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) @@ -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) { - 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) @@ -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) { - 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) @@ -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) { - 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) @@ -348,7 +348,7 @@ namespace Semmle.Extraction.CSharp 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) @@ -383,7 +383,7 @@ namespace Semmle.Extraction.CSharp 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) @@ -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) { - 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) @@ -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) { - 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) @@ -513,7 +513,7 @@ namespace Semmle.Extraction.CSharp 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) @@ -528,7 +528,7 @@ namespace Semmle.Extraction.CSharp 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) diff --git a/csharp/extractor/Semmle.Extraction.Tests/Layout.cs b/csharp/extractor/Semmle.Extraction.Tests/Layout.cs index 889d1152d16..303ea5bf71e 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Layout.cs +++ b/csharp/extractor/Semmle.Extraction.Tests/Layout.cs @@ -191,7 +191,7 @@ namespace Semmle.Extraction.Tests Content = content; } - public void EmitToTrapBuilder(TextWriter trapFile) + public void EmitTrap(TextWriter trapFile) { trapFile.Write(Content); } diff --git a/csharp/extractor/Semmle.Extraction/Context.cs b/csharp/extractor/Semmle.Extraction/Context.cs index 52c49e50883..fee1f97a159 100644 --- a/csharp/extractor/Semmle.Extraction/Context.cs +++ b/csharp/extractor/Semmle.Extraction/Context.cs @@ -332,7 +332,7 @@ namespace Semmle.Extraction Key = key; } - public void EmitToTrapBuilder(TextWriter trapFile) + public void EmitTrap(TextWriter trapFile) { trapFile.Write(".push "); Key.AppendTo(trapFile); @@ -342,7 +342,7 @@ namespace Semmle.Extraction class PopEmitter : ITrapEmitter { - public void EmitToTrapBuilder(TextWriter trapFile) + public void EmitTrap(TextWriter trapFile) { trapFile.WriteLine(".pop"); } diff --git a/csharp/extractor/Semmle.Extraction/TrapBuilder.cs b/csharp/extractor/Semmle.Extraction/TrapBuilder.cs deleted file mode 100644 index b17ca1f1e1d..00000000000 --- a/csharp/extractor/Semmle.Extraction/TrapBuilder.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; - -namespace Semmle.Extraction -{ - public static class TrapBuilderExtensions - { - /// - /// Appends a [comma] separated list to a trap builder. - /// - /// The type of the list. - /// The trap builder to append to. - /// The separator string (e.g. ",") - /// The list of items. - /// The original trap builder (fluent interface). - public static TextWriter AppendList(this TextWriter trapFile, string separator, IEnumerable items) where T:IEntity - { - return trapFile.BuildList(separator, items, (x, tb0) => { tb0.WriteSubId(x); }); - } - - /// - /// Builds a trap builder using a separator and an action for each item in the list. - /// - /// The type of the items. - /// The trap builder to append to. - /// The separator string (e.g. ",") - /// The list of items. - /// The action on each item. - /// The original trap builder (fluent interface). - public static TextWriter BuildList(this TextWriter trapFile, string separator, IEnumerable items, Action action) - { - bool first = true; - foreach (var item in items) - { - if (first) first = false; else trapFile.Write(separator); - action(item, trapFile); - } - return trapFile; - } - } -} diff --git a/csharp/extractor/Semmle.Extraction/TrapExtensions.cs b/csharp/extractor/Semmle.Extraction/TrapExtensions.cs index e2d257c8e1d..f3e672b13bb 100644 --- a/csharp/extractor/Semmle.Extraction/TrapExtensions.cs +++ b/csharp/extractor/Semmle.Extraction/TrapExtensions.cs @@ -1,4 +1,6 @@ -using System.IO; +using System; +using System.Collections.Generic; +using System.IO; namespace Semmle.Extraction { @@ -27,85 +29,57 @@ namespace Semmle.Extraction if (index++ > 0) trapFile.Write(separator); } - public struct FirstParam + + public static TextWriter WriteColumn(this TextWriter trapFile, int i) { - private readonly TextWriter Writer; - - 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(')'); - } + trapFile.Write(i); + return trapFile; } - 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) - { - Writer = trapFile; - } + public static TextWriter WriteColumn(this TextWriter trapFile, IEntity entity) + { + trapFile.WriteLabel(entity.Label.Value); + return trapFile; + } - private void WriteComma() - { - Writer.Write(", "); - } + public static TextWriter WriteColumn(this TextWriter trapFile, Label label) + { + trapFile.WriteLabel(label.Value); + return trapFile; + } - public NextParam Param(string str) - { - WriteComma(); - Writer.WriteTrapString(str); - return this; - } - public NextParam Param(float f) - { - WriteComma(); - Writer.WriteTrapFloat(f); - return this; - } + public static TextWriter WriteColumn(this TextWriter trapFile, float f) + { + trapFile.WriteTrapFloat(f); + return trapFile; + } - 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(); - Writer.Write(i); - return this; - } - - public NextParam Param(IEntity e) - { - WriteComma(); - Writer.WriteLabel(e.Label.Value); - return this; - } - - public void EndTuple() - { - Writer.WriteLine(')'); + case int i: + return trapFile.WriteColumn(i); + case float f: + return trapFile.WriteColumn(f); + case string s: + return trapFile.WriteColumn(s); + case IEntity e: + return trapFile.WriteColumn(e); + case Label l: + return trapFile.WriteColumn(l); + case Enum _: + return trapFile.WriteColumn((int)o); + default: + throw new ArgumentException(nameof(o)); } } @@ -185,66 +159,94 @@ namespace Semmle.Extraction 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('('); - 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) { - 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) + /// + /// Appends a [comma] separated list to a trap builder. + /// + /// The type of the list. + /// The trap builder to append to. + /// The separator string (e.g. ",") + /// The list of items. + /// The original trap builder (fluent interface). + public static TextWriter AppendList(this TextWriter trapFile, string separator, IEnumerable 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) + /// + /// Builds a trap builder using a separator and an action for each item in the list. + /// + /// The type of the items. + /// The trap builder to append to. + /// The separator string (e.g. ",") + /// The list of items. + /// The action on each item. + /// The original trap builder (fluent interface). + public static TextWriter BuildList(this TextWriter trapFile, string separator, IEnumerable items, Action action) { - trapFile.BeginTuple(name).Param(p1).Param(p2).Param(p3).EndTuple(); - } - - public static void WriteTuple(this TextWriter trapFile, string name, IEntity p1, IEntity p2, int p3) - { - trapFile.BeginTuple(name).Param(p1).Param(p2).Param(p3).EndTuple(); - } - - 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(); + bool first = true; + foreach (var item in items) + { + if (first) first = false; else trapFile.Write(separator); + action(item, trapFile); + } + return trapFile; } } } diff --git a/csharp/extractor/Semmle.Extraction/TrapWriter.cs b/csharp/extractor/Semmle.Extraction/TrapWriter.cs index 4e45f2eec6a..c32d7aae0b4 100644 --- a/csharp/extractor/Semmle.Extraction/TrapWriter.cs +++ b/csharp/extractor/Semmle.Extraction/TrapWriter.cs @@ -10,7 +10,7 @@ namespace Semmle.Extraction { public interface ITrapEmitter { - void EmitToTrapBuilder(TextWriter trapFile); + void EmitTrap(TextWriter trapFile); } public sealed class TrapWriter : IDisposable @@ -202,7 +202,7 @@ namespace Semmle.Extraction public void Emit(ITrapEmitter emitter) { - emitter.EmitToTrapBuilder(Writer); + emitter.EmitTrap(Writer); } /// diff --git a/csharp/extractor/Semmle.Extraction/Tuple.cs b/csharp/extractor/Semmle.Extraction/Tuple.cs index 54450684ad6..85d95d7e031 100644 --- a/csharp/extractor/Semmle.Extraction/Tuple.cs +++ b/csharp/extractor/Semmle.Extraction/Tuple.cs @@ -1,5 +1,4 @@ using System.IO; -using System.Linq; namespace Semmle.Extraction { @@ -17,139 +16,13 @@ namespace Semmle.Extraction 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)); - - /// - /// Truncates a string such that the output UTF8 does not exceed bytes. - /// - /// The input string to truncate. - /// The number of bytes available. - /// The truncated string. - 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("\"", "\"\""); - - /// - /// Output a string to the trap file, such that the encoded output does not exceed - /// bytes. - /// - /// The trapbuilder - /// The string to output. - /// The remaining bytes available to output. - private static void WriteTruncatedString(TextWriter trapFile, string s, ref int bytesRemaining) - { - WriteString(trapFile, TruncateString(s, ref bytesRemaining)); - } - /// /// Constructs a unique string for this tuple. /// - /// The trap builder used to store the result. - public void EmitToTrapBuilder(TextWriter trapFile) + /// The trap file to write to. + public void EmitTrap(TextWriter trapFile) { - trapFile.Write(Name); - 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(")"); + trapFile.WriteTuple(Name, Args); } public override string ToString() @@ -157,7 +30,7 @@ namespace Semmle.Extraction // Only implemented for debugging purposes using (var writer = new StringWriter()) { - EmitToTrapBuilder(writer); + EmitTrap(writer); return writer.ToString(); } } diff --git a/csharp/extractor/Semmle.Extraction/Tuples.cs b/csharp/extractor/Semmle.Extraction/Tuples.cs index d0c452f8ea6..3297b705f58 100644 --- a/csharp/extractor/Semmle.Extraction/Tuples.cs +++ b/csharp/extractor/Semmle.Extraction/Tuples.cs @@ -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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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) { - 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); } } }