From ed98184eef5a6c8958422e13af65397de87186ff Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Mon, 17 Oct 2022 23:49:17 +0200 Subject: [PATCH] Check UsedImplicitlyAttribute (RCS1074) (#968) --- ChangeLog.md | 1 + .../RemoveRedundantConstructorAnalyzer.cs | 27 +++++----- .../RCS1074RemoveRedundantConstructorTests.cs | 53 +++++++++++++++++++ 3 files changed, 66 insertions(+), 15 deletions(-) create mode 100644 src/Tests/Analyzers.Tests/RCS1074RemoveRedundantConstructorTests.cs diff --git a/ChangeLog.md b/ChangeLog.md index 5a1163134a..7b86e70ae0 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -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). ----- diff --git a/src/Analyzers/CSharp/Analysis/RemoveRedundantConstructorAnalyzer.cs b/src/Analyzers/CSharp/Analysis/RemoveRedundantConstructorAnalyzer.cs index e26bd808ca..7b32baa61c 100644 --- a/src/Analyzers/CSharp/Analysis/RemoveRedundantConstructorAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/RemoveRedundantConstructorAnalyzer.cs @@ -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 _supportedDiagnostics; public override ImmutableArray SupportedDiagnostics @@ -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() - .All(f => f.Equals(constructor) || f.Modifiers.Contains(SyntaxKind.StaticKeyword)); + DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantConstructor, constructor); } } } diff --git a/src/Tests/Analyzers.Tests/RCS1074RemoveRedundantConstructorTests.cs b/src/Tests/Analyzers.Tests/RCS1074RemoveRedundantConstructorTests.cs new file mode 100644 index 0000000000..10617e0ba3 --- /dev/null +++ b/src/Tests/Analyzers.Tests/RCS1074RemoveRedundantConstructorTests.cs @@ -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 + { + 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 + { + } +} +"); + } + } +}