Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions csharp/ql/lib/Linq/Helpers.qll
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,17 @@ predicate missedOfTypeOpportunity(ForeachStmtEnumerable fes, LocalVariableDeclSt
/**
* Holds if `foreach` statement `fes` can be converted to a `.Select()` call.
* That is, the loop variable is accessed only in the first statement of the
* block, the access is not a cast, and the first statement is a
* local variable declaration statement `s`.
* block, the access is not a cast, the first statement is a
* local variable declaration statement `s`, and the initializer does not
* contain an `await` expression (since `Select` does not support async lambdas).
Comment thread
hvitved marked this conversation as resolved.
*/
predicate missedSelectOpportunity(ForeachStmtGenericEnumerable fes, LocalVariableDeclStmt s) {
s = firstStmt(fes) and
forex(VariableAccess va | va = fes.getVariable().getAnAccess() |
va = s.getAVariableDeclExpr().getAChildExpr*()
) and
not s.getAVariableDeclExpr().getInitializer() instanceof Cast
not s.getAVariableDeclExpr().getInitializer() instanceof Cast and
not s.getAVariableDeclExpr().getInitializer().getAChildExpr*() instanceof AwaitExpr
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading.Tasks;

class MissedSelectOpportunity
{
public void M1(List<int> lst)
{
// BAD: Can be replaced with lst.Select(i => i * i)
foreach (int i in lst)
{
int j = i * i;
Console.WriteLine(j);
}
}

public async Task M2(IEnumerable<ICounter> counters)
{
// GOOD: Cannot use Select because the initializer contains an await expression
foreach (var counter in counters)
{
var count = await counter.CountAsync();
Console.WriteLine(count);
}
}

public interface ICounter
{
Task<int> CountAsync();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
| MissedSelectOpportunity.cs:11:9:15:9 | foreach (... ... in ...) ... | This foreach loop immediately $@ - consider mapping the sequence explicitly using '.Select(...)'. | MissedSelectOpportunity.cs:13:13:13:26 | ... ...; | maps its iteration variable to another variable |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Linq/MissedSelectOpportunity.ql

Check warning

Code scanning / CodeQL

Query test without inline test expectations Warning test

Query test does not use inline test expectations.
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use inline test expectations, i.e.

postprocess:
 - utils/test/InlineExpectationsTestQuery.ql

This also means adding // $ Alert marker comment in the test file.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
semmle-extractor-options: /nostdlib /noconfig
semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj
Loading