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

Add option 'roslynator_unity_code_analysis.enabled' #1245

Merged
merged 10 commits into from
Nov 10, 2023
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
3 changes: 3 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix refactoring [Inline method](https://josefpihrt.github.io/docs/roslynator/refactorings/RR0062) ([PR](https://github.com/dotnet/roslynator/pull/1234))
- [CLI] Fix globbing ([PR](https://github.com/dotnet/roslynator/pull/1238))
- [CLI] Remove assembly resolving ([PR](https://github.com/dotnet/roslynator/pull/1237))
- Detect false positive from Unity code ([RCS1169](https://josefpihrt.github.io/docs/roslynator/analyzers/RCS1169)) ([PR](https://github.com/dotnet/roslynator/pull/1245))
- Introduce config option `roslynator_unity_code_analysis.enabled = true|false`
- Make option `roslynator_suppress_unity_script_methods` obsolete

## [4.6.1] - 2023-10-23

Expand Down
4 changes: 4 additions & 0 deletions src/Analyzers.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5178,6 +5178,9 @@ abstract class Foo : IFoo
<Title>Make field read-only.</Title>
<DefaultSeverity>Info</DefaultSeverity>
<IsEnabledByDefault>true</IsEnabledByDefault>
<ConfigOptions>
<Option Key="unity_code_analysis.enabled" />
</ConfigOptions>
<Samples>
<Sample>
<Before><![CDATA[public class Foo
Expand Down Expand Up @@ -6117,6 +6120,7 @@ x = "";]]></Before>
<IsEnabledByDefault>true</IsEnabledByDefault>
<SupportsFadeOut>true</SupportsFadeOut>
<ConfigOptions>
<Option Key="unity_code_analysis.enabled" />
<Option Key="suppress_unity_script_methods" />
</ConfigOptions>
<Options>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions src/Analyzers/CSharp/Analysis/EnumSymbolAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<DiagnosticDescriptor> _supportedDiagnostics;

Expand Down Expand Up @@ -135,7 +136,9 @@ private static void AnalyzeTypeDeclaration(
&& fieldSymbol.DeclaredAccessibility == Accessibility.Private
&& !fieldSymbol.IsReadOnly
&& !fieldSymbol.IsVolatile
&& ValidateType(fieldSymbol.Type))
&& ValidateType(fieldSymbol.Type)
&& (context.IsUnityCodeAnalysisEnabled() != true
|| !fieldSymbol.HasAttribute(UnityEngine_SerializeFieldAttribute)))
{
symbols[fieldSymbol.Name] = (declarator, fieldSymbol);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context)
break;

if (declaration.ReturnsVoid()
&& context.GetSuppressUnityScriptMethods() == true)
&& context.IsUnityCodeAnalysisEnabled() == true)
{
if (canContainUnityScriptMethods is null)
{
Expand Down
11 changes: 7 additions & 4 deletions src/Common/CSharp/Extensions/CodeStyleExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -565,12 +565,15 @@ public static BlankLineStyle GetBlankLineAfterFileScopedNamespaceDeclaration(thi
return BlankLineStyle.None;
}

public static bool? GetSuppressUnityScriptMethods(this SyntaxNodeAnalysisContext context)
public static bool? IsUnityCodeAnalysisEnabled(this SyntaxNodeAnalysisContext context)
{
if (ConfigOptions.TryGetValueAsBool(context.GetConfigOptions(), ConfigOptions.SuppressUnityScriptMethods, out bool value))
{
if (ConfigOptions.TryGetValueAsBool(context.GetConfigOptions(), ConfigOptions.UnityCodeAnalysisEnabled, out bool value))
return value;
}

#pragma warning disable CS0618 // Type or member is obsolete
if (ConfigOptions.TryGetValueAsBool(context.GetConfigOptions(), ConfigOptions.SuppressUnityScriptMethods, out value))
return value;
#pragma warning restore CS0618 // Type or member is obsolete

if (context.TryGetOptionAsBool(LegacyConfigOptions.SuppressUnityScriptMethods, out value))
return value;
Expand Down
1 change: 1 addition & 0 deletions src/Common/ConfigOptionKeys.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ internal static partial class ConfigOptionKeys
public const string SuppressUnityScriptMethods = "roslynator_suppress_unity_script_methods";
public const string TabLength = "roslynator_tab_length";
public const string TrailingCommaStyle = "roslynator_trailing_comma_style";
public const string UnityCodeAnalysisEnabled = "roslynator_unity_code_analysis.enabled";
public const string UseAnonymousFunctionOrMethodGroup = "roslynator_use_anonymous_function_or_method_group";
public const string UseBlockBodyWhenDeclarationSpansOverMultipleLines = "roslynator_use_block_body_when_declaration_spans_over_multiple_lines";
public const string UseBlockBodyWhenExpressionSpansOverMultipleLines = "roslynator_use_block_body_when_expression_spans_over_multiple_lines";
Expand Down
10 changes: 9 additions & 1 deletion src/Common/ConfigOptions.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

// <auto-generated>

using System;
using System.Collections.Generic;

namespace Roslynator
Expand Down Expand Up @@ -176,11 +177,12 @@ 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,
defaultValuePlaceholder: "true|false",
description: "Suppress Unity script methods");
description: "[deprecated] This option is obsolete, use option 'roslynator_unity_code_analysis.enabled' instead.");

public static readonly ConfigOptionDescriptor TabLength = new(
key: ConfigOptionKeys.TabLength,
Expand All @@ -194,6 +196,12 @@ public static partial class ConfigOptions
defaultValuePlaceholder: "include|omit|omit_when_single_line",
description: "Include/omit trailing comma in initializer or enum");

public static readonly ConfigOptionDescriptor UnityCodeAnalysisEnabled = new(
key: ConfigOptionKeys.UnityCodeAnalysisEnabled,
defaultValue: null,
defaultValuePlaceholder: "true|false",
description: "Enable code analysis to detect Unity-specific code");

public static readonly ConfigOptionDescriptor UseAnonymousFunctionOrMethodGroup = new(
key: ConfigOptionKeys.UseAnonymousFunctionOrMethodGroup,
defaultValue: null,
Expand Down
9 changes: 7 additions & 2 deletions src/ConfigOptions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,14 @@
<ValuePlaceholder>true|false</ValuePlaceholder>
<Description>Prefix field identifier with underscore</Description>
</Option>
<Option Id="SuppressUnityScriptMethods">
<Option Id="SuppressUnityScriptMethods" IsObsolete="true">
<ValuePlaceholder>true|false</ValuePlaceholder>
<Description>Suppress Unity script methods</Description>
<Description>[deprecated] This option is obsolete, use option 'roslynator_unity_code_analysis.enabled' instead.</Description>
</Option>
<Option Id="UnityCodeAnalysisEnabled">
<Key>unity_code_analysis.enabled</Key>
<ValuePlaceholder>true|false</ValuePlaceholder>
<Description>Enable code analysis to detect Unity-specific code</Description>
</Option>
<Option Id="UseAnonymousFunctionOrMethodGroup">
<Description>Use anonymous function or method group</Description>
Expand Down
22 changes: 22 additions & 0 deletions src/Tests/Analyzers.Tests/RCS1169MakeFieldReadOnlyTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,26 @@ class C
}
");
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.MakeFieldReadOnly)]
public async Task TestNoDiagnostic_UnitySerializeAttribute()
{
await VerifyNoDiagnosticAsync(@"
using System;
using UnityEngine;

class C
{
[SerializeField]
private string f;
}

namespace UnityEngine
{
class SerializeFieldAttribute : Attribute
{
}
}
", options: Options.AddConfigOption(ConfigOptionKeys.UnityCodeAnalysisEnabled, true));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -366,4 +366,26 @@ class MonoBehaviour
}
", options: Options.AddConfigOption(ConfigOptionKeys.SuppressUnityScriptMethods, true));
}

[Fact, Trait(Traits.Analyzer, DiagnosticIdentifiers.RemoveUnusedMemberDeclaration)]
public async Task TestNoDiagnostic_UnityScriptMethods2()
{
await VerifyNoDiagnosticAsync(@"
using UnityEngine;

class C : MonoBehaviour
{
private void Awake()
{
}
}

namespace UnityEngine
{
class MonoBehaviour
{
}
}
", options: Options.AddConfigOption(ConfigOptionKeys.UnityCodeAnalysisEnabled, true));
}
}
5 changes: 3 additions & 2 deletions src/Tools/CodeGeneration/CSharp/CodeGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static class CodeGenerator
public static CompilationUnitSyntax GenerateConfigOptions(IEnumerable<AnalyzerOptionMetadata> options, IEnumerable<AnalyzerMetadata> analyzers)
{
CompilationUnitSyntax compilationUnit = CompilationUnit(
UsingDirectives("System.Collections.Generic"),
UsingDirectives("System", "System.Collections.Generic"),
NamespaceDeclaration(
"Roslynator",
ClassDeclaration(
Expand All @@ -38,7 +38,8 @@ public static CompilationUnitSyntax GenerateConfigOptions(IEnumerable<AnalyzerOp
Argument(NameColon("defaultValue"), (f.DefaultValue is not null) ? StringLiteralExpression(f.DefaultValue) : NullLiteralExpression()),
Argument(NameColon("defaultValuePlaceholder"), StringLiteralExpression(f.DefaultValuePlaceholder)),
Argument(NameColon("description"), StringLiteralExpression(f.Description))),
default(InitializerExpressionSyntax)));
default(InitializerExpressionSyntax)))
.AddObsoleteAttributeIf(f.IsObsolete);
})
.Concat(new MemberDeclarationSyntax[]
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ public static string GenerateEditorConfig(RoslynatorMetadata metadata, bool comm

var isSeparatedWithNewLine = true;

foreach (AnalyzerOptionMetadata option in metadata.ConfigOptions.OrderBy(f => f.Key))
foreach (AnalyzerOptionMetadata option in metadata.ConfigOptions
.Where(f => !f.IsObsolete)
.OrderBy(f => f.Key))
{
if (optionMap.TryGetValue(option.Key, out HashSet<AnalyzerMetadata> analyzers)
&& !isSeparatedWithNewLine)
Expand Down Expand Up @@ -86,6 +88,7 @@ public static string GenerateEditorConfig(RoslynatorMetadata metadata, bool comm
+ string.Join(
", ",
analyzer.ConfigOptions
.Where(f => metadata.ConfigOptions.FirstOrDefault(ff => ff.Key == f.Key)?.IsObsolete != true)
.OrderBy(f => f.Key)
.Select(f2 => metadata.ConfigOptions.First(f => f.Key == f2.Key).Key)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"profiles": {
"CodeGenerator": {
"commandName": "Project",
"commandLineArgs": "\"../../../../..\""
"commandLineArgs": "\"../../../../..\" \"../../../../../Tools/ConfigurationFileGenerator/configuration.md\" \"../../../../../../tools/build/configuration.md\""
}
}
}
2 changes: 1 addition & 1 deletion src/Tools/Metadata/AnalyzerOptionMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Roslynator.Metadata;

public record AnalyzerOptionMetadata(string Id, string Key, string DefaultValue, string DefaultValuePlaceholder, string Description)
public record AnalyzerOptionMetadata(string Id, string Key, string DefaultValue, string DefaultValuePlaceholder, string Description, bool IsObsolete)
{
public List<AnalyzerOptionValueMetadata> Values { get; } = new();
}
3 changes: 2 additions & 1 deletion src/Tools/Metadata/MetadataFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,8 @@ public static IEnumerable<AnalyzerOptionMetadata> ReadOptions(string filePath)
Key: "roslynator_" + key,
DefaultValue: defaultValue,
DefaultValuePlaceholder: defaultValuePlaceholder,
Description: element.Element("Description").Value
Description: element.Element("Description").Value,
IsObsolete: element.AttributeValueAsBooleanOrDefault("IsObsolete")
);

analyzerOption.Values.AddRange(values ?? Enumerable.Empty<AnalyzerOptionValueMetadata>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,16 @@ roslynator_analyzers.enabled_by_default = true|false

#roslynator_prefix_field_identifier_with_underscore = true|false

#roslynator_suppress_unity_script_methods = true|false
# Applicable to: rcs1213

#roslynator_tab_length = <NUM>
# Default: 4
# Applicable to: rcs0056

#roslynator_trailing_comma_style = include|omit|omit_when_single_line
# Applicable to: rcs1260

#roslynator_unity_code_analysis.enabled = true|false
# Applicable to: rcs1169, rcs1213

#roslynator_use_anonymous_function_or_method_group = anonymous_function|method_group
# Applicable to: rcs1207

Expand Down Expand Up @@ -641,6 +641,7 @@ roslynator_analyzers.enabled_by_default = true|false

# Make field read-only
#dotnet_diagnostic.rcs1169.severity = suggestion
# Options: roslynator_unity_code_analysis.enabled

# Use read-only auto-implemented property
#dotnet_diagnostic.rcs1170.severity = suggestion
Expand Down Expand Up @@ -762,7 +763,7 @@ roslynator_analyzers.enabled_by_default = true|false

# Remove unused member declaration
#dotnet_diagnostic.rcs1213.severity = suggestion
# Options: roslynator_suppress_unity_script_methods
# Options: roslynator_unity_code_analysis.enabled

# Unnecessary interpolated string
#dotnet_diagnostic.rcs1214.severity = suggestion
Expand Down