Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Suppress uninitialized DbSet warnings when a ctor is present #27869

Merged
merged 1 commit into from
Apr 26, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@
<MicrosoftExtensionsLoggingVersion>7.0.0-preview.4.22217.5</MicrosoftExtensionsLoggingVersion>
</PropertyGroup>
<PropertyGroup Label="Other dependencies">
<MicrosoftCodeAnalysisVersion>4.0.1</MicrosoftCodeAnalysisVersion>
<MicrosoftCodeAnalysisVersion>4.2.0-2.final</MicrosoftCodeAnalysisVersion>
</PropertyGroup>
</Project>
17 changes: 13 additions & 4 deletions src/EFCore.Analyzers/UninitializedDbSetDiagnosticSuppressor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,19 @@ public override void ReportSuppressions(SuppressionAnalysisContext context)
foreach (var diagnostic in context.ReportedDiagnostics)
{
// We have an warning about an uninitialized non-nullable property.
// Get the node, and make sure it's a property who's type syntactically contains DbSet (fast check before getting the
// semantic model, which is heavier).
if (diagnostic.Location.SourceTree is not { } sourceTree
|| sourceTree.GetRoot().FindNode(diagnostic.Location.SourceSpan) is not PropertyDeclarationSyntax propertyDeclarationSyntax

// CS8618 contains the location of the uninitialized property in AdditionalLocations; note that if the class has a constructor,
// the diagnostic main Location points to the constructor rather than to the uninitialized property.
// The AdditionalLocations was added in 7.0.0-preview.3, fall back to the main location just in case and older compiler is
// being used (the check below for PropertyDeclarationSyntax will filter out the diagnostic if it's pointing to a constructor).
var location = diagnostic.AdditionalLocations.Count > 0
? diagnostic.AdditionalLocations[0]
: diagnostic.Location;

// Get the node, and make sure it's a property whose type syntactically contains DbSet (fast check before getting the semantic
// model, which is heavier).
if (location.SourceTree is not { } sourceTree
|| sourceTree.GetRoot().FindNode(location.SourceSpan) is not PropertyDeclarationSyntax propertyDeclarationSyntax
|| !propertyDeclarationSyntax.Type.ToString().Contains("DbSet"))
{
continue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,57 @@ public class Blog
Assert.False(diagnostic.IsSuppressed);
}

[ConditionalFact]
public async Task DbSet_property_on_DbContext_with_ctor_is_suppressed()
{
var source = @"
public class MyDbContext : Microsoft.EntityFrameworkCore.DbContext
{
public MyDbContext() {}

public Microsoft.EntityFrameworkCore.DbSet<Blog> Blogs { get; set; }
}

public class Blog
{
public int Id { get; set; }
}";

var diagnostic = Assert.Single(await GetDiagnosticsFullSourceAsync(source));

Assert.Equal("CS8618", diagnostic.Id);
Assert.True(diagnostic.IsSuppressed);
}

[ConditionalFact]
public async Task DbSet_property_on_DbContext_with_ctors_is_suppressed()
{
var source = @"
public class MyDbContext : Microsoft.EntityFrameworkCore.DbContext
{
public MyDbContext() {}

public MyDbContext(int foo) {}

public Microsoft.EntityFrameworkCore.DbSet<Blog> Blogs { get; set; }
}

public class Blog
{
public int Id { get; set; }
}";

var diagnostics = await GetDiagnosticsFullSourceAsync(source);

Assert.All(
diagnostics,
diagnostic =>
{
Assert.Equal("CS8618", diagnostic.Id);
Assert.True(diagnostic.IsSuppressed);
});
}

protected Task<Diagnostic[]> GetDiagnosticsFullSourceAsync(string source)
=> base.GetDiagnosticsFullSourceAsync(source, analyzerDiagnosticsOnly: false);

Expand Down