Skip to content

Commit 8bfab55

Browse files
authored
Merge branch 'main' into workflow/coverage/update
2 parents 09198d9 + 133e269 commit 8bfab55

File tree

581 files changed

+29220
-35430
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

581 files changed

+29220
-35430
lines changed

cpp/ql/src/Critical/ScanfChecks.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ private string getEofValue() {
3737
*/
3838
private predicate checkedForEof(ScanfFunctionCall call) {
3939
exists(IRGuardCondition gc |
40-
exists(Instruction i | i.getUnconvertedResultExpression() = call |
40+
exists(CallInstruction i | i.getUnconvertedResultExpression() = call |
4141
exists(int val | gc.comparesEq(valueNumber(i).getAUse(), val, _, _) |
4242
// call == EOF
4343
val = getEofValue().toInt()

csharp/extractor/Semmle.Extraction.CSharp/CodeAnalysisExtensions/SymbolExtensions.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,12 @@ attribute.AttributeClass is INamedTypeSymbol nt &&
532532
return isInline;
533533
}
534534

535+
/// <summary>
536+
/// Returns true if this type implements `System.IFormattable`.
537+
/// </summary>
538+
public static bool ImplementsIFormattable(this ITypeSymbol type) =>
539+
type.AllInterfaces.Any(i => i.Name == "IFormattable" && i.ContainingNamespace.ToString() == "System");
540+
535541
/// <summary>
536542
/// Holds if this type is of the form <code>System.ReadOnlySpan&lt;byte&gt;</code>.
537543
/// </summary>

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ public static void CreateDeferred(Context cx, ExpressionSyntax node, IExpression
129129
cx.PopulateLater(() => Create(cx, node, parent, child));
130130
}
131131

132-
private static bool ContainsPattern(SyntaxNode node) =>
132+
protected static bool ContainsPattern(SyntaxNode node) =>
133133
node is PatternSyntax || node is VariableDesignationSyntax || node.ChildNodes().Any(ContainsPattern);
134134

135135
/// <summary>

csharp/extractor/Semmle.Extraction.CSharp/Entities/ExpressionNodeInfo.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,13 @@ public Location Location
129129

130130
public ExprKind Kind { get; set; } = ExprKind.UNKNOWN;
131131

132-
public bool IsCompilerGenerated { get; set; }
132+
public bool IsCompilerGenerated { get; init; }
133+
134+
/// <summary>
135+
/// Whether the expression should have a compiler generated `ToString` call added,
136+
/// if there is no suitable implicit cast.
137+
/// </summary>
138+
public bool ImplicitToString { get; private set; }
133139

134140
public ExpressionNodeInfo SetParent(IExpressionParentEntity parent, int child)
135141
{
@@ -157,6 +163,12 @@ public ExpressionNodeInfo SetNode(ExpressionSyntax node)
157163
return this;
158164
}
159165

166+
public ExpressionNodeInfo SetImplicitToString(bool value)
167+
{
168+
ImplicitToString = value;
169+
return this;
170+
}
171+
160172
private SymbolInfo cachedSymbolInfo;
161173

162174
public SymbolInfo SymbolInfo

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,35 @@ private Binary(ExpressionNodeInfo info)
1414

1515
public static Expression Create(ExpressionNodeInfo info) => new Binary(info).TryPopulate();
1616

17+
private Expression CreateChild(Context cx, ExpressionSyntax node, int child)
18+
{
19+
// If this is a "+" expression we might need to wrap the child expressions
20+
// in ToString calls
21+
return Kind == ExprKind.ADD
22+
? ImplicitToString.Create(cx, node, this, child)
23+
: Create(cx, node, this, child);
24+
}
25+
26+
/// <summary>
27+
/// Creates an expression from a syntax node.
28+
/// Inserts type conversion as required.
29+
/// Population is deferred to avoid overflowing the stack.
30+
/// </summary>
31+
private void CreateDeferred(Context cx, ExpressionSyntax node, int child)
32+
{
33+
if (ContainsPattern(node))
34+
// Expressions with patterns should be created right away, as they may introduce
35+
// local variables referenced in `LocalVariable::GetAlreadyCreated()`
36+
CreateChild(cx, node, child);
37+
else
38+
cx.PopulateLater(() => CreateChild(cx, node, child));
39+
}
40+
1741
protected override void PopulateExpression(TextWriter trapFile)
1842
{
1943
OperatorCall(trapFile, Syntax);
20-
CreateDeferred(Context, Syntax.Left, this, 0);
21-
CreateDeferred(Context, Syntax.Right, this, 1);
44+
CreateDeferred(Context, Syntax.Left, 0);
45+
CreateDeferred(Context, Syntax.Right, 1);
2246
}
2347

2448
private static ExprKind GetKind(Context cx, BinaryExpressionSyntax node)

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitCast.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ convertedType.Symbol is IPointerTypeSymbol &&
156156
return new ImplicitCast(info);
157157
}
158158

159+
if (info.ImplicitToString)
160+
{
161+
// x -> x.ToString() in "abc" + x
162+
return ImplicitToString.Wrap(info);
163+
}
164+
159165
// Default: Just create the expression without a conversion.
160166
return Factory.Create(info);
161167
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System.Linq;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using Semmle.Extraction.CSharp.Util;
5+
using Semmle.Extraction.Kinds;
6+
7+
8+
namespace Semmle.Extraction.CSharp.Entities.Expressions
9+
{
10+
internal sealed class ImplicitToString : Expression
11+
{
12+
/// <summary>
13+
/// Gets the `ToString` method for the given type.
14+
/// </summary>
15+
private static IMethodSymbol? GetToStringMethod(ITypeSymbol? type)
16+
{
17+
return type?
18+
.GetMembers()
19+
.OfType<IMethodSymbol>()
20+
.Where(method =>
21+
method.GetName() == "ToString" &&
22+
method.Parameters.Length == 0
23+
)
24+
.FirstOrDefault();
25+
}
26+
27+
private ImplicitToString(ExpressionNodeInfo info, IMethodSymbol toString) : base(new ExpressionInfo(info.Context, AnnotatedTypeSymbol.CreateNotAnnotated(toString.ReturnType), info.Location, ExprKind.METHOD_INVOCATION, info.Parent, info.Child, isCompilerGenerated: true, info.ExprValue))
28+
{
29+
Factory.Create(info.SetParent(this, -1));
30+
31+
var target = Method.Create(Context, toString);
32+
Context.TrapWriter.Writer.expr_call(this, target);
33+
}
34+
35+
private static bool IsStringType(AnnotatedTypeSymbol? type) =>
36+
type.HasValue && type.Value.Symbol?.SpecialType == SpecialType.System_String;
37+
38+
/// <summary>
39+
/// Creates a new expression, adding a compiler generated `ToString` call if required.
40+
/// </summary>
41+
public static Expression Create(Context cx, ExpressionSyntax node, Expression parent, int child)
42+
{
43+
var info = new ExpressionNodeInfo(cx, node, parent, child);
44+
return CreateFromNode(info.SetImplicitToString(IsStringType(parent.Type) && !IsStringType(info.Type)));
45+
}
46+
47+
/// <summary>
48+
/// Wraps the resulting expression in a `ToString` call, if a suitable `ToString` method is available.
49+
/// </summary>
50+
public static Expression Wrap(ExpressionNodeInfo info)
51+
{
52+
if (GetToStringMethod(info.Type?.Symbol) is IMethodSymbol toString)
53+
{
54+
return new ImplicitToString(info, toString);
55+
}
56+
return Factory.Create(info);
57+
}
58+
}
59+
}

csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/InterpolatedString.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.IO;
2+
using Microsoft.CodeAnalysis;
23
using Microsoft.CodeAnalysis.CSharp;
34
using Microsoft.CodeAnalysis.CSharp.Syntax;
45
using Semmle.Extraction.Kinds;
@@ -20,7 +21,15 @@ protected override void PopulateExpression(TextWriter trapFile)
2021
{
2122
case SyntaxKind.Interpolation:
2223
var interpolation = (InterpolationSyntax)c;
23-
Create(Context, interpolation.Expression, this, child++);
24+
var exp = interpolation.Expression;
25+
if (Context.GetTypeInfo(exp).Type is ITypeSymbol type && !type.ImplementsIFormattable())
26+
{
27+
ImplicitToString.Create(Context, exp, this, child++);
28+
}
29+
else
30+
{
31+
Create(Context, exp, this, child++);
32+
}
2433
break;
2534
case SyntaxKind.InterpolatedStringText:
2635
// Create a string literal

csharp/ql/examples/snippets/ternary_conditional.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import csharp
1111

1212
from ConditionalExpr e
1313
where
14-
e.getThen().stripImplicitCasts() != e.getElse().stripImplicitCasts() and
14+
e.getThen().stripImplicit() != e.getElse().stripImplicit() and
1515
not e.getThen().getType() instanceof NullType and
1616
not e.getElse().getType() instanceof NullType
1717
select e
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added extractor support for extracting implicit `ToString` calls in binary `+` expressions and string interpolation expressions.

0 commit comments

Comments
 (0)