Skip to content

Commit a0a053b

Browse files
authored
Enable NetAnalyzers reliability and globalization rules (#22625)
The following rules led to code changes: - CA2000: Dispose objects before losing scope - CA2012: Use ValueTasks correctly - CA2008: Do not create tasks without passing a TaskScheduler - CA2016: Forward the 'CancellationToken' parameter to methods that take one - CA1310: Specify StringComparison for correctness - CA1309: Use ordinal stringcomparison - CA1304: Specify CultureInfo Part of #18870
1 parent a9871fe commit a0a053b

File tree

55 files changed

+170
-164
lines changed

Some content is hidden

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

55 files changed

+170
-164
lines changed

Diff for: rulesets/FxCop.ruleset

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@
9595
<Rule Id="CA1829" Action="None" /> <!-- Use Length/Count property instead of Count() when available -->
9696
<Rule Id="CA2000" Action="None" /> <!-- Dispose objects before losing scope -->
9797
<Rule Id="CA2002" Action="None" /> <!-- Do not lock on objects with weak identity -->
98-
<Rule Id="CA2007" Action="Warning" /> <!-- Consider calling ConfigureAwait on the awaited task -->
98+
<Rule Id="CA2007" Action="None" /> <!-- Consider calling ConfigureAwait on the awaited task -->
9999
<Rule Id="CA2008" Action="None" /> <!-- Do not create tasks without passing a TaskScheduler -->
100100
<Rule Id="CA2009" Action="None" /> <!-- Do not call ToImmutableCollection on an ImmutableCollection value -->
101101
<Rule Id="CA2010" Action="None" /> <!-- Always consume the value returned by methods marked with PreserveSigAttribute -->

Diff for: src/.editorconfig

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# Code analysis rules and configuration
2+
3+
root = false
4+
5+
# Code files
6+
[*.cs]
7+
8+
# Globalization rules
9+
10+
# CA1303: Do not pass literals as localized parameters
11+
dotnet_diagnostic.CA1303.severity = none
12+
13+
# CA1304: Specify CultureInfo
14+
dotnet_diagnostic.CA1304.severity = error
15+
16+
# CA1305: Specify IFormatProvider
17+
dotnet_diagnostic.CA1305.severity = none
18+
19+
# CA1307: Specify StringComparison for clarity
20+
dotnet_diagnostic.CA1307.severity = none
21+
22+
# CA1308: Normalize strings to uppercase
23+
dotnet_diagnostic.CA1308.severity = none
24+
25+
# CA1309: Use ordinal stringcomparison
26+
dotnet_diagnostic.CA1309.severity = error
27+
28+
# CA1310: Specify StringComparison for correctness
29+
dotnet_diagnostic.CA1310.severity = error
30+
31+
# CA2101: Specify marshaling for P/Invoke string arguments
32+
dotnet_diagnostic.CA2101.severity = error
33+
34+
# Reliability Rules
35+
36+
# CA2000: Dispose objects before losing scope
37+
# Not reliable enough - false positives
38+
dotnet_diagnostic.CA2000.severity = suggestion
39+
40+
# CA2002: Do not lock on objects with weak identity
41+
dotnet_diagnostic.CA2002.severity = error
42+
43+
# CA2007: Consider calling ConfigureAwait on the awaited task
44+
dotnet_diagnostic.CA2007.severity = error
45+
46+
# CA2008: Do not create tasks without passing a TaskScheduler
47+
dotnet_diagnostic.CA2008.severity = error
48+
49+
# CA2009: Do not call ToImmutableCollection on an ImmutableCollection value
50+
dotnet_diagnostic.CA2009.severity = error
51+
52+
# CA2011: Avoid infinite recursion
53+
dotnet_diagnostic.CA2011.severity = error
54+
55+
# CA2012: Use ValueTasks correctly
56+
dotnet_diagnostic.CA2012.severity = error
57+
58+
# CA2013: Do not use ReferenceEquals with value types
59+
dotnet_diagnostic.CA2013.severity = error
60+
61+
# CA2014: Do not use stackalloc in loops
62+
dotnet_diagnostic.CA2014.severity = error
63+
64+
# CA2015: Do not define finalizers for types derived from MemoryManager<T>
65+
dotnet_diagnostic.CA2015.severity = error
66+
67+
# CA2016: Forward the 'CancellationToken' parameter to methods that take one
68+
dotnet_diagnostic.CA2016.severity = error

Diff for: src/Directory.Build.props

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<Import Project="..\Directory.Build.props" />
33

44
<PropertyGroup>
5+
<AnalysisLevel>latest</AnalysisLevel>
56
<IsPackable>True</IsPackable>
67
<IncludeSymbols>True</IncludeSymbols>
78
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)..\rulesets\EFCore.ruleset</CodeAnalysisRuleSet>

Diff for: src/EFCore.Analyzers/InternalUsageDiagnosticAnalyzer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ private static bool IsInInternalNamespace(ISymbol symbol)
325325
{
326326
if (symbol?.ContainingNamespace?.ToDisplayString() is string ns)
327327
{
328-
var i = ns.IndexOf("EntityFrameworkCore");
328+
var i = ns.IndexOf("EntityFrameworkCore", StringComparison.Ordinal);
329329

330330
return
331331
i != -1

Diff for: src/EFCore.Cosmos/Query/Internal/CosmosQueryableMethodTranslatingExpressionVisitor.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1159,7 +1159,8 @@ Expression GetPartitionKeyValue(BinaryExpression binaryExpression, IEntityType e
11591159

11601160
if (valueExpression is ConstantExpression
11611161
|| (valueExpression is ParameterExpression valueParameterExpression
1162-
&& valueParameterExpression.Name?.StartsWith(QueryCompilationContext.QueryParameterPrefix) == true))
1162+
&& valueParameterExpression.Name?
1163+
.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal) == true))
11631164
{
11641165
return valueExpression;
11651166
}

Diff for: src/EFCore.Cosmos/Query/Internal/CosmosShapedQueryCompilingExpressionVisitor.QueryingEnumerable.cs

+6-3
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,12 @@ public async ValueTask<bool> MoveNextAsync()
252252

253253
public ValueTask DisposeAsync()
254254
{
255-
_enumerator?.DisposeAsync();
256-
_enumerator = null;
257-
255+
var enumerator = _enumerator;
256+
if (enumerator != null)
257+
{
258+
_enumerator = null;
259+
return enumerator.DisposeAsync();
260+
}
258261
return default;
259262
}
260263
}

Diff for: src/EFCore.Cosmos/Query/Internal/KeyAccessExpression.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ public override bool Equals(object obj)
122122

123123
private bool Equals(KeyAccessExpression keyAccessExpression)
124124
=> base.Equals(keyAccessExpression)
125-
&& string.Equals(Name, keyAccessExpression.Name)
125+
&& Name == keyAccessExpression.Name
126126
&& AccessExpression.Equals(keyAccessExpression.AccessExpression);
127127

128128
/// <summary>

Diff for: src/EFCore.Cosmos/Query/Internal/ProjectionExpression.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,7 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter)
107107
Check.NotNull(expressionPrinter, nameof(expressionPrinter));
108108

109109
expressionPrinter.Visit(Expression);
110-
if (!string.Equals(string.Empty, Alias)
111-
&& !string.Equals(Alias, Name))
110+
if (Alias != string.Empty && Alias != Name)
112111
{
113112
expressionPrinter.Append(" AS " + Alias);
114113
}
@@ -127,7 +126,7 @@ public override bool Equals(object obj)
127126
&& Equals(projectionExpression));
128127

129128
private bool Equals(ProjectionExpression projectionExpression)
130-
=> string.Equals(Alias, projectionExpression.Alias)
129+
=> Alias == projectionExpression.Alias
131130
&& Expression.Equals(projectionExpression.Expression);
132131

133132
/// <summary>

Diff for: src/EFCore.Cosmos/Query/Internal/RootReferenceExpression.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public override bool Equals(object obj)
107107
&& Equals(rootReferenceExpression));
108108

109109
private bool Equals(RootReferenceExpression rootReferenceExpression)
110-
=> string.Equals(Alias, rootReferenceExpression.Alias)
110+
=> Alias == rootReferenceExpression.Alias
111111
&& EntityType.Equals(rootReferenceExpression.EntityType);
112112

113113
/// <summary>

Diff for: src/EFCore.Cosmos/Query/Internal/SqlFunctionExpression.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public override bool Equals(object obj)
134134

135135
private bool Equals(SqlFunctionExpression sqlFunctionExpression)
136136
=> base.Equals(sqlFunctionExpression)
137-
&& string.Equals(Name, sqlFunctionExpression.Name)
137+
&& Name == sqlFunctionExpression.Name
138138
&& Arguments.SequenceEqual(sqlFunctionExpression.Arguments);
139139

140140
/// <summary>

Diff for: src/EFCore.Cosmos/Query/Internal/SqlParameterExpression.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,7 @@ public override bool Equals(object obj)
8989
&& Equals(sqlParameterExpression));
9090

9191
private bool Equals(SqlParameterExpression sqlParameterExpression)
92-
=> base.Equals(sqlParameterExpression)
93-
&& string.Equals(Name, sqlParameterExpression.Name);
92+
=> base.Equals(sqlParameterExpression) && Name != sqlParameterExpression.Name;
9493

9594
/// <summary>
9695
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to

Diff for: src/EFCore.Cosmos/Storage/Internal/CosmosClientWrapper.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -565,8 +565,8 @@ private static JObject JObjectFromReadItemResponseMessage(ResponseMessage respon
565565
responseMessage.EnsureSuccessStatusCode();
566566

567567
var responseStream = responseMessage.Content;
568-
var reader = new StreamReader(responseStream);
569-
var jsonReader = new JsonTextReader(reader);
568+
using var reader = new StreamReader(responseStream);
569+
using var jsonReader = new JsonTextReader(reader);
570570

571571
var jObject = Serializer.Deserialize<JObject>(jsonReader);
572572

Diff for: src/EFCore.Relational/Extensions/RelationalTaskExtensions.cs

-64
This file was deleted.

Diff for: src/EFCore.Relational/Migrations/Internal/MigrationsModelDiffer.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -942,14 +942,12 @@ private static bool EntityTypePathEquals(IEntityType source, IEntityType target,
942942
return true;
943943
}
944944

945-
if (!string.Equals(source.Name, target.Name))
945+
if (source.Name != target.Name)
946946
{
947947
return false;
948948
}
949949

950-
if (!string.Equals(
951-
GetDefiningNavigationName(source),
952-
GetDefiningNavigationName(target)))
950+
if (GetDefiningNavigationName(source) != GetDefiningNavigationName(target))
953951
{
954952
return false;
955953
}

Diff for: src/EFCore.Relational/Query/QuerySqlGenerator.cs

+2-3
Original file line numberDiff line numberDiff line change
@@ -249,9 +249,8 @@ protected override Expression VisitProjection(ProjectionExpression projectionExp
249249

250250
Visit(projectionExpression.Expression);
251251

252-
if (!string.Equals(string.Empty, projectionExpression.Alias)
253-
&& !(projectionExpression.Expression is ColumnExpression column
254-
&& string.Equals(column.Name, projectionExpression.Alias)))
252+
if (projectionExpression.Alias != string.Empty
253+
&& !(projectionExpression.Expression is ColumnExpression column && column.Name == projectionExpression.Alias))
255254
{
256255
_relationalCommandBuilder.Append(AliasSeparator + _sqlGenerationHelper.DelimitIdentifier(projectionExpression.Alias));
257256
}

Diff for: src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ protected override Expression VisitExtension(Expression extensionExpression)
9393
fromSqlQueryRootExpression.EntityType,
9494
new FromSqlExpression(
9595
fromSqlQueryRootExpression.EntityType.GetDefaultMappings().SingleOrDefault().Table.Name.Substring(0, 1)
96-
.ToLower(),
96+
.ToLowerInvariant(),
9797
fromSqlQueryRootExpression.Sql,
9898
fromSqlQueryRootExpression.Argument)));
9999

@@ -1461,7 +1461,7 @@ private static IDictionary<IProperty, ColumnExpression> GetPropertyExpressionFro
14611461
tableExpression = selectExpression.Tables
14621462
.Select(t => (t as InnerJoinExpression)?.Table ?? (t as LeftJoinExpression)?.Table ?? t)
14631463
.Cast<TableExpression>()
1464-
.First(t => string.Equals(t.Name, table.Name) && string.Equals(t.Schema, table.Schema));
1464+
.First(t => t.Name == table.Name && t.Schema == table.Schema);
14651465
}
14661466

14671467
var propertyExpressions = new Dictionary<IProperty, ColumnExpression>();

Diff for: src/EFCore.Relational/Query/SqlExpressionFactory.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,7 @@ public virtual SelectExpression Select(IEntityType entityType, string sql, Expre
817817
Check.NotNull(sql, nameof(sql));
818818

819819
var tableExpression = new FromSqlExpression(
820-
entityType.GetDefaultMappings().SingleOrDefault().Table.Name.Substring(0, 1).ToLower(), sql, sqlArguments);
820+
entityType.GetDefaultMappings().SingleOrDefault().Table.Name.Substring(0, 1).ToLowerInvariant(), sql, sqlArguments);
821821
var selectExpression = new SelectExpression(entityType, tableExpression);
822822
AddConditions(selectExpression, entityType);
823823

Diff for: src/EFCore.Relational/Query/SqlExpressions/ColumnExpression.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public override bool Equals(object obj)
114114

115115
private bool Equals(ColumnExpression columnExpression)
116116
=> base.Equals(columnExpression)
117-
&& string.Equals(Name, columnExpression.Name)
117+
&& Name == columnExpression.Name
118118
&& Table.Equals(columnExpression.Table)
119119
&& IsNullable == columnExpression.IsNullable;
120120

Diff for: src/EFCore.Relational/Query/SqlExpressions/FromSqlExpression.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ public override bool Equals(object obj)
102102

103103
private bool Equals(FromSqlExpression fromSqlExpression)
104104
=> base.Equals(fromSqlExpression)
105-
&& string.Equals(Sql, fromSqlExpression.Sql)
105+
&& Sql == fromSqlExpression.Sql
106106
&& ExpressionEqualityComparer.Instance.Equals(Arguments, fromSqlExpression.Arguments);
107107

108108
/// <inheritdoc />

Diff for: src/EFCore.Relational/Query/SqlExpressions/ProjectionExpression.cs

+3-4
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ void IPrintableExpression.Print(ExpressionPrinter expressionPrinter)
7676
Check.NotNull(expressionPrinter, nameof(expressionPrinter));
7777

7878
expressionPrinter.Visit(Expression);
79-
if (!string.Equals(string.Empty, Alias)
79+
if (Alias != string.Empty
8080
&& !(Expression is ColumnExpression column
81-
&& string.Equals(column.Name, Alias)))
81+
&& column.Name == Alias))
8282
{
8383
expressionPrinter.Append(" AS " + Alias);
8484
}
@@ -92,8 +92,7 @@ public override bool Equals(object obj)
9292
&& Equals(projectionExpression));
9393

9494
private bool Equals(ProjectionExpression projectionExpression)
95-
=> string.Equals(Alias, projectionExpression.Alias)
96-
&& Expression.Equals(projectionExpression.Expression);
95+
=> Alias == projectionExpression.Alias && Expression.Equals(projectionExpression.Expression);
9796

9897
/// <inheritdoc />
9998
public override int GetHashCode()

Diff for: src/EFCore.Relational/Query/SqlExpressions/SqlFragmentExpression.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ public override bool Equals(object obj)
6161

6262
private bool Equals(SqlFragmentExpression sqlFragmentExpression)
6363
=> base.Equals(sqlFragmentExpression)
64-
&& string.Equals(Sql, sqlFragmentExpression.Sql)
65-
&& !string.Equals(Sql, "*"); // We make star projection different because it could be coming from different table.
64+
&& Sql == sqlFragmentExpression.Sql
65+
&& Sql != "*"; // We make star projection different because it could be coming from different table.
6666

6767
/// <inheritdoc />
6868
public override int GetHashCode()

Diff for: src/EFCore.Relational/Query/SqlExpressions/SqlFunctionExpression.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,8 @@ public override bool Equals(object obj)
379379

380380
private bool Equals(SqlFunctionExpression sqlFunctionExpression)
381381
=> base.Equals(sqlFunctionExpression)
382-
&& string.Equals(Name, sqlFunctionExpression.Name)
383-
&& string.Equals(Schema, sqlFunctionExpression.Schema)
382+
&& Name == sqlFunctionExpression.Name
383+
&& Schema == sqlFunctionExpression.Schema
384384
&& ((Instance == null && sqlFunctionExpression.Instance == null)
385385
|| (Instance != null && Instance.Equals(sqlFunctionExpression.Instance)))
386386
&& Arguments.SequenceEqual(sqlFunctionExpression.Arguments);

Diff for: src/EFCore.Relational/Query/SqlExpressions/SqlParameterExpression.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ public override bool Equals(object obj)
7474

7575
private bool Equals(SqlParameterExpression sqlParameterExpression)
7676
=> base.Equals(sqlParameterExpression)
77-
&& string.Equals(Name, sqlParameterExpression.Name);
77+
&& Name == sqlParameterExpression.Name;
7878

7979
/// <inheritdoc />
8080
public override int GetHashCode()

Diff for: src/EFCore.Relational/Query/SqlExpressions/TableExpression.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace Microsoft.EntityFrameworkCore.Query.SqlExpressions
2121
public sealed class TableExpression : TableExpressionBase
2222
{
2323
internal TableExpression([NotNull] ITableBase table)
24-
: base(table.Name.Substring(0, 1).ToLower())
24+
: base(table.Name.Substring(0, 1).ToLowerInvariant())
2525
{
2626
Name = table.Name;
2727
Schema = table.Schema;

Diff for: src/EFCore.Relational/Query/SqlExpressions/TableExpressionBase.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public override bool Equals(object obj)
6969
&& Equals(tableExpressionBase));
7070

7171
private bool Equals(TableExpressionBase tableExpressionBase)
72-
=> string.Equals(Alias, tableExpressionBase.Alias);
72+
=> Alias == tableExpressionBase.Alias;
7373

7474
/// <inheritdoc />
7575
public override int GetHashCode()

0 commit comments

Comments
 (0)