C#: Adjust conditional access locations

This commit is contained in:
Tom Hvitved
2024-04-10 15:24:20 +02:00
parent 7c43ca7001
commit 1c344d6735
20 changed files with 337 additions and 307 deletions

View File

@@ -314,24 +314,46 @@ namespace Semmle.Extraction.CSharp.Entities
}
/// <summary>
/// Given b in a?.b.c, return a.
/// Given `b` in `a?.b.c`, return `(a?.b, a?.b)`.
///
/// Given `c` in `a?.b?.c.d`, return `(b?.c, a?.b?.c)`.
/// </summary>
/// <param name="node">A MemberBindingExpression.</param>
/// <returns>The qualifier of the conditional access.</returns>
protected static ExpressionSyntax FindConditionalQualifier(ExpressionSyntax node)
/// <returns>The conditional access.</returns>
public static (ConditionalAccessExpressionSyntax Parent, ConditionalAccessExpressionSyntax Root) FindConditionalAccessParent(ExpressionSyntax node)
{
for (SyntaxNode? n = node; n is not null; n = n.Parent)
(ConditionalAccessExpressionSyntax, ConditionalAccessExpressionSyntax)? res = null;
SyntaxNode? prev = null;
for (SyntaxNode? n = node; n is not null; prev = n, n = n.Parent)
{
if (n.Parent is ConditionalAccessExpressionSyntax conditionalAccess &&
conditionalAccess.WhenNotNull == n)
if (n is ConditionalAccessExpressionSyntax conditionalAccess &&
(prev is null || conditionalAccess.WhenNotNull == prev))
{
return conditionalAccess.Expression;
res = res is null ? (conditionalAccess, conditionalAccess) : (res.Value.Item1, conditionalAccess);
}
else if (res.HasValue)
{
break;
}
}
if (res.HasValue)
{
return res.Value;
}
throw new InternalError(node, "Unable to locate a ConditionalAccessExpression");
}
/// <summary>
/// Given b in a?.b.c, return a.
/// </summary>
/// <param name="node">A MemberBindingExpression.</param>
/// <returns>The qualifier of the conditional access.</returns>
protected static ExpressionSyntax FindConditionalQualifier(ExpressionSyntax node) =>
FindConditionalAccessParent(node).Parent.Expression;
public void MakeConditional(TextWriter trapFile)
{
trapFile.conditional_access(this);

View File

@@ -125,11 +125,6 @@ namespace Semmle.Extraction.CSharp.Entities
cachedLocation = Context.CreateLocation(CodeAnalysisLocation);
return cachedLocation;
}
set
{
cachedLocation = value;
}
}
public ExprKind Kind { get; set; } = ExprKind.UNKNOWN;

View File

@@ -79,7 +79,9 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
internal class BindingElementAccess : ElementAccess
{
private BindingElementAccess(ExpressionNodeInfo info)
: base(info, FindConditionalQualifier(info.Node), ((ElementBindingExpressionSyntax)info.Node).ArgumentList) { }
: base(info, FindConditionalQualifier(info.Node), ((ElementBindingExpressionSyntax)info.Node).ArgumentList)
{
}
public static Expression Create(ExpressionNodeInfo info) => new BindingElementAccess(info).TryPopulate();

View File

@@ -13,7 +13,7 @@ namespace Semmle.Extraction.CSharp.Populators
/// <param name="l1">The location to extend.</param>
/// <param name="n2">The node to extend the location to.</param>
/// <returns>Extended location.</returns>
public static Location ExtendLocation(this Location l1, SyntaxNode n2)
public static Location ExtendLocation(this Location l1, SyntaxNode n2, bool onlyStart = false)
{
if (n2 is null)
{
@@ -22,7 +22,7 @@ namespace Semmle.Extraction.CSharp.Populators
var l2 = n2.FixedLocation();
var start = System.Math.Min(l1.SourceSpan.Start, l2.SourceSpan.Start);
var end = System.Math.Max(l1.SourceSpan.End, l2.SourceSpan.End);
var end = onlyStart ? l1.SourceSpan.End : System.Math.Max(l1.SourceSpan.End, l2.SourceSpan.End);
return Location.Create(n2.SyntaxTree, new Microsoft.CodeAnalysis.Text.TextSpan(start, end - start));
}
@@ -85,6 +85,17 @@ namespace Semmle.Extraction.CSharp.Populators
return ((CatchDeclarationSyntax)node).Identifier.GetLocation();
case SyntaxKind.LabeledStatement:
return ((LabeledStatementSyntax)node).Identifier.GetLocation();
case SyntaxKind.ElementBindingExpression:
return node.GetLocation().ExtendLocation(Entities.Expression.FindConditionalAccessParent((ElementBindingExpressionSyntax)node).Root, onlyStart: true);
case SyntaxKind.MemberBindingExpression:
return node.GetLocation().ExtendLocation(Entities.Expression.FindConditionalAccessParent((MemberBindingExpressionSyntax)node).Root, onlyStart: true);
case SyntaxKind.ElementAccessExpression:
return node.GetLocation().ExtendLocation(((ElementAccessExpressionSyntax)node).Expression);
case SyntaxKind.SimpleMemberAccessExpression:
return node.GetLocation().ExtendLocation(((MemberAccessExpressionSyntax)node).Expression);
case SyntaxKind.InvocationExpression:
return node.GetLocation().ExtendLocation(((InvocationExpressionSyntax)node).Expression);
default:
result = node.GetLocation();
break;