mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
C#: Extract function pointers
This commit is contained in:
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Microsoft.CodeAnalysis.CSharp;
|
||||
using Semmle.Extraction.Kinds;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
@@ -66,7 +67,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Delegate call; `d()`
|
||||
// Delegate or function pointer call; `d()`
|
||||
Create(cx, Syntax.Expression, this, child++);
|
||||
break;
|
||||
}
|
||||
@@ -84,7 +85,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
if (!isDynamicCall && !IsDelegateCall(info))
|
||||
if (!isDynamicCall && !IsDelegateLikeCall(info))
|
||||
cx.ModelError(Syntax, "Unable to resolve target for call. (Compilation error?)");
|
||||
return;
|
||||
}
|
||||
@@ -98,7 +99,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
// Either the qualifier (Expression) is dynamic,
|
||||
// or one of the arguments is dynamic.
|
||||
var node = (InvocationExpressionSyntax)info.Node;
|
||||
return !IsDelegateCall(info) &&
|
||||
return !IsDelegateLikeCall(info) &&
|
||||
(IsDynamic(info.Context, node.Expression) || node.ArgumentList.Arguments.Any(arg => IsDynamic(info.Context, arg.Expression)));
|
||||
}
|
||||
|
||||
@@ -133,12 +134,22 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsDelegateCall(ExpressionNodeInfo info)
|
||||
private static bool IsDelegateLikeCall(ExpressionNodeInfo info)
|
||||
{
|
||||
return IsDelegateLikeCall(info, IsDelegateLikeCall);
|
||||
}
|
||||
|
||||
private static bool IsDelegateInvokeCall(ExpressionNodeInfo info)
|
||||
{
|
||||
return IsDelegateLikeCall(info, IsDelegateInvoke);
|
||||
}
|
||||
|
||||
private static bool IsDelegateLikeCall(ExpressionNodeInfo info, Func<ISymbol, bool> check)
|
||||
{
|
||||
var si = info.SymbolInfo;
|
||||
|
||||
if (si.CandidateReason == CandidateReason.OverloadResolutionFailure &&
|
||||
si.CandidateSymbols.OfType<IMethodSymbol>().All(s => s.MethodKind == MethodKind.DelegateInvoke))
|
||||
si.CandidateSymbols.All(check))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -153,9 +164,26 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
return true;
|
||||
}
|
||||
|
||||
return si.Symbol != null &&
|
||||
si.Symbol.Kind == SymbolKind.Method &&
|
||||
((IMethodSymbol)si.Symbol).MethodKind == MethodKind.DelegateInvoke;
|
||||
return check(si.Symbol);
|
||||
}
|
||||
|
||||
private static bool IsDelegateLikeCall(ISymbol symbol)
|
||||
{
|
||||
return IsFunctionPointer(symbol) ||
|
||||
IsDelegateInvoke(symbol);
|
||||
}
|
||||
|
||||
private static bool IsFunctionPointer(ISymbol symbol)
|
||||
{
|
||||
return symbol != null &&
|
||||
symbol.Kind == SymbolKind.FunctionPointerType;
|
||||
}
|
||||
|
||||
private static bool IsDelegateInvoke(ISymbol symbol)
|
||||
{
|
||||
return symbol != null &&
|
||||
symbol.Kind == SymbolKind.Method &&
|
||||
((IMethodSymbol)symbol).MethodKind == MethodKind.DelegateInvoke;
|
||||
}
|
||||
|
||||
private static bool IsLocalFunctionInvocation(ExpressionNodeInfo info)
|
||||
@@ -168,8 +196,10 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
return IsNameof((InvocationExpressionSyntax)info.Node)
|
||||
? ExprKind.NAMEOF
|
||||
: IsDelegateCall(info)
|
||||
? ExprKind.DELEGATE_INVOCATION
|
||||
: IsDelegateLikeCall(info)
|
||||
? IsDelegateInvokeCall(info)
|
||||
? ExprKind.DELEGATE_INVOCATION
|
||||
: ExprKind.FUNCTION_POINTER_INVOCATION
|
||||
: IsLocalFunctionInvocation(info)
|
||||
? ExprKind.LOCAL_FUNCTION_INVOCATION
|
||||
: ExprKind.METHOD_INVOCATION;
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
var originalDefinition = IsSourceDeclaration ? this : Create(Context, symbol.OriginalDefinition);
|
||||
var returnType = Type.Create(Context, symbol.ReturnType);
|
||||
trapFile.local_functions(this, symbol.Name, returnType, originalDefinition);
|
||||
ExtractRefReturn(trapFile);
|
||||
ExtractRefReturn(trapFile, symbol, this);
|
||||
}
|
||||
|
||||
public override TrapStackBehaviour TrapStackBehaviour => TrapStackBehaviour.NeedsLabel;
|
||||
|
||||
@@ -40,7 +40,9 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
foreach (var p in parameters.Zip(originalParameters, (paramSymbol, originalParam) => new { paramSymbol, originalParam }))
|
||||
{
|
||||
var original = SymbolEqualityComparer.Default.Equals(p.paramSymbol, p.originalParam) ? null : Parameter.Create(Context, p.originalParam, originalMethod);
|
||||
var original = SymbolEqualityComparer.Default.Equals(p.paramSymbol, p.originalParam)
|
||||
? null
|
||||
: Parameter.Create(Context, p.originalParam, originalMethod);
|
||||
Parameter.Create(Context, p.paramSymbol, this, original);
|
||||
}
|
||||
|
||||
@@ -110,7 +112,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
/// <summary>
|
||||
/// Factored out to share logic between `Method` and `UserOperator`.
|
||||
/// </summary>
|
||||
protected static void BuildMethodId(Method m, TextWriter trapFile)
|
||||
private static void BuildMethodId(Method m, TextWriter trapFile)
|
||||
{
|
||||
m.symbol.ReturnType.BuildOrWriteId(m.Context, trapFile, m.symbol);
|
||||
trapFile.Write(" ");
|
||||
@@ -324,12 +326,12 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
protected void ExtractRefReturn(TextWriter trapFile)
|
||||
public static void ExtractRefReturn(TextWriter trapFile, IMethodSymbol method, IEntity element)
|
||||
{
|
||||
if (symbol.ReturnsByRef)
|
||||
trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref);
|
||||
if (symbol.ReturnsByRefReadonly)
|
||||
trapFile.type_annotation(this, Kinds.TypeAnnotation.ReadonlyRef);
|
||||
if (method.ReturnsByRef)
|
||||
trapFile.type_annotation(element, Kinds.TypeAnnotation.Ref);
|
||||
if (method.ReturnsByRefReadonly)
|
||||
trapFile.type_annotation(element, Kinds.TypeAnnotation.ReadonlyRef);
|
||||
}
|
||||
|
||||
protected void PopulateMethod(TextWriter trapFile)
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
|
||||
PopulateGenerics(trapFile);
|
||||
Overrides(trapFile);
|
||||
ExtractRefReturn(trapFile);
|
||||
ExtractRefReturn(trapFile, symbol, this);
|
||||
ExtractCompilerGenerated(trapFile);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Microsoft.CodeAnalysis;
|
||||
|
||||
namespace Semmle.Extraction.CSharp.Entities
|
||||
{
|
||||
internal class FunctionPointerType : Type<IFunctionPointerTypeSymbol>
|
||||
{
|
||||
private FunctionPointerType(Context cx, IFunctionPointerTypeSymbol init)
|
||||
: base(cx, init)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteId(TextWriter trapFile)
|
||||
{
|
||||
symbol.BuildTypeId(Context, trapFile, symbol);
|
||||
trapFile.Write(";functionpointertype");
|
||||
}
|
||||
|
||||
public override bool NeedsPopulation => true;
|
||||
|
||||
public override void Populate(TextWriter trapFile)
|
||||
{
|
||||
var unmanagedCallingConventionTypes = symbol.Signature.UnmanagedCallingConventionTypes.Select(nt => Create(Context, nt)).ToArray();
|
||||
|
||||
trapFile.function_pointer_calling_conventions(this, (int)symbol.Signature.CallingConvention);
|
||||
for (var i = 0; i < unmanagedCallingConventionTypes.Length; i++)
|
||||
{
|
||||
trapFile.has_unmanaged_calling_conventions(this, i, unmanagedCallingConventionTypes[i].TypeRef);
|
||||
}
|
||||
|
||||
PopulateType(trapFile);
|
||||
}
|
||||
|
||||
public static FunctionPointerType Create(Context cx, IFunctionPointerTypeSymbol symbol) => FunctionPointerTypeFactory.Instance.CreateEntityFromSymbol(cx, symbol);
|
||||
|
||||
private class FunctionPointerTypeFactory : ICachedEntityFactory<IFunctionPointerTypeSymbol, FunctionPointerType>
|
||||
{
|
||||
public static FunctionPointerTypeFactory Instance { get; } = new FunctionPointerTypeFactory();
|
||||
|
||||
public FunctionPointerType Create(Context cx, IFunctionPointerTypeSymbol init) => new FunctionPointerType(cx, init);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||
using Semmle.Util;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -57,6 +58,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
case TypeKind.Enum: return Kinds.TypeKind.ENUM;
|
||||
case TypeKind.Delegate: return Kinds.TypeKind.DELEGATE;
|
||||
case TypeKind.Pointer: return Kinds.TypeKind.POINTER;
|
||||
case TypeKind.FunctionPointer: return Kinds.TypeKind.FUNCTION_POINTER;
|
||||
case TypeKind.Error: return Kinds.TypeKind.UNKNOWN;
|
||||
default:
|
||||
cx.ModelError(t, $"Unhandled type kind '{t.TypeKind}'");
|
||||
@@ -131,23 +133,14 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
// This is a delegate.
|
||||
// The method "Invoke" has the return type.
|
||||
var invokeMethod = ((INamedTypeSymbol)symbol).DelegateInvokeMethod;
|
||||
ExtractParametersForDelegateLikeType(trapFile, invokeMethod,
|
||||
t => trapFile.delegate_return_type(this, t));
|
||||
}
|
||||
|
||||
// Copy the parameters from the "Invoke" method to the delegate type
|
||||
for (var i = 0; i < invokeMethod.Parameters.Length; ++i)
|
||||
{
|
||||
var param = invokeMethod.Parameters[i];
|
||||
var originalParam = invokeMethod.OriginalDefinition.Parameters[i];
|
||||
var originalParamEntity = SymbolEqualityComparer.Default.Equals(param, originalParam) ? null :
|
||||
DelegateTypeParameter.Create(Context, originalParam, Create(Context, ((INamedTypeSymbol)symbol).OriginalDefinition));
|
||||
DelegateTypeParameter.Create(Context, param, this, originalParamEntity);
|
||||
}
|
||||
|
||||
var returnKey = Create(Context, invokeMethod.ReturnType);
|
||||
trapFile.delegate_return_type(this, returnKey.TypeRef);
|
||||
if (invokeMethod.ReturnsByRef)
|
||||
trapFile.type_annotation(this, Kinds.TypeAnnotation.Ref);
|
||||
if (invokeMethod.ReturnsByRefReadonly)
|
||||
trapFile.type_annotation(this, Kinds.TypeAnnotation.ReadonlyRef);
|
||||
if (symbol is IFunctionPointerTypeSymbol functionPointer)
|
||||
{
|
||||
ExtractParametersForDelegateLikeType(trapFile, functionPointer.Signature,
|
||||
t => trapFile.function_pointer_return_type(this, t));
|
||||
}
|
||||
|
||||
Modifier.ExtractModifiers(Context, trapFile, this, symbol);
|
||||
@@ -170,6 +163,23 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
}
|
||||
}
|
||||
|
||||
private void ExtractParametersForDelegateLikeType(TextWriter trapFile, IMethodSymbol invokeMethod, Action<Type> storeReturnType)
|
||||
{
|
||||
for (var i = 0; i < invokeMethod.Parameters.Length; ++i)
|
||||
{
|
||||
var param = invokeMethod.Parameters[i];
|
||||
var originalParam = invokeMethod.OriginalDefinition.Parameters[i];
|
||||
var originalParamEntity = SymbolEqualityComparer.Default.Equals(param, originalParam)
|
||||
? null
|
||||
: DelegateTypeParameter.Create(Context, originalParam, Create(Context, ((INamedTypeSymbol)symbol).OriginalDefinition));
|
||||
DelegateTypeParameter.Create(Context, param, this, originalParamEntity);
|
||||
}
|
||||
|
||||
var returnKey = Create(Context, invokeMethod.ReturnType);
|
||||
storeReturnType(returnKey.TypeRef);
|
||||
Method.ExtractRefReturn(trapFile, invokeMethod, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called to extract all members and nested types.
|
||||
/// This is called on each member of a namespace,
|
||||
@@ -265,8 +275,7 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
symbol != null && symbol.TypeKind == TypeKind.Delegate;
|
||||
|
||||
/// <summary>
|
||||
/// A copy of a delegate "Invoke" method parameter used for the delgate
|
||||
/// type.
|
||||
/// A copy of a delegate "Invoke" method or function pointer parameter.
|
||||
/// </summary>
|
||||
private class DelegateTypeParameter : Parameter
|
||||
{
|
||||
|
||||
@@ -120,6 +120,7 @@ namespace Semmle.Extraction.Kinds
|
||||
GT_PATTERN = 123,
|
||||
LE_PATTERN = 124,
|
||||
GE_PATTERN = 125,
|
||||
NOT_PATTERN = 126
|
||||
NOT_PATTERN = 126,
|
||||
FUNCTION_POINTER_INVOCATION = 129,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Semmle.Extraction.Kinds // lgtm[cs/similar-file]
|
||||
DYNAMIC = 29,
|
||||
ARGLIST = 30,
|
||||
UNKNOWN = 31,
|
||||
TUPLE = 32
|
||||
TUPLE = 32,
|
||||
FUNCTION_POINTER = 33
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace Semmle.Extraction.CSharp.Populators
|
||||
|
||||
public override IEntity VisitPointerType(IPointerTypeSymbol symbol) => PointerType.Create(cx, symbol);
|
||||
|
||||
public override IEntity VisitFunctionPointerType(IFunctionPointerTypeSymbol symbol) => FunctionPointerType.Create(cx, symbol);
|
||||
|
||||
public override IEntity VisitDynamicType(IDynamicTypeSymbol symbol) => DynamicType.Create(cx, symbol);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,6 +134,13 @@ namespace Semmle.Extraction.CSharp
|
||||
return tp.ContainingSymbol is ITypeSymbol cont
|
||||
? IdDependsOnImpl(cont)
|
||||
: SymbolEqualityComparer.Default.Equals(tp.ContainingSymbol, symbol);
|
||||
case TypeKind.FunctionPointer:
|
||||
var funptr = (IFunctionPointerTypeSymbol)type;
|
||||
if (funptr.Signature.Parameters.Any(p => IdDependsOnImpl(p.Type)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return IdDependsOnImpl(funptr.Signature.ReturnType);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -190,6 +197,10 @@ namespace Semmle.Extraction.CSharp
|
||||
case TypeKind.Dynamic:
|
||||
trapFile.Write("dynamic");
|
||||
return;
|
||||
case TypeKind.FunctionPointer:
|
||||
var funptr = (IFunctionPointerTypeSymbol)type;
|
||||
funptr.BuildFunctionPointerTypeId(cx, trapFile, symbolBeingDefined);
|
||||
return;
|
||||
default:
|
||||
throw new InternalError(type, $"Unhandled type kind '{type.TypeKind}'");
|
||||
}
|
||||
@@ -265,6 +276,53 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.Write("::");
|
||||
}
|
||||
|
||||
private static void BuildFunctionPointerTypeId(this IFunctionPointerTypeSymbol funptr, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined)
|
||||
{
|
||||
trapFile.Write("delegate* ");
|
||||
trapFile.Write(funptr.Signature.CallingConvention.ToString().ToLowerInvariant());
|
||||
if (funptr.Signature.UnmanagedCallingConventionTypes.Any())
|
||||
{
|
||||
trapFile.Write('[');
|
||||
trapFile.BuildList(",", funptr.Signature.UnmanagedCallingConventionTypes,
|
||||
(ta, tb0) => ta.BuildOrWriteId(cx, tb0, symbolBeingDefined)
|
||||
);
|
||||
trapFile.Write("]");
|
||||
}
|
||||
|
||||
trapFile.Write('<');
|
||||
trapFile.BuildList(",", funptr.Signature.Parameters,
|
||||
(p, trap) =>
|
||||
{
|
||||
p.Type.BuildOrWriteId(cx, trap, symbolBeingDefined);
|
||||
switch (p.RefKind)
|
||||
{
|
||||
case RefKind.Out:
|
||||
trap.Write(" out");
|
||||
break;
|
||||
case RefKind.In:
|
||||
trap.Write(" in");
|
||||
break;
|
||||
case RefKind.Ref:
|
||||
trap.Write(" ref");
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (funptr.Signature.Parameters.Any())
|
||||
{
|
||||
trapFile.Write(",");
|
||||
}
|
||||
|
||||
funptr.Signature.ReturnType.BuildOrWriteId(cx, trapFile, symbolBeingDefined);
|
||||
|
||||
if (funptr.Signature.ReturnsByRef)
|
||||
trapFile.Write(" ref");
|
||||
if (funptr.Signature.ReturnsByRefReadonly)
|
||||
trapFile.Write(" readonly ref");
|
||||
|
||||
trapFile.Write('>');
|
||||
}
|
||||
|
||||
private static void BuildNamedTypeId(this INamedTypeSymbol named, Context cx, TextWriter trapFile, ISymbol symbolBeingDefined, bool addBaseClass, bool constructUnderlyingTupleType)
|
||||
{
|
||||
if (!constructUnderlyingTupleType && named.IsTupleType)
|
||||
@@ -394,6 +452,10 @@ namespace Semmle.Extraction.CSharp
|
||||
ptr.PointedAtType.BuildDisplayName(cx, trapFile);
|
||||
trapFile.Write('*');
|
||||
return;
|
||||
case TypeKind.FunctionPointer:
|
||||
var funptr = (IFunctionPointerTypeSymbol)type;
|
||||
funptr.BuildFunctionPointerTypeDisplayName(cx, trapFile);
|
||||
return;
|
||||
case TypeKind.TypeParameter:
|
||||
trapFile.Write(type.Name);
|
||||
return;
|
||||
@@ -406,31 +468,90 @@ namespace Semmle.Extraction.CSharp
|
||||
}
|
||||
}
|
||||
|
||||
public static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, TextWriter trapFile, bool constructUnderlyingTupleType)
|
||||
private static void BuildFunctionPointerTypeDisplayName(this IFunctionPointerTypeSymbol funptr, Context cx, TextWriter trapFile)
|
||||
{
|
||||
trapFile.Write("delegate* ");
|
||||
trapFile.Write(funptr.Signature.CallingConvention.ToString().ToLowerInvariant());
|
||||
|
||||
if (funptr.Signature.UnmanagedCallingConventionTypes.Any())
|
||||
{
|
||||
trapFile.Write('[');
|
||||
trapFile.BuildList(
|
||||
",",
|
||||
funptr.Signature.UnmanagedCallingConventionTypes,
|
||||
(t, tb0) => t.BuildDisplayName(cx, tb0));
|
||||
trapFile.Write("]");
|
||||
}
|
||||
|
||||
trapFile.Write('<');
|
||||
trapFile.BuildList(",", funptr.Signature.Parameters,
|
||||
(p, trap) =>
|
||||
{
|
||||
p.Type.BuildDisplayName(cx, trapFile);
|
||||
switch (p.RefKind)
|
||||
{
|
||||
case RefKind.Out:
|
||||
trap.Write(" out");
|
||||
break;
|
||||
case RefKind.In:
|
||||
trap.Write(" in");
|
||||
break;
|
||||
case RefKind.Ref:
|
||||
trap.Write(" ref");
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if (funptr.Signature.Parameters.Any())
|
||||
{
|
||||
trapFile.Write(",");
|
||||
}
|
||||
|
||||
funptr.Signature.ReturnType.BuildDisplayName(cx, trapFile);
|
||||
|
||||
if (funptr.Signature.ReturnsByRef)
|
||||
trapFile.Write(" ref");
|
||||
if (funptr.Signature.ReturnsByRefReadonly)
|
||||
trapFile.Write(" readonly ref");
|
||||
|
||||
trapFile.Write('>');
|
||||
}
|
||||
|
||||
private static void BuildNamedTypeDisplayName(this INamedTypeSymbol namedType, Context cx, TextWriter trapFile, bool constructUnderlyingTupleType)
|
||||
{
|
||||
if (!constructUnderlyingTupleType && namedType.IsTupleType)
|
||||
{
|
||||
trapFile.Write('(');
|
||||
trapFile.BuildList(",", namedType.TupleElements.Select(f => f.Type),
|
||||
(t, tb0) => t.BuildDisplayName(cx, tb0)
|
||||
);
|
||||
|
||||
trapFile.BuildList(
|
||||
",",
|
||||
namedType.TupleElements.Select(f => f.Type),
|
||||
(t, tb0) => t.BuildDisplayName(cx, tb0));
|
||||
trapFile.Write(")");
|
||||
return;
|
||||
}
|
||||
|
||||
if (namedType.IsAnonymousType)
|
||||
{
|
||||
namedType.BuildAnonymousName(cx, trapFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
trapFile.Write(namedType.Name);
|
||||
}
|
||||
|
||||
if (namedType.IsGenericType && namedType.TypeKind != TypeKind.Error && namedType.TypeArguments.Any())
|
||||
{
|
||||
trapFile.Write('<');
|
||||
trapFile.BuildList(",", namedType.TypeArguments, (p, tb0) =>
|
||||
{
|
||||
if (IsReallyBound(namedType))
|
||||
p.BuildDisplayName(cx, tb0);
|
||||
});
|
||||
trapFile.BuildList(
|
||||
",",
|
||||
namedType.TypeArguments,
|
||||
(p, tb0) =>
|
||||
{
|
||||
if (IsReallyBound(namedType))
|
||||
{
|
||||
p.BuildDisplayName(cx, tb0);
|
||||
}
|
||||
});
|
||||
trapFile.Write('>');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +151,11 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.WriteTuple("delegate_return_type", delegateKey, returnType);
|
||||
}
|
||||
|
||||
internal static void function_pointer_return_type(this TextWriter trapFile, Type functionPointer, Type returnType)
|
||||
{
|
||||
trapFile.WriteTuple("function_pointer_return_type", functionPointer, returnType);
|
||||
}
|
||||
|
||||
internal static void destructor_location(this TextWriter trapFile, Destructor destructor, Location location)
|
||||
{
|
||||
trapFile.WriteTuple("destructor_location", destructor, location);
|
||||
@@ -476,6 +481,16 @@ namespace Semmle.Extraction.CSharp
|
||||
trapFile.WriteTuple("specific_type_parameter_nullability", constraints, baseType, nullability);
|
||||
}
|
||||
|
||||
internal static void function_pointer_calling_conventions(this TextWriter trapFile, FunctionPointerType type, int kind)
|
||||
{
|
||||
trapFile.WriteTuple("function_pointer_calling_conventions", type, kind);
|
||||
}
|
||||
|
||||
internal static void has_unmanaged_calling_conventions(this TextWriter trapFile, FunctionPointerType type, int index, Type convention)
|
||||
{
|
||||
trapFile.WriteTuple("has_unmanaged_calling_conventions", type, index, convention);
|
||||
}
|
||||
|
||||
internal static void stackalloc_array_creation(this TextWriter trapFile, Expression array)
|
||||
{
|
||||
trapFile.WriteTuple("stackalloc_array_creation", array);
|
||||
|
||||
Reference in New Issue
Block a user