mirror of
https://github.com/github/codeql.git
synced 2026-05-14 11:19:27 +02:00
C#: Re-use the GetTargetSymbol logic from invocations to find the right operator symbol (operators can also be declared in extensions).
This commit is contained in:
@@ -228,6 +228,41 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
return Literal.CreateGenerated(cx, parent, childIndex, type, defaultValue, location);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given an expression syntax node, attempt to resolve the target method symbol for it.
|
||||
/// The operation takes extension methods into account.
|
||||
/// </summary>
|
||||
/// <param name="node">The expression syntax node.</param>
|
||||
/// <returns>Returns the target method symbol, or null if it cannot be resolved.</returns>
|
||||
protected IMethodSymbol? GetTargetSymbol(ExpressionSyntax node)
|
||||
{
|
||||
var si = Context.GetSymbolInfo(node);
|
||||
if (si.Symbol is ISymbol symbol)
|
||||
{
|
||||
var method = symbol as IMethodSymbol;
|
||||
// Case for compiler-generated extension methods.
|
||||
return method?.TryGetExtensionMethod() ?? method;
|
||||
}
|
||||
|
||||
if (si.CandidateReason == CandidateReason.OverloadResolutionFailure && node is InvocationExpressionSyntax syntax)
|
||||
{
|
||||
// This seems to be a bug in Roslyn
|
||||
// For some reason, typeof(X).InvokeMember(...) fails to resolve the correct
|
||||
// InvokeMember() method, even though the number of parameters clearly identifies the correct method
|
||||
|
||||
var candidates = si.CandidateSymbols
|
||||
.OfType<IMethodSymbol>()
|
||||
.Where(method => method.Parameters.Length >= syntax.ArgumentList.Arguments.Count)
|
||||
.Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= syntax.ArgumentList.Arguments.Count);
|
||||
|
||||
return Context.ExtractionContext.IsStandalone ?
|
||||
candidates.FirstOrDefault() :
|
||||
candidates.SingleOrDefault();
|
||||
}
|
||||
|
||||
return si.Symbol as IMethodSymbol;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adapt the operator kind depending on whether it's a dynamic call or a user-operator call.
|
||||
/// </summary>
|
||||
@@ -244,10 +279,10 @@ namespace Semmle.Extraction.CSharp.Entities
|
||||
/// name if available.
|
||||
/// </summary>
|
||||
/// <param name="node">The expression.</param>
|
||||
public void OperatorCall(TextWriter trapFile, ExpressionSyntax node)
|
||||
public void AddOperatorCall(TextWriter trapFile, ExpressionSyntax node)
|
||||
{
|
||||
var @operator = Context.GetSymbolInfo(node);
|
||||
if (@operator.Symbol is IMethodSymbol method)
|
||||
var @operator = GetTargetSymbol(node);
|
||||
if (@operator is IMethodSymbol method)
|
||||
{
|
||||
var callType = GetCallType(Context, node);
|
||||
if (callType == CallType.Dynamic)
|
||||
|
||||
@@ -24,10 +24,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
{
|
||||
Create(Context, Syntax.Left, this, 0);
|
||||
Create(Context, Syntax.Right, this, 1);
|
||||
|
||||
if (Kind != ExprKind.SIMPLE_ASSIGN && Kind != ExprKind.ASSIGN_COALESCE)
|
||||
{
|
||||
OperatorCall(trapFile, Syntax);
|
||||
AddOperatorCall(trapFile, Syntax);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
OperatorCall(trapFile, Syntax);
|
||||
AddOperatorCall(trapFile, Syntax);
|
||||
CreateDeferred(Context, Syntax.Left, 0);
|
||||
CreateDeferred(Context, Syntax.Right, 1);
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
else
|
||||
{
|
||||
// Type conversion
|
||||
OperatorCall(trapFile, Syntax);
|
||||
AddOperatorCall(trapFile, Syntax);
|
||||
TypeMention.Create(Context, Syntax.Type, this, Type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
|
||||
var child = -1;
|
||||
string? memberName = null;
|
||||
var target = TargetSymbol;
|
||||
var target = GetTargetSymbol(Syntax);
|
||||
switch (Syntax.Expression)
|
||||
{
|
||||
case MemberAccessExpressionSyntax memberAccess when IsValidMemberAccessKind():
|
||||
@@ -129,39 +129,6 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
method.TryGetExtensionMethod()?.MethodKind == MethodKind.UserDefinedOperator;
|
||||
}
|
||||
|
||||
public IMethodSymbol? TargetSymbol
|
||||
{
|
||||
get
|
||||
{
|
||||
var si = SymbolInfo;
|
||||
|
||||
if (si.Symbol is ISymbol symbol)
|
||||
{
|
||||
var method = symbol as IMethodSymbol;
|
||||
// Case for compiler-generated extension methods.
|
||||
return method?.TryGetExtensionMethod() ?? method;
|
||||
}
|
||||
|
||||
if (si.CandidateReason == CandidateReason.OverloadResolutionFailure)
|
||||
{
|
||||
// This seems to be a bug in Roslyn
|
||||
// For some reason, typeof(X).InvokeMember(...) fails to resolve the correct
|
||||
// InvokeMember() method, even though the number of parameters clearly identifies the correct method
|
||||
|
||||
var candidates = si.CandidateSymbols
|
||||
.OfType<IMethodSymbol>()
|
||||
.Where(method => method.Parameters.Length >= Syntax.ArgumentList.Arguments.Count)
|
||||
.Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= Syntax.ArgumentList.Arguments.Count);
|
||||
|
||||
return Context.ExtractionContext.IsStandalone ?
|
||||
candidates.FirstOrDefault() :
|
||||
candidates.SingleOrDefault();
|
||||
}
|
||||
|
||||
return si.Symbol as IMethodSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsDelegateLikeCall(ExpressionNodeInfo info)
|
||||
{
|
||||
return IsDelegateLikeCall(info, symbol => IsFunctionPointer(symbol) || IsDelegateInvoke(symbol));
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
if ((operatorKind == ExprKind.POST_INCR || operatorKind == ExprKind.POST_DECR) &&
|
||||
Kind == ExprKind.OPERATOR_INVOCATION)
|
||||
{
|
||||
OperatorCall(trapFile, Syntax);
|
||||
AddOperatorCall(trapFile, Syntax);
|
||||
trapFile.mutator_invocation_mode(this, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
|
||||
protected override void PopulateExpression(TextWriter trapFile)
|
||||
{
|
||||
Create(Context, Syntax.Operand, this, 0);
|
||||
OperatorCall(trapFile, Syntax);
|
||||
AddOperatorCall(trapFile, Syntax);
|
||||
|
||||
if ((operatorKind == ExprKind.PRE_INCR || operatorKind == ExprKind.PRE_DECR) &&
|
||||
Kind == ExprKind.OPERATOR_INVOCATION)
|
||||
|
||||
Reference in New Issue
Block a user