From 4e589f9ccf654f8a4ccd02176eeba148c1356377 Mon Sep 17 00:00:00 2001 From: Josef Pihrt Date: Fri, 10 Nov 2023 17:39:21 +0100 Subject: [PATCH 01/10] Add option 'detect_unity_features' --- src/Analyzers.xml | 4 ++++ .../AnalyzerOptionIsObsoleteAnalyzer.cs | 2 ++ .../CSharp/Analysis/EnumSymbolAnalyzer.cs | 2 ++ .../MakeMemberReadOnlyAnalyzer.cs | 5 ++++- .../UnusedMember/UnusedMemberAnalyzer.cs | 2 +- .../CSharp/Extensions/CodeStyleExtensions.cs | 13 +++++++++-- src/Common/ConfigOptionKeys.Generated.cs | 1 + src/Common/ConfigOptions.Generated.cs | 8 +++++++ src/ConfigOptions.xml | 5 +++++ .../RCS1169MakeFieldReadOnlyTests.cs | 22 +++++++++++++++++++ ...S1213RemoveUnusedMemberDeclarationTests.cs | 22 +++++++++++++++++++ .../CodeGeneration/CSharp/CodeGenerator.cs | 5 +++-- .../EditorConfig/EditorConfigGenerator.cs | 4 +++- .../Markdown/MarkdownGenerator.cs | 9 ++++++-- src/Tools/Metadata/AnalyzerOptionMetadata.cs | 4 +++- src/Tools/Metadata/MetadataFile.cs | 3 ++- .../src/configurationFiles.generated.ts | 9 ++++---- 17 files changed, 105 insertions(+), 15 deletions(-) diff --git a/src/Analyzers.xml b/src/Analyzers.xml index e8035a66a9..12fc3a0911 100644 --- a/src/Analyzers.xml +++ b/src/Analyzers.xml @@ -5178,6 +5178,9 @@ abstract class Foo : IFoo Make field read-only. Info true + + true true + diff --git a/src/Analyzers/CSharp/Analysis/AnalyzerOptionIsObsoleteAnalyzer.cs b/src/Analyzers/CSharp/Analysis/AnalyzerOptionIsObsoleteAnalyzer.cs index 0baeb0c4a0..daf2669f50 100644 --- a/src/Analyzers/CSharp/Analysis/AnalyzerOptionIsObsoleteAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/AnalyzerOptionIsObsoleteAnalyzer.cs @@ -52,7 +52,9 @@ public override void Initialize(AnalysisContext context) Validate(ref context, compilationOptions, options, Flags.RemoveEmptyLineBetweenClosingBraceAndSwitchSection, ref flags, DiagnosticRules.RemoveUnnecessaryBlankLine, ConfigOptions.BlankLineBetweenClosingBraceAndSwitchSection, LegacyConfigOptions.RemoveEmptyLineBetweenClosingBraceAndSwitchSection, "false"); Validate(ref context, compilationOptions, options, Flags.RemoveParenthesesFromConditionOfConditionalExpressionWhenExpressionIsSingleToken, ref flags, DiagnosticRules.AddOrRemoveParenthesesFromConditionInConditionalOperator, ConfigOptions.ConditionalOperatorConditionParenthesesStyle, LegacyConfigOptions.RemoveParenthesesFromConditionOfConditionalExpressionWhenExpressionIsSingleToken, ConfigOptionValues.ConditionalOperatorConditionParenthesesStyle_OmitWhenConditionIsSingleToken); Validate(ref context, compilationOptions, options, Flags.RemoveParenthesesWhenCreatingNewObject, ref flags, DiagnosticRules.UseImplicitOrExplicitObjectCreation, ConfigOptions.ObjectCreationParenthesesStyle, LegacyConfigOptions.RemoveParenthesesWhenCreatingNewObject, ConfigOptionValues.ObjectCreationParenthesesStyle_Omit); +#pragma warning disable CS0618 // Type or member is obsolete Validate(ref context, compilationOptions, options, Flags.SuppressUnityScriptMethods, ref flags, DiagnosticRules.RemoveUnusedMemberDeclaration, ConfigOptions.SuppressUnityScriptMethods, LegacyConfigOptions.SuppressUnityScriptMethods, "true"); +#pragma warning restore CS0618 // Type or member is obsolete Validate(ref context, compilationOptions, options, Flags.UseComparisonInsteadPatternMatchingToCheckForNull, ref flags, DiagnosticRules.NormalizeNullCheck, ConfigOptions.NullCheckStyle, LegacyConfigOptions.UseComparisonInsteadPatternMatchingToCheckForNull, ConfigOptionValues.NullCheckStyle_EqualityOperator); Validate(ref context, compilationOptions, options, Flags.UseImplicitlyTypedArray, ref flags, DiagnosticRules.UseExplicitlyOrImplicitlyTypedArray, ConfigOptions.ArrayCreationTypeStyle, LegacyConfigOptions.UseImplicitlyTypedArray, ConfigOptionValues.ArrayCreationTypeStyle_Implicit); Validate(ref context, compilationOptions, options, Flags.UseImplicitlyTypedArrayWhenTypeIsObvious, ref flags, DiagnosticRules.UseExplicitlyOrImplicitlyTypedArray, ConfigOptions.ArrayCreationTypeStyle, LegacyConfigOptions.UseImplicitlyTypedArrayWhenTypeIsObvious, ConfigOptionValues.ArrayCreationTypeStyle_ImplicitWhenTypeIsObvious); diff --git a/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs b/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs index 5bad422e50..b3a17d513d 100644 --- a/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs @@ -198,7 +198,9 @@ private static void AnalyzeNamedType(SymbolAnalysisContext context) if (CSharpUtility.IsSymbolObsolete(symbolInfo1.Symbol) || CSharpUtility.IsSymbolObsolete(symbolInfo2.Symbol)) + { continue; + } var enumMember1 = (EnumMemberDeclarationSyntax)symbolInfo1.Symbol.GetSyntax(context.CancellationToken); diff --git a/src/Analyzers/CSharp/Analysis/MakeMemberReadOnly/MakeMemberReadOnlyAnalyzer.cs b/src/Analyzers/CSharp/Analysis/MakeMemberReadOnly/MakeMemberReadOnlyAnalyzer.cs index 33a15900a2..5b147fa260 100644 --- a/src/Analyzers/CSharp/Analysis/MakeMemberReadOnly/MakeMemberReadOnlyAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/MakeMemberReadOnly/MakeMemberReadOnlyAnalyzer.cs @@ -18,6 +18,7 @@ public sealed class MakeMemberReadOnlyAnalyzer : BaseDiagnosticAnalyzer private static readonly MetadataName Microsoft_AspNetCore_Components_CascadingParameterAttribute = MetadataName.Parse("Microsoft.AspNetCore.Components.CascadingParameterAttribute"); private static readonly MetadataName Microsoft_AspNetCore_Components_InjectAttribute = MetadataName.Parse("Microsoft.AspNetCore.Components.InjectAttribute"); private static readonly MetadataName Newtonsoft_Json_JsonPropertyAttribute = MetadataName.Parse("Newtonsoft.Json.JsonPropertyAttribute"); + private static readonly MetadataName UnityEngine_SerializeFieldAttribute = MetadataName.Parse("UnityEngine.SerializeFieldAttribute"); private static ImmutableArray _supportedDiagnostics; @@ -135,7 +136,9 @@ private static void AnalyzeTypeDeclaration( && fieldSymbol.DeclaredAccessibility == Accessibility.Private && !fieldSymbol.IsReadOnly && !fieldSymbol.IsVolatile - && ValidateType(fieldSymbol.Type)) + && ValidateType(fieldSymbol.Type) + && (context.DetectUnityFeatures() != true + || !fieldSymbol.HasAttribute(UnityEngine_SerializeFieldAttribute))) { symbols[fieldSymbol.Name] = (declarator, fieldSymbol); } diff --git a/src/Analyzers/CSharp/Analysis/UnusedMember/UnusedMemberAnalyzer.cs b/src/Analyzers/CSharp/Analysis/UnusedMember/UnusedMemberAnalyzer.cs index ac7d03fc19..b3e2041b27 100644 --- a/src/Analyzers/CSharp/Analysis/UnusedMember/UnusedMemberAnalyzer.cs +++ b/src/Analyzers/CSharp/Analysis/UnusedMember/UnusedMemberAnalyzer.cs @@ -159,7 +159,7 @@ private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context) break; if (declaration.ReturnsVoid() - && context.GetSuppressUnityScriptMethods() == true) + && context.DetectUnityFeatures() == true) { if (canContainUnityScriptMethods is null) { diff --git a/src/Common/CSharp/Extensions/CodeStyleExtensions.cs b/src/Common/CSharp/Extensions/CodeStyleExtensions.cs index 3e7f82fbac..222937b118 100644 --- a/src/Common/CSharp/Extensions/CodeStyleExtensions.cs +++ b/src/Common/CSharp/Extensions/CodeStyleExtensions.cs @@ -565,12 +565,11 @@ public static BlankLineStyle GetBlankLineAfterFileScopedNamespaceDeclaration(thi return BlankLineStyle.None; } + [Obsolete] public static bool? GetSuppressUnityScriptMethods(this SyntaxNodeAnalysisContext context) { if (ConfigOptions.TryGetValueAsBool(context.GetConfigOptions(), ConfigOptions.SuppressUnityScriptMethods, out bool value)) - { return value; - } if (context.TryGetOptionAsBool(LegacyConfigOptions.SuppressUnityScriptMethods, out value)) return value; @@ -578,6 +577,16 @@ public static BlankLineStyle GetBlankLineAfterFileScopedNamespaceDeclaration(thi return null; } + public static bool? DetectUnityFeatures(this SyntaxNodeAnalysisContext context) + { + if (ConfigOptions.TryGetValueAsBool(context.GetConfigOptions(), ConfigOptions.DetectUnityFeatures, out bool value)) + return value; + +#pragma warning disable CS0612 // Type or member is obsolete + return GetSuppressUnityScriptMethods(context); +#pragma warning restore CS0612 // Type or member is obsolete + } + public static NewLinePosition GetEqualsSignNewLinePosition(this SyntaxNodeAnalysisContext context) { return context.GetConfigOptions().GetEqualsTokenNewLinePosition(); diff --git a/src/Common/ConfigOptionKeys.Generated.cs b/src/Common/ConfigOptionKeys.Generated.cs index a35b9675c2..b5b56ea9c4 100644 --- a/src/Common/ConfigOptionKeys.Generated.cs +++ b/src/Common/ConfigOptionKeys.Generated.cs @@ -20,6 +20,7 @@ internal static partial class ConfigOptionKeys public const string ConditionalOperatorConditionParenthesesStyle = "roslynator_conditional_operator_condition_parentheses_style"; public const string ConditionalOperatorNewLine = "roslynator_conditional_operator_new_line"; public const string ConfigureAwait = "roslynator_configure_await"; + public const string DetectUnityFeatures = "roslynator_detect_unity_features"; public const string DocCommentSummaryStyle = "roslynator_doc_comment_summary_style"; public const string EmptyStringStyle = "roslynator_empty_string_style"; public const string EnumFlagValueStyle = "roslynator_enum_flag_value_style"; diff --git a/src/Common/ConfigOptions.Generated.cs b/src/Common/ConfigOptions.Generated.cs index 82c5cd06f0..6fc94adf3f 100644 --- a/src/Common/ConfigOptions.Generated.cs +++ b/src/Common/ConfigOptions.Generated.cs @@ -2,6 +2,7 @@ // +using System; using System.Collections.Generic; namespace Roslynator @@ -92,6 +93,12 @@ public static partial class ConfigOptions defaultValuePlaceholder: "true|false", description: "Add/remove 'ConfigureAwait(false)' call"); + public static readonly ConfigOptionDescriptor DetectUnityFeatures = new( + key: ConfigOptionKeys.DetectUnityFeatures, + defaultValue: null, + defaultValuePlaceholder: "true|false", + description: "Detect false positives from Unity code"); + public static readonly ConfigOptionDescriptor DocCommentSummaryStyle = new( key: ConfigOptionKeys.DocCommentSummaryStyle, defaultValue: null, @@ -176,6 +183,7 @@ public static partial class ConfigOptions defaultValuePlaceholder: "true|false", description: "Prefix field identifier with underscore"); + [Obsolete("", error: false)] public static readonly ConfigOptionDescriptor SuppressUnityScriptMethods = new( key: ConfigOptionKeys.SuppressUnityScriptMethods, defaultValue: null, diff --git a/src/ConfigOptions.xml b/src/ConfigOptions.xml index f8fa222c1e..459df38dea 100644 --- a/src/ConfigOptions.xml +++ b/src/ConfigOptions.xml @@ -173,6 +173,11 @@ +