Skip to content

Commit

Permalink
Check UsedImplicitlyAttribute (RCS1074) (dotnet#968)
Browse files Browse the repository at this point in the history
  • Loading branch information
josefpihrt authored and JochemHarmes committed Oct 30, 2023
1 parent 6875799 commit ed98184
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 15 deletions.
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [CLI] Include compiler diagnostics in the xml output file of the `roslynator analyze` command ([#964](https://github.com/JosefPihrt/Roslynator/pull/964) by @PeterKaszab).
- Do not simplify 'default' expression if the type is inferred ([RCS1244](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1244.md)) ([#966](https://github.com/josefpihrt/roslynator/pull/966).
- Use explicit type from lambda expression ([RCS1008](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1008.md)) ([#967](https://github.com/josefpihrt/roslynator/pull/967).
- Do not remove constructor if it is decorated with 'UsedImplicitlyAttribute' ([RCS1074](https://github.com/JosefPihrt/Roslynator/blob/main/docs/analyzers/RCS1074.md)) ([#968](https://github.com/josefpihrt/roslynator/pull/968).

-----
<!-- Content below does not adhere to 'Keep a Changelog' format -->
Expand Down
27 changes: 12 additions & 15 deletions src/Analyzers/CSharp/Analysis/RemoveRedundantConstructorAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
// Copyright (c) Josef Pihrt and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Roslynator.CSharp.Syntax;

namespace Roslynator.CSharp.Analysis
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class RemoveRedundantConstructorAnalyzer : BaseDiagnosticAnalyzer
{
private static readonly MetadataName _usedImplicitlyAttribute = MetadataName.Parse("JetBrains.Annotations.UsedImplicitlyAttribute");

private static ImmutableArray<DiagnosticDescriptor> _supportedDiagnostics;

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
Expand Down Expand Up @@ -63,27 +63,24 @@ private static void AnalyzeConstructorDeclaration(SyntaxNodeAnalysisContext cont
return;
}

if (!IsSingleInstanceConstructor(constructor))
if (constructor.HasDocumentationComment())
return;

if (constructor.HasDocumentationComment())
IMethodSymbol symbol = context.SemanticModel.GetDeclaredSymbol(constructor, context.CancellationToken);

if (symbol?.Kind != SymbolKind.Method)
return;

if (!constructor.DescendantTrivia(constructor.Span).All(f => f.IsWhitespaceOrEndOfLineTrivia()))
if (symbol.ContainingType.InstanceConstructors.SingleOrDefault(shouldThrow: false) != symbol)
return;

DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantConstructor, constructor);
}
if (symbol.HasAttribute(_usedImplicitlyAttribute))
return;

private static bool IsSingleInstanceConstructor(ConstructorDeclarationSyntax constructor)
{
MemberDeclarationListInfo info = SyntaxInfo.MemberDeclarationListInfo(constructor.Parent);
if (!constructor.DescendantTrivia(constructor.Span).All(f => f.IsWhitespaceOrEndOfLineTrivia()))
return;

return info.Success
&& info
.Members
.OfType<ConstructorDeclarationSyntax>()
.All(f => f.Equals(constructor) || f.Modifiers.Contains(SyntaxKind.StaticKeyword));
DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantConstructor, constructor);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Josef Pihrt and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Roslynator.CSharp.CodeFixes;
using Roslynator.Testing.CSharp;
using Xunit;

namespace Roslynator.CSharp.Analysis.Tests
{
public class RCS1074RemoveRedundantConstructorTests : AbstractCSharpDiagnosticVerifier<RemoveRedundantConstructorAnalyzer, ConstructorDeclarationCodeFixProvider>
{
public override DiagnosticDescriptor Descriptor { get; } = DiagnosticRules.RemoveRedundantConstructor;

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.RemoveRedundantConstructor)]
public async Task Test_SingleInstanceConstructor()
{
await VerifyDiagnosticAndFixAsync(@"
class C
{
[|public C()
{
}|]
}
", @"
class C
{
}
");
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.RemoveRedundantConstructor)]
public async Task TestNoDiagnostic_UsedImplicitlyAttribute()
{
await VerifyNoDiagnosticAsync(@"
class C
{
[JetBrains.Annotations.UsedImplicitly]
public C()
{
}
}
namespace JetBrains.Annotations
{
public class UsedImplicitlyAttribute : System.Attribute
{
}
}
");
}
}
}

0 comments on commit ed98184

Please sign in to comment.