mirror of
https://github.com/github/codeql.git
synced 2026-04-29 10:45:15 +02:00
C#: Fix DB inconsistencies, and rework id generation.
This commit is contained in:
@@ -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(']');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user