C#: Fix DB inconsistencies, and rework id generation.

This commit is contained in:
Calum Grant
2019-07-18 17:42:47 +01:00
parent 39a45ceefe
commit 61ab9431ab
25 changed files with 387 additions and 179 deletions

View File

@@ -920,7 +920,8 @@ namespace Semmle.Extraction.CIL.Entities
{
elementType.GetId(trapFile, inContext);
trapFile.Write('[');
trapFile.Write(rank);
for (int i = 1; i < rank; ++i)
trapFile.Write(',');
trapFile.Write(']');
}
@@ -1206,7 +1207,10 @@ namespace Semmle.Extraction.CIL.Entities
public void WriteId(TextWriter trapFile, GenericContext gc)
{
elementType.WriteId(trapFile, gc);
trapFile.Write("[]");
trapFile.Write('[');
for(int i=1; i<shape.Rank; ++i)
trapFile.Write(',');
trapFile.Write(']');
}
}

View File

@@ -258,6 +258,7 @@ namespace Semmle.Extraction.CSharp
var assemblyPath = r.FilePath;
var projectLayout = layout.LookupProjectOrDefault(assemblyPath);
using (var trapWriter = projectLayout.CreateTrapWriter(Logger, assemblyPath, true, options.TrapCompression))
{
var skipExtraction = options.Cache && File.Exists(trapWriter.TrapFile);
@@ -277,15 +278,14 @@ namespace Semmle.Extraction.CSharp
* then there is a small amount of duplicated work but the output should
* still be correct.
*/
// compilation.Clone() reduces memory footprint by allowing the symbols
// in c to be garbage collected.
Compilation c = compilation.Clone();
var assembly = c.GetAssemblyOrModuleSymbol(r) as IAssemblySymbol;
if (assembly != null)
{
var cx = extractor.CreateContext(c, trapWriter, new AssemblyScope(assembly, assemblyPath, false));
foreach (var module in assembly.Modules)

View File

@@ -21,7 +21,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
var type = Type.Create(Context, symbol.Type);
trapFile.events(this, symbol.GetName(), ContainingType, type.TypeRef, Create(Context, symbol.OriginalDefinition));

View File

@@ -30,7 +30,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateMetadataHandle(trapFile);
PopulateAttributes();
ContainingType.PopulateGenerics();
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
Field unboundFieldKey = Field.Create(Context, symbol.OriginalDefinition);
trapFile.fields(this, (symbol.IsConst ? 2 : 1), symbol.Name, ContainingType, Type.Type.TypeRef, unboundFieldKey);

View File

@@ -14,7 +14,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
var type = Type.Create(Context, symbol.Type);
trapFile.indexers(this, symbol.GetName(useMetadataName: true), ContainingType, type.TypeRef, OriginalDefinition);

View File

@@ -19,7 +19,7 @@ namespace Semmle.Extraction.CSharp.Entities
if (symbol.IsGenericMethod && !IsSourceDeclaration)
{
trapFile.Write('<');
trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta));
trapFile.BuildList(",", symbol.TypeArguments, (ta, tb0) => AddSignatureTypeToId(Context, tb0, symbol, ta, TypeNameContext.MethodName));
trapFile.Write('>');
}
trapFile.Write(";localfunction");

View File

@@ -31,7 +31,7 @@ namespace Semmle.Extraction.CSharp.Entities
{
if (symbol is ILocalSymbol local)
{
PopulateNullability(trapFile, local.NullableAnnotation);
PopulateNullability(trapFile, local.GetAnnotatedType());
if (local.IsRef)
trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref);
}

View File

@@ -108,6 +108,7 @@ namespace Semmle.Extraction.CSharp.Entities
/// </summary>
protected static void BuildMethodId(Method m, TextWriter trapFile)
{
// AddSignatureTypeToId(m.Context, trapFile, m.symbol, m.ContainingType.symbol, false);
trapFile.WriteSubId(m.ContainingType);
AddExplicitInterfaceQualifierToId(m.Context, trapFile, m.symbol.ExplicitInterfaceImplementations);
@@ -129,7 +130,7 @@ namespace Semmle.Extraction.CSharp.Entities
// Type arguments with different nullability can result in
// a constructed method with different nullability of its parameters and return type,
// so we need to create a distinct database entity for it.
trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol); trapFile.Write((int)ta.Nullability); });
trapFile.BuildList(",", m.symbol.GetAnnotatedTypeArguments(), (ta, tb0) => { AddSignatureTypeToId(m.Context, tb0, m.symbol, ta.Symbol, TypeNameContext.MethodName); trapFile.Write((int)ta.Nullability); });
trapFile.Write('>');
}
}
@@ -199,12 +200,12 @@ namespace Semmle.Extraction.CSharp.Entities
/// to make the reference to <code>#3</code> in the label definition <code>#4</code> for
/// <code>T</code> valid.
/// </summary>
protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type)
protected static void AddSignatureTypeToId(Context cx, TextWriter trapFile, IMethodSymbol method, ITypeSymbol type, TypeNameContext assemblyPrefix)
{
if (type.ContainsTypeParameters(cx, method))
type.BuildTypeId(cx, trapFile, (cx0, tb0, type0) => AddSignatureTypeToId(cx, tb0, method, type0));
type.BuildTypeId(cx, trapFile, (cx0, tb0, type0, _) => AddSignatureTypeToId(cx, tb0, method, type0, assemblyPrefix), assemblyPrefix, method);
else
trapFile.WriteSubId(Type.Create(cx, type));
trapFile.WriteSubId(Type.Create(cx, type).TypeRef);
}
protected static void AddParametersToId(Context cx, TextWriter trapFile, IMethodSymbol method)
@@ -215,13 +216,13 @@ namespace Semmle.Extraction.CSharp.Entities
if (method.MethodKind == MethodKind.ReducedExtension)
{
trapFile.WriteSeparator(",", ref index);
AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType);
AddSignatureTypeToId(cx, trapFile, method, method.ReceiverType, TypeNameContext.MethodParam);
}
foreach (var param in method.Parameters)
{
trapFile.WriteSeparator(",", ref index);
AddSignatureTypeToId(cx, trapFile, method, param.Type);
AddSignatureTypeToId(cx, trapFile, method, param.Type, TypeNameContext.MethodParam);
switch (param.RefKind)
{
case RefKind.Out:
@@ -345,11 +346,10 @@ namespace Semmle.Extraction.CSharp.Entities
foreach (var tp in symbol.GetAnnotatedTypeArguments())
{
trapFile.type_arguments(Type.Create(Context, tp.Symbol), child, this);
var ta = tp.Nullability.GetTypeAnnotation();
if (ta != Kinds.TypeAnnotation.None)
trapFile.type_argument_annotation(this, child, ta);
child++;
}
trapFile.type_nullability(this, NullabilityEntity.Create(Context, new Nullability(symbol)));
}
else
{
@@ -380,7 +380,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateMethodBody(trapFile);
PopulateGenerics(trapFile);
PopulateMetadataHandle(trapFile);
PopulateNullability(trapFile, symbol.ReturnNullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedReturnType());
}
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.PushesLabel;

View File

@@ -86,7 +86,8 @@ namespace Semmle.Extraction.CSharp.Entities
trapFile.Write(";parameter");
}
public override bool NeedsPopulation => true;
// If we don't have the type of the parameter, do not populate it.
public override bool NeedsPopulation => symbol.Type.TypeKind != TypeKind.Error;
string Name
{
@@ -103,7 +104,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate(TextWriter trapFile)
{
PopulateAttributes();
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
PopulateRefKind(trapFile, symbol.RefKind);
if (symbol.Name != Original.symbol.Name)

View File

@@ -15,6 +15,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
// trapFile.WriteSubId(ContainingType.TypeRef);
trapFile.WriteSubId(ContainingType);
trapFile.Write('.');
Method.AddExplicitInterfaceQualifierToId(Context, trapFile, symbol.ExplicitInterfaceImplementations);
@@ -28,7 +29,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateAttributes();
PopulateModifiers(trapFile);
BindComments();
PopulateNullability(trapFile, symbol.NullableAnnotation);
PopulateNullability(trapFile, symbol.GetAnnotatedType());
PopulateRefKind(trapFile, symbol.RefKind);
var type = Type.Create(Context, symbol.Type);

View File

@@ -28,11 +28,14 @@ namespace Semmle.Extraction.CSharp.Entities
Attribute.ExtractAttributes(Context, symbol, this);
}
protected void PopulateNullability(TextWriter trapFile, NullableAnnotation annotation)
protected void PopulateNullability(TextWriter trapFile, AnnotatedTypeSymbol type)
{
var ta = annotation.GetTypeAnnotation();
if (ta != Kinds.TypeAnnotation.None)
trapFile.type_annotation(this, ta);
var ta = type.Nullability.GetTypeAnnotation();
var n = NullabilityEntity.Create(Context, Nullability.Create(type));
if (ta != Kinds.TypeAnnotation.None || !type.HasConsistentNullability())
{
trapFile.type_nullability(this, n);
}
}
protected void PopulateRefKind(TextWriter trapFile, RefKind kind)

View File

@@ -27,13 +27,11 @@ namespace Semmle.Extraction.CSharp.Entities
{
trapFile.array_element_type(this, Dimension, Rank, element.Type.TypeRef);
PopulateType(trapFile);
PopulateNullability(trapFile, symbol.ElementNullableAnnotation);
}
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(element.Type);
trapFile.Write((int)symbol.ElementNullableAnnotation);
symbol.BuildArraySuffix(trapFile);
trapFile.Write(";type");
}

View File

@@ -57,9 +57,6 @@ namespace Semmle.Extraction.CSharp.Entities
for (int i = 0; i < symbol.TypeArguments.Length; ++i)
{
var ta = symbol.TypeArgumentsNullableAnnotations[i].GetTypeAnnotation();
if (ta != Kinds.TypeAnnotation.None)
trapFile.type_argument_annotation(this, i, ta);
trapFile.type_arguments(TypeArguments[i].TypeRef, i, this);
}
}
@@ -114,7 +111,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeNameContext.TypeName, symbol);
trapFile.Write(";type");
}
@@ -154,33 +151,40 @@ namespace Semmle.Extraction.CSharp.Entities
public NamedType Create(Context cx, INamedTypeSymbol init) => new NamedType(cx, init);
}
public override Type TypeRef => NamedTypeRef.Create(Context, symbol);
public override Type TypeRef => NamedTypeRef.Create(Context, this, symbol);
}
class NamedTypeRef : Type<INamedTypeSymbol>
class NamedTypeRef : Type<ITypeSymbol>
{
readonly Type referencedType;
public NamedTypeRef(Context cx, INamedTypeSymbol symbol) : base(cx, symbol)
public NamedTypeRef(Context cx, Type type, ITypeSymbol symbol) : base(cx, symbol)
{
referencedType = Type.Create(cx, symbol);
referencedType = type;
}
public static NamedTypeRef Create(Context cx, INamedTypeSymbol type) => NamedTypeRefFactory.Instance.CreateEntity2(cx, type);
public static NamedTypeRef Create(Context cx, Type referencedType, ITypeSymbol type) =>
NamedTypeRefFactory.Instance.CreateEntity2(cx, (referencedType, type));
class NamedTypeRefFactory : ICachedEntityFactory<INamedTypeSymbol, NamedTypeRef>
class NamedTypeRefFactory : ICachedEntityFactory<(Type, ITypeSymbol), NamedTypeRef>
{
public static readonly NamedTypeRefFactory Instance = new NamedTypeRefFactory();
public NamedTypeRef Create(Context cx, INamedTypeSymbol init) => new NamedTypeRef(cx, init);
public NamedTypeRef Create(Context cx, (Type, ITypeSymbol) init) => new NamedTypeRef(cx, init.Item1, init.Item2);
}
public override bool NeedsPopulation => true;
public override void WriteId(TextWriter trapFile)
{
trapFile.WriteSubId(referencedType);
trapFile.Write(";typeRef");
void ExpandType(Context cx0, TextWriter tb0, ITypeSymbol sub, ISymbol gc)
{
sub.BuildTypeId(cx0, tb0, ExpandType, TypeNameContext.TypeRef, gc);
}
// Prefix anonymous types because they shouldn't be visible outside of the current assembly.
symbol.BuildTypeId(Context, trapFile, ExpandType, TypeNameContext.TypeRef, symbol);
trapFile.Write(";typeref");
}
public override void Populate(TextWriter trapFile)

View File

@@ -32,7 +32,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub) => tb0.WriteSubId(Create(cx0, sub)));
symbol.BuildTypeId(Context, trapFile, (cx0, tb0, sub, _) => tb0.WriteSubId(Create(cx0, sub)), TypeNameContext.TypeName, symbol);
trapFile.Write(";tuple");
}
@@ -42,7 +42,7 @@ namespace Semmle.Extraction.CSharp.Entities
PopulateGenerics();
var underlyingType = NamedType.Create(Context, symbol.TupleUnderlyingType);
trapFile.tuple_underlying_type(this, underlyingType);
trapFile.tuple_underlying_type(this, underlyingType.TypeRef);
int index = 0;
foreach (var element in TupleElements)

View File

@@ -95,6 +95,7 @@ namespace Semmle.Extraction.CSharp.Entities
var baseTypes = new List<Type>();
if (symbol.BaseType != null)
{
// !! Do not extend "object" if the base type is missing :-(
Type baseKey = Create(Context, symbol.BaseType);
trapFile.extend(this, baseKey.TypeRef);
if (symbol.TypeKind != TypeKind.Struct)
@@ -268,6 +269,10 @@ namespace Semmle.Extraction.CSharp.Entities
public static Type Create(Context cx, ITypeSymbol type)
{
type = type.DisambiguateType();
if (type is INamedTypeSymbol nt && nt.IsEvilTwin())
type = nt.ConstructedFrom;
const bool errorTypeIsNull = false;
return type == null || (errorTypeIsNull && type.TypeKind == TypeKind.Error) ?
NullType.Create(cx).Type : (Type)cx.CreateEntity(type);

View File

@@ -51,7 +51,7 @@ namespace Semmle.Extraction.CSharp.Entities
public override void WriteId(TextWriter trapFile)
{
AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType); // Needed for op_explicit(), which differs only by return type.
AddSignatureTypeToId(Context, trapFile, symbol, symbol.ReturnType, TypeNameContext.MethodParam); // Needed for op_explicit(), which differs only by return type.
trapFile.Write(' ');
BuildMethodId(this, trapFile);
}

View File

@@ -120,7 +120,8 @@ namespace Semmle.Extraction.CSharp
var syntaxTrees = new List<SyntaxTree>();
var syntaxTreeTasks = ReadSyntaxTrees(
compilerArguments.SourceFiles.
Select(src => canonicalPathCache.GetCanonicalPath(src.Path)),
Select(src => canonicalPathCache.GetCanonicalPath(src.Path)).
Where(f => !f.EndsWith(".dll")),
analyser,
compilerArguments.ParseOptions,
compilerArguments.Encoding,

View File

@@ -4,6 +4,8 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Semmle.Extraction.CSharp
{
@@ -25,6 +27,16 @@ namespace Semmle.Extraction.CSharp
}
}
public enum TypeNameContext
{
TypeName,
TypeRef,
AnonymousType,
MethodName,
MethodParam
}
static class SymbolExtensions
{
/// <summary>
@@ -131,17 +143,36 @@ namespace Semmle.Extraction.CSharp
/// <param name="cx">The extraction context.</param>
/// <param name="trapFile">The trap builder used to store the result.</param>
/// <param name="subTermAction">The action to apply to syntactic sub terms of this type.</param>
public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol> subTermAction)
public static void BuildTypeId(this ITypeSymbol type, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol, ISymbol> subTermAction, TypeNameContext assemblyPrefix, ISymbol genericContext)
{
if (type.SpecialType != SpecialType.None)
switch(type.SpecialType)
{
/*
* Use the keyword ("int" etc) for the built-in types.
* This makes the IDs shorter and means that all built-in types map to
* the same entities (even when using multiple versions of mscorlib).
*/
trapFile.Write(type.ToDisplayString());
return;
case SpecialType.System_Object:
case SpecialType.System_Void:
case SpecialType.System_Boolean:
case SpecialType.System_Char:
case SpecialType.System_SByte:
case SpecialType.System_Byte:
case SpecialType.System_Int16:
case SpecialType.System_UInt16:
case SpecialType.System_Int32:
case SpecialType.System_UInt32:
case SpecialType.System_Int64:
case SpecialType.System_UInt64:
case SpecialType.System_Decimal:
case SpecialType.System_Single:
case SpecialType.System_Double:
case SpecialType.System_String:
case SpecialType.System_IntPtr:
case SpecialType.System_UIntPtr:
/*
* Use the keyword ("int" etc) for the built-in types.
* This makes the IDs shorter and means that all built-in types map to
* the same entities (even when using multiple versions of mscorlib).
*/
trapFile.Write(type.ToDisplayString());
return;
}
using (cx.StackGuard)
@@ -150,7 +181,9 @@ namespace Semmle.Extraction.CSharp
{
case TypeKind.Array:
var array = (IArrayTypeSymbol)type;
subTermAction(cx, trapFile, array.ElementType);
subTermAction(cx, trapFile, array.ElementType, genericContext);
if(assemblyPrefix == TypeNameContext.TypeName)
trapFile.Write((int)array.ElementNullableAnnotation);
array.BuildArraySuffix(trapFile);
return;
case TypeKind.Class:
@@ -160,16 +193,29 @@ namespace Semmle.Extraction.CSharp
case TypeKind.Delegate:
case TypeKind.Error:
var named = (INamedTypeSymbol)type;
named.BuildNamedTypeId(cx, trapFile, subTermAction);
named.BuildNamedTypeId(cx, trapFile, subTermAction, assemblyPrefix, genericContext);
return;
case TypeKind.Pointer:
var ptr = (IPointerTypeSymbol)type;
subTermAction(cx, trapFile, ptr.PointedAtType);
trapFile.Write('*');
subTermAction(cx, trapFile, ptr.PointedAtType, genericContext);
trapFile.Write("*");
return;
case TypeKind.TypeParameter:
var tp = (ITypeParameterSymbol)type;
trapFile.Write(tp.Name);
switch(tp.TypeParameterKind)
{
case TypeParameterKind.Method:
if(!Equals(genericContext, tp.DeclaringMethod))
trapFile.WriteSubId(Method.Create(cx, tp.DeclaringMethod));
trapFile.Write("!!");
break;
case TypeParameterKind.Type:
if(!Equals(genericContext,tp.DeclaringType))
subTermAction(cx, trapFile, tp.DeclaringType, genericContext);
trapFile.Write("!");
break;
}
trapFile.Write(tp.Ordinal);
return;
case TypeKind.Dynamic:
trapFile.Write("dynamic");
@@ -193,8 +239,34 @@ namespace Semmle.Extraction.CSharp
trapFile.Write(']');
}
static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol> subTermAction)
private static void BuildAssembly(IAssemblySymbol asm, TextWriter trapFile, bool extraPrecise = false)
{
var assembly = asm.Identity;
trapFile.Write(assembly.Name);
trapFile.Write('_');
trapFile.Write(assembly.Version.Major);
trapFile.Write('.');
trapFile.Write(assembly.Version.Minor);
trapFile.Write('.');
trapFile.Write(assembly.Version.Build);
if (extraPrecise)
{
trapFile.Write('.');
trapFile.Write(assembly.Version.Revision);
}
trapFile.Write("::");
}
public static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol, ISymbol> subTermAction, TypeNameContext assemblyPrefix, ISymbol genericContext)
{
bool prefixAssembly = false;
if (named.IsAnonymous()) prefixAssembly = true;
else if(assemblyPrefix == TypeNameContext.TypeName && cx.Extractor.Identifiers != IdentifierMode.Imprecise) prefixAssembly = true;
if (named.ContainingAssembly is null) prefixAssembly = false;
if (prefixAssembly)
BuildAssembly(named.ContainingAssembly, trapFile);
if (named.IsTupleType)
{
trapFile.Write('(');
@@ -203,7 +275,7 @@ namespace Semmle.Extraction.CSharp
{
trapFile.Write(f.Name);
trapFile.Write(":");
subTermAction(cx, tb0, f.Type);
subTermAction(cx, tb0, f.Type, genericContext);
}
);
trapFile.Write(")");
@@ -212,16 +284,16 @@ namespace Semmle.Extraction.CSharp
if (named.ContainingType != null)
{
subTermAction(cx, trapFile, named.ContainingType);
subTermAction(cx, trapFile, named.ContainingType, genericContext);
trapFile.Write('.');
}
else if (named.ContainingNamespace != null)
else if (named.ContainingNamespace != null && !named.IsConstructedGeneric())
{
named.ContainingNamespace.BuildNamespace(cx, trapFile);
}
if (named.IsAnonymousType)
named.BuildAnonymousName(cx, trapFile, subTermAction, true);
named.BuildAnonymousName(cx, trapFile, subTermAction, true, genericContext);
else if (named.TypeParameters.IsEmpty)
trapFile.Write(named.Name);
else if (IsReallyUnbound(named))
@@ -232,7 +304,7 @@ namespace Semmle.Extraction.CSharp
}
else
{
subTermAction(cx, trapFile, named.ConstructedFrom);
subTermAction(cx, trapFile, named.ConstructedFrom, genericContext);
trapFile.Write('<');
// Encode the nullability of the type arguments in the label.
// Type arguments with different nullability can result in
@@ -245,40 +317,20 @@ namespace Semmle.Extraction.CSharp
static void BuildNamespace(this INamespaceSymbol ns, Context cx, TextWriter trapFile)
{
// Only include the assembly information in each type ID
// for normal extractions. This is because standalone extractions
// lack assembly information or may be ambiguous.
bool prependAssemblyToTypeId = !cx.Extractor.Standalone && ns.ContainingAssembly != null;
if (prependAssemblyToTypeId)
{
// Note that we exclude the revision number as this has
// been observed to be unstable.
var assembly = ns.ContainingAssembly.Identity;
trapFile.Write(assembly.Name);
trapFile.Write('_');
trapFile.Write(assembly.Version.Major);
trapFile.Write('.');
trapFile.Write(assembly.Version.Minor);
trapFile.Write('.');
trapFile.Write(assembly.Version.Build);
trapFile.Write("::");
}
trapFile.WriteSubId(Namespace.Create(cx, ns));
trapFile.Write('.');
}
static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol> subTermAction, bool includeParamName)
static void BuildAnonymousName(this ITypeSymbol type, Context cx, TextWriter trapFile, Action<Context, TextWriter, ITypeSymbol, ISymbol> subTermAction, bool includeParamName, ISymbol genericContext)
{
var buildParam = includeParamName
? (prop, tb0) =>
{
tb0.Write(prop.Name);
trapFile.Write(' ');
subTermAction(cx, tb0, prop.Type);
tb0.Write(' ');
subTermAction(cx, tb0, prop.Type, genericContext);
}
: (Action<IPropertySymbol, TextWriter>)((prop, tb0) => subTermAction(cx, tb0, prop.Type));
: (Action<IPropertySymbol, TextWriter>)((prop, tb0) => subTermAction(cx, tb0, prop.Type, genericContext));
int memberCount = type.GetMembers().OfType<IPropertySymbol>().Count();
int hackTypeNumber = memberCount == 1 ? 1 : 0;
trapFile.Write("<>__AnonType");
@@ -350,15 +402,16 @@ namespace Semmle.Extraction.CSharp
if (namedType.IsAnonymousType)
{
namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub) => sub.BuildDisplayName(cx0, tb0), false);
namedType.BuildAnonymousName(cx, trapFile, (cx0, tb0, sub, _) => sub.BuildDisplayName(cx0, tb0), false, namedType);
}
trapFile.Write(namedType.Name);
if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any())
if (namedType.IsGenericType && /* namedType.TypeKind != TypeKind.Error && */ namedType.TypeArguments.Any())
{
trapFile.Write('<');
trapFile.BuildList(",", namedType.TypeArguments, (p, tb0) =>
{
// tb0.Write(p.Name);
if (IsReallyBound(namedType))
p.BuildDisplayName(cx, tb0);
});
@@ -490,12 +543,6 @@ namespace Semmle.Extraction.CSharp
return new AnnotatedTypeSymbol(info.Type.DisambiguateType(), info.Nullability.Annotation);
}
/// <summary>
/// Gets the annotated type of an ILocalSymbol.
/// This has not yet been exposed on the public API.
/// </summary>
public static AnnotatedTypeSymbol GetAnnotatedType(this ILocalSymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation);
/// <summary>
/// Gets the annotated type of an IPropertySymbol.
/// This has not yet been exposed on the public API.

View File

@@ -381,6 +381,16 @@ namespace Semmle.Extraction.CSharp
trapFile.WriteTuple("nullable_underlying_type", nullableType, underlyingType);
}
internal static void nullability(this TextWriter trapFile, NullabilityEntity nullability, int annotation)
{
trapFile.WriteTuple("nullability", nullability, annotation);
}
internal static void nullability_member(this TextWriter trapFile, NullabilityEntity nullability, int index, NullabilityEntity child)
{
trapFile.WriteTuple(nameof(nullability_member), nullability, index, child);
}
internal static void numlines(this TextWriter trapFile, IEntity label, LineCounts lineCounts)
{
trapFile.WriteTuple("numlines", label, lineCounts.Total, lineCounts.Code, lineCounts.Comment);
@@ -471,7 +481,7 @@ namespace Semmle.Extraction.CSharp
trapFile.WriteTuple("tuple_element", type, index, field);
}
internal static void tuple_underlying_type(this TextWriter trapFile, TupleType type, NamedType underlying)
internal static void tuple_underlying_type(this TextWriter trapFile, TupleType type, Type underlying)
{
trapFile.WriteTuple("tuple_underlying_type", type, underlying);
}
@@ -481,9 +491,14 @@ namespace Semmle.Extraction.CSharp
trapFile.WriteTuple("type_annotation", element, (int)annotation);
}
internal static void type_argument_annotation(this TextWriter trapFile, IEntity element, int index, Kinds.TypeAnnotation annotation)
internal static void type_arguments(this TextWriter trapFile, Type arg, int n, IEntity typeOrMethod)
{
trapFile.WriteTuple("type_argument_annotation", element, index, (int)annotation);
trapFile.WriteTuple("type_arguments", arg, n, typeOrMethod);
}
internal static void type_location(this TextWriter trapFile, Type type, Location location)
{
trapFile.WriteTuple("type_location", type, location);
}
internal static void type_mention(this TextWriter trapFile, TypeMention ta, Type type, IEntity parent)
@@ -496,14 +511,9 @@ namespace Semmle.Extraction.CSharp
trapFile.WriteTuple("type_mention_location", ta, loc);
}
internal static void type_arguments(this TextWriter trapFile, Type arg, int n, IEntity typeOrMethod)
internal static void type_nullability(this TextWriter trapFile, IEntity element, NullabilityEntity nullability)
{
trapFile.WriteTuple("type_arguments", arg, n, typeOrMethod);
}
internal static void type_location(this TextWriter trapFile, Type type, Location location)
{
trapFile.WriteTuple("type_location", type, location);
trapFile.WriteTuple("type_nullability", element, nullability);
}
internal static void type_parameter_constraints(this TextWriter trapFile, TypeParameterConstraints constraints, TypeParameter typeParam)

View File

@@ -87,6 +87,16 @@ namespace Semmle.Extraction
/// <param name="scope">The extraction scope (what to include in this trap file).</param>
/// <returns></returns>
Context CreateContext(Compilation c, TrapWriter trapWriter, IExtractionScope scope);
IdentifierMode Identifiers { get; }
}
public enum IdentifierMode
{
Imprecise,
Flexible,
Precise,
ExtraPrecise
}
/// <summary>
@@ -112,6 +122,7 @@ namespace Semmle.Extraction
public Extractor(bool standalone, string outputPath, ILogger logger)
{
Standalone = standalone;
if (Standalone) Identifiers = IdentifierMode.Imprecise;
OutputPath = outputPath;
Logger = logger;
}
@@ -197,5 +208,7 @@ namespace Semmle.Extraction
public ILogger Logger { get; private set; }
public static string Version => $"{ThisAssembly.Git.BaseTag} ({ThisAssembly.Git.Sha})";
public IdentifierMode Identifiers { get; } = IdentifierMode.Imprecise;
}
}