Skip to content

Commit

Permalink
Merge branch 'master' into Pavel/CreateWorkflow
Browse files Browse the repository at this point in the history
  • Loading branch information
marco-antognini-sonarsource authored Jan 9, 2025
2 parents 9d46e58 + e39e8bb commit fb626bf
Show file tree
Hide file tree
Showing 24 changed files with 936 additions and 82 deletions.
17 changes: 10 additions & 7 deletions frontend/public/covered_rules.json
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@
"S2216": "sonar-cpp 5.1.0.10083",
"S2234": "sonar-cpp 5.1.0.10083",
"S2245": "sonar-cpp 6.15.0.25047",
"S2253": "sonar-cpp master",
"S2253": "sonar-cpp 6.62.0.78645",
"S2259": "sonar-cpp 5.1.0.10083",
"S2260": "sonar-cpp 5.1.0.10083",
"S2275": "sonar-cpp 6.2.0.11201",
Expand Down Expand Up @@ -412,7 +412,7 @@
"S5271": "sonar-cpp 6.2.0.11201",
"S5273": "sonar-cpp 6.2.0.11201",
"S5276": "sonar-cpp 6.10.0.18490",
"S5277": "sonar-cpp master",
"S5277": "sonar-cpp 6.62.0.78645",
"S5278": "sonar-cpp 6.2.0.11201",
"S5279": "sonar-cpp 6.2.0.11201",
"S5280": "sonar-cpp 6.2.0.11201",
Expand Down Expand Up @@ -536,7 +536,7 @@
"S959": "sonar-cpp 5.1.0.10083",
"S960": "sonar-cpp 5.1.0.10083",
"S961": "sonar-cpp 5.1.0.10083",
"S963": "sonar-cpp master",
"S963": "sonar-cpp 6.62.0.78645",
"S966": "sonar-cpp 5.1.0.10083",
"S967": "sonar-cpp 6.3.0.11371",
"S968": "sonar-cpp 5.1.0.10083",
Expand Down Expand Up @@ -950,7 +950,7 @@
"S2216": "sonar-cpp 5.1.0.10083",
"S2234": "sonar-cpp 5.1.0.10083",
"S2245": "sonar-cpp 6.15.0.25047",
"S2253": "sonar-cpp master",
"S2253": "sonar-cpp 6.62.0.78645",
"S2259": "sonar-cpp 5.1.0.10083",
"S2260": "sonar-cpp 5.1.0.10083",
"S2275": "sonar-cpp 6.2.0.11201",
Expand Down Expand Up @@ -1340,6 +1340,7 @@
"S7127": "sonar-cpp 6.61.0.77816",
"S7129": "sonar-cpp 6.61.0.77816",
"S7132": "sonar-cpp 6.61.0.77816",
"S7172": "sonar-cpp master",
"S784": "sonar-cpp 5.1.0.10083",
"S787": "sonar-cpp 5.1.0.10083",
"S793": "sonar-cpp 5.1.0.10083",
Expand Down Expand Up @@ -4180,7 +4181,7 @@
"S2216": "sonar-cpp 5.1.0.10083",
"S2234": "sonar-cpp 5.1.0.10083",
"S2245": "sonar-cpp 6.15.0.25047",
"S2253": "sonar-cpp master",
"S2253": "sonar-cpp 6.62.0.78645",
"S2259": "sonar-cpp 6.5.0.12506",
"S2260": "sonar-cpp 5.1.0.10083",
"S2275": "sonar-cpp 6.2.0.11201",
Expand Down Expand Up @@ -4260,7 +4261,7 @@
"S5271": "sonar-cpp 6.2.0.11201",
"S5273": "sonar-cpp 6.2.0.11201",
"S5276": "sonar-cpp 6.10.0.18490",
"S5277": "sonar-cpp master",
"S5277": "sonar-cpp 6.62.0.78645",
"S5278": "sonar-cpp 6.2.0.11201",
"S5279": "sonar-cpp 6.2.0.11201",
"S5280": "sonar-cpp 6.2.0.11201",
Expand Down Expand Up @@ -4380,7 +4381,7 @@
"S959": "sonar-cpp 5.1.0.10083",
"S960": "sonar-cpp 5.1.0.10083",
"S961": "sonar-cpp 5.1.0.10083",
"S963": "sonar-cpp master",
"S963": "sonar-cpp 6.62.0.78645",
"S966": "sonar-cpp 5.1.0.10083",
"S967": "sonar-cpp 6.3.0.11371",
"S968": "sonar-cpp 5.1.0.10083",
Expand Down Expand Up @@ -6299,6 +6300,8 @@
"S1702": "sonar-vb 2.4.0.1305",
"S1821": "sonar-vb 2.7.0.2492",
"S2260": "sonar-vb 2.4.0.1305",
"S6146": "sonar-vb 2.14.0.5475",
"S7173": "sonar-vb 2.14.0.5475",
"S907": "sonar-vb 2.4.0.1305"
},
"VBNET": {
Expand Down
65 changes: 63 additions & 2 deletions rules/S1155/csharp/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ When you call `Any()`, it clearly communicates the code's intention, which is to
* if the collection is an `EntityFramework` or other ORM query, calling `Count()` will cause executing a potentially massive SQL query and could put a large overhead on the application database. Calling `Any()` will also connect to the database, but will generate much more efficient SQL.
* if the collection is part of a LINQ query that contains `Select()` statements that create objects, a large amount of memory could be unnecessarily allocated. Calling `Any()` will be much more efficient because it will execute fewer iterations of the enumerable.
== How to fix it

Prefer using `Any()` to test for emptiness over `Count()`.

=== Code examples

==== Noncompliant code example

[source,csharp,diff-id=1,diff-type=noncompliant]
----
private static bool HasContent(IEnumerable<string> strings)
Expand All @@ -23,7 +31,7 @@ private static bool IsEmpty(IEnumerable<string> strings)
}
----

Prefer using `Any()` to test for emptiness over `Count()`.
==== Compliant solution

[source,csharp,diff-id=1,diff-type=compliant]
----
Expand All @@ -43,6 +51,59 @@ private static bool IsEmpty(IEnumerable<string> strings)
}
----

== Resources

=== Benchmarks

[options="header"]
|===
| Method | Runtime | Mean | Standard Deviation
| Count | .NET 9.0 | 2,841.003 ns | 266.0238 ns
| Any | .NET 9.0 | 1.749 ns | 0.1242 ns
| Count | .NET Framework 4.8.1 | 71,125.275 ns | 731.0382 ns
| Any | .NET Framework 4.8.1 | 31.774 ns | 0.3196 ns
|===

==== Glossary

* https://en.wikipedia.org/wiki/Arithmetic_mean[Mean]
* https://en.wikipedia.org/wiki/Standard_deviation[Standard Deviation]

The results were generated by running the following snippet with https://github.com/dotnet/BenchmarkDotNet[BenchmarkDotNet]:

[source,csharp]
----
private IEnumerable<int> collection;
public const int N = 10_000;
[GlobalSetup]
public void GlobalSetup()
{
collection = Enumerable.Range(0, N).Select(x => N - x);
}
[Benchmark(Baseline = true)]
public bool Count() =>
collection.Count() > 0;
[Benchmark]
public bool Any() =>
collection.Any();
----

Hardware Configuration:

[source]
----
BenchmarkDotNet v0.14.0, Windows 10 (10.0.19045.5247/22H2/2022Update)
12th Gen Intel Core i7-12800H, 1 CPU, 20 logical and 14 physical cores
[Host] : .NET Framework 4.8.1 (4.8.9282.0), X64 RyuJIT VectorSize=256
.NET 9.0 : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX2
.NET Framework 4.8.1 : .NET Framework 4.8.1 (4.8.9282.0), X64 RyuJIT VectorSize=256
----


ifdef::env-github,rspecator-view[]

'''
Expand Down Expand Up @@ -101,7 +162,7 @@ Added the `Count() == 0` to the description and extended the code samples
\[~ann.campbell.2] You are right, I removed the comparison to `0`.

=== on 27 May 2015, 14:04:31 Ann Campbell wrote:
Thanks [~tamas.vajk]. I've merged the code blocks into one block each for Compliant and Noncompliant
Thanks [~tamas.vajk]. I've merged the code blocks into one block each for Compliant and Noncompliant

=== on 1 Jun 2015, 14:30:42 Ann Campbell wrote:
I've updated the examples with `List<string>`. Please double-check me.
Expand Down
78 changes: 78 additions & 0 deletions rules/S1215/csharp/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,82 @@ There may be exceptions to this rule: for example, you've just triggered some ev
* https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/latency[Garbage collection latency modes]
* https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/performance#troubleshoot-performance-issues[Garbage collection troubleshoot performance issues]

=== Benchmarks

Each .NET runtime features distinct implementations, modes, and configurations for its garbage collector.
The benchmark below illustrates how invoking `GC.Collect()` can have opposite effects across different runtimes.

[options="header"]
|===
| Runtime | Collect | Mean | Standard Deviation | Allocated
| .NET 9.0 | False | 659.2 ms | 15.69 ms | 205.95 MB
| .NET 9.0 | True | 888.8 ms | 15.34 ms | 205.95 MB
| | | | |
| .NET Framework 4.8.1 | False | 545.7 ms | 19.49 ms | 228.8 MB
| .NET Framework 4.8.1 | True | 484.8 ms | 11.79 ms | 228.8 MB
|===

==== Glossary

* Collect - if `True`, `GC.Collect()` is called in the middle of the allocation heavy `Benchmark()` method
* https://en.wikipedia.org/wiki/Arithmetic_mean[Mean]
* https://en.wikipedia.org/wiki/Standard_deviation[Standard Deviation]
* https://github.com/dotnet/BenchmarkDotNet/blob/master/docs/articles/configs/diagnosers.md[Allocated]

The results were generated by running the following snippet with https://github.com/dotnet/BenchmarkDotNet[BenchmarkDotNet]:

[source,csharp]
----
class Tree
{
public List<Tree> Children = new();
}
private void AppendToTree(Tree tree, int childsPerTree, int depth)
{
if (depth == 0)
{
return;
}
for (int i = 0; i < childsPerTree; i++)
{
var child = new Tree();
tree.Children.Add(child);
AppendToTree(child, childsPerTree, depth - 1);
}
}
[Benchmark]
[Arguments(true)]
[Arguments(false)]
public void Benchmark(bool collect)
{
var tree = new Tree();
AppendToTree(tree, 8, 7); // Create 8^7 Tree objects (2.097.152 objects) linked via List<Tree> Children
GC.Collect();
GC.Collect(); // Move the objects to generation 2
AppendToTree(new Tree(), 8, 6); // Add some more memory preasure (8^6 262.144 objects) which can be collected right after this call
tree = null; // Remove all references to the tree and its content. This freees up 8^7 Tree objects (2.097.152 objects)
if (collect)
{
GC.Collect(); // Force GC to run and block until it finishes
}
AppendToTree(new Tree(), 3, 10); // Do some more allocations (3^10 = 59.049)
AppendToTree(new Tree(), 4, 7); // 4^10 = 1.048.576
AppendToTree(new Tree(), 5, 7); // 5^7 = 78.125
GC.Collect(); // Collect all the memory allocated in this method
}
----

Hardware configuration:

[source]
----
BenchmarkDotNet v0.14.0, Windows 10 (10.0.19045.5247/22H2/2022Update)
Intel Core Ultra 7 165H, 1 CPU, 22 logical and 16 physical cores
[Host] : .NET Framework 4.8.1 (4.8.9282.0), X64 RyuJIT VectorSize=256
.NET 9.0 : .NET 9.0.0 (9.0.24.52809), X64 RyuJIT AVX2
.NET Framework 4.8.1 : .NET Framework 4.8.1 (4.8.9282.0), X64 RyuJIT VectorSize=256
----

include::rspecator.adoc[]
38 changes: 37 additions & 1 deletion rules/S125/csharp/rule.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,40 @@
include::../rule.adoc[]
== Why is this an issue?

Commented-out code distracts the focus from the actual executed code. It creates a noise that increases maintenance code. And because it is never executed, it quickly becomes out of date and invalid.

Commented-out code should be deleted and can be retrieved from source control history if required.

== How to fix it

Delete the commented out code.

=== Code examples

==== Noncompliant code example

[source,csharp,diff-id=1,diff-type=noncompliant]
----
void Method(string s)
{
// if (s.StartsWith('A'))
// {
// s = s.Substring(1);
// }
// Do something...
}
----

==== Compliant solution

[source,csharp,diff-id=1,diff-type=compliant]
----
void Method(string s)
{
// Do something...
}
----


ifdef::env-github,rspecator-view[]

Expand Down
64 changes: 63 additions & 1 deletion rules/S1264/csharp/rule.adoc
Original file line number Diff line number Diff line change
@@ -1,4 +1,66 @@
include::../rule.adoc[]
== Why is this an issue?

Using a `for` loop without its typical structure (initialization, condition, increment) can be confusing. In those cases, it is better to use a `while` loop as it is more readable.

The initializer section should contain a variable declaration to be considered as a valid initialization.

== How to fix it

Replace the `for` loop with a `while` loop.

=== Code example

==== Noncompliant code example

[source,csharp,diff-id=1,diff-type=noncompliant]
----
for (;condition;) // Noncompliant; both the initializer and increment sections are missing
{
// Do something
}
----

==== Compliant solution

[source,csharp,diff-id=1,diff-type=compliant]
----
while (condition)
{
// Do something
}
----

==== Noncompliant code example

[source,csharp,diff-id=2,diff-type=noncompliant]
----
int i;
for (i = 0; i < 10;) // Noncompliant; the initializer section should contain a variable declaration
{
// Do something
i++;
}
----

==== Compliant solution

[source,csharp,diff-id=2,diff-type=compliant]
----
int i = 0;
while (i < 10)
{
// Do something
i++;
}
----

== Resources

=== Documentation

* Microsoft Learn - https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/iteration-statements#the-for-statement[The `for` statement]

ifdef::env-github,rspecator-view[]

Expand Down
2 changes: 1 addition & 1 deletion rules/S1542/vb6/rule.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ include::../description.adoc[]

=== Noncompliant code example

With default provided regular expression: ^([A-Z][a-zA-Z0-9_]*)|([a-z][a-zA-Z0-9]*_[A-Z][a-zA-Z]*)$
With default provided regular expression: ^([A-Z][a-zA-Z0-9_]\*)|([a-z][a-zA-Z0-9]*_[A-Z][a-zA-Z]*)$


[source,vb6]
Expand Down
Loading

0 comments on commit fb626bf

Please sign in to comment.