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)
{
@@ -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);

View File

@@ -15,7 +15,7 @@ namespace Semmle.Extraction.CIL
public T Populate<T>(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
/// <returns>The string.</returns>
public string GetString(StringHandle h) => mdReader.GetString(h);
#region Namespaces
#region Namespaces
readonly CachedFunction<StringHandle, Namespace> 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<PDB.ISourceFile, PdbSourceFile> sourceFiles;
readonly CachedFunction<string, Folder> folders;
readonly CachedFunction<PDB.Location, PdbSourceLocation> sourceLocations;
@@ -225,7 +225,7 @@ namespace Semmle.Extraction.CIL
/// <returns>A source location entity.</returns>
public PdbSourceLocation CreateSourceLocation(PDB.Location loc) => sourceLocations[loc];
#endregion
#endregion
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)
{
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)

View File

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

View File

@@ -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");
}

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
{
@@ -27,85 +29,57 @@ namespace Semmle.Extraction
if (index++ > 0) trapFile.Write(separator);
}
public struct FirstParam
{
private readonly TextWriter Writer;
public FirstParam(TextWriter trapFile)
public static TextWriter WriteColumn(this TextWriter trapFile, int i)
{
Writer = trapFile;
trapFile.Write(i);
return trapFile;
}
public NextParam Param(IEntity entity)
public static TextWriter WriteColumn(this TextWriter trapFile, string s)
{
Writer.WriteLabel(entity.Label.Value);
return new NextParam(Writer);
trapFile.WriteTrapString(s);
return trapFile;
}
public NextParam Param(Label label)
public static TextWriter WriteColumn(this TextWriter trapFile, IEntity entity)
{
Writer.WriteLabel(label.Value);
return new NextParam(Writer);
trapFile.WriteLabel(entity.Label.Value);
return trapFile;
}
public void EndTuple()
public static TextWriter WriteColumn(this TextWriter trapFile, Label label)
{
Writer.WriteLine(')');
}
trapFile.WriteLabel(label.Value);
return trapFile;
}
public struct NextParam
{
private readonly TextWriter Writer;
public NextParam(TextWriter trapFile)
public static TextWriter WriteColumn(this TextWriter trapFile, float f)
{
Writer = trapFile;
trapFile.WriteTrapFloat(f);
return trapFile;
}
private void WriteComma()
{
Writer.Write(", ");
}
public NextParam Param(string str)
public static TextWriter WriteColumn(this TextWriter trapFile, object o)
{
WriteComma();
Writer.WriteTrapString(str);
return this;
}
public NextParam Param(float f)
switch (o)
{
WriteComma();
Writer.WriteTrapFloat(f);
return this;
}
public NextParam Param(Label label)
{
WriteComma();
Writer.WriteLabel(label.Value);
return this;
}
public NextParam Param(int i)
{
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)
/// <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)
{
if (first) first = false; else trapFile.Write(separator);
action(item, trapFile);
}
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();
return trapFile;
}
}
}

View File

@@ -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);
}
/// <summary>

View File

@@ -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));
/// <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>
/// Constructs a unique string for this tuple.
/// </summary>
/// <param name="trapFile">The trap builder used to store the result.</param>
public void EmitToTrapBuilder(TextWriter trapFile)
/// <param name="trapFile">The trap file to write to.</param>
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();
}
}

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)
{
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);
}
}
}