Skip to content

Commit ac58f45

Browse files
committed
Implement SA0002 (InvalidSettingsFile)
Fixes #2029
1 parent 9e71f5d commit ac58f45

8 files changed

Lines changed: 191 additions & 3 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers
5+
{
6+
using Newtonsoft.Json;
7+
using StyleCop.Analyzers.Settings.ObjectModel;
8+
9+
/// <summary>
10+
/// Defines the behavior of various <see cref="SettingsHelper"/> methods in the event of a deserialization error.
11+
/// </summary>
12+
internal enum DeserializationFailureBehavior
13+
{
14+
/// <summary>
15+
/// When deserialization fails, return a default <see cref="StyleCopSettings"/> instance.
16+
/// </summary>
17+
ReturnDefaultSettings,
18+
19+
/// <summary>
20+
/// When deserialization fails, throw a <see cref="JsonException"/> containing details about the error.
21+
/// </summary>
22+
ThrowException
23+
}
24+
}

StyleCop.Analyzers/StyleCop.Analyzers/Settings/SettingsHelper.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ static SettingsHelper()
4141
/// <summary>
4242
/// Gets the StyleCop settings.
4343
/// </summary>
44+
/// <remarks>
45+
/// <para>If a <see cref="JsonException"/> occurs while deserializing the settings file, a default settings
46+
/// instance is returned.</para>
47+
/// </remarks>
4448
/// <param name="context">The context that will be used to determine the StyleCop settings.</param>
4549
/// <param name="cancellationToken">The cancellation token that the operation will observe.</param>
4650
/// <returns>A <see cref="StyleCopSettings"/> instance that represents the StyleCop settings for the given context.</returns>
@@ -52,15 +56,32 @@ internal static StyleCopSettings GetStyleCopSettings(this SyntaxTreeAnalysisCont
5256
/// <summary>
5357
/// Gets the StyleCop settings.
5458
/// </summary>
59+
/// <remarks>
60+
/// <para>If a <see cref="JsonException"/> occurs while deserializing the settings file, a default settings
61+
/// instance is returned.</para>
62+
/// </remarks>
5563
/// <param name="options">The analyzer options that will be used to determine the StyleCop settings.</param>
5664
/// <param name="cancellationToken">The cancellation token that the operation will observe.</param>
5765
/// <returns>A <see cref="StyleCopSettings"/> instance that represents the StyleCop settings for the given context.</returns>
5866
internal static StyleCopSettings GetStyleCopSettings(this AnalyzerOptions options, CancellationToken cancellationToken)
5967
{
60-
return GetStyleCopSettings(options != null ? options.AdditionalFiles : ImmutableArray.Create<AdditionalText>(), cancellationToken);
68+
return GetStyleCopSettings(options, DeserializationFailureBehavior.ReturnDefaultSettings, cancellationToken);
6169
}
6270

63-
private static StyleCopSettings GetStyleCopSettings(ImmutableArray<AdditionalText> additionalFiles, CancellationToken cancellationToken)
71+
/// <summary>
72+
/// Gets the StyleCop settings.
73+
/// </summary>
74+
/// <param name="options">The analyzer options that will be used to determine the StyleCop settings.</param>
75+
/// <param name="failureBehavior">The behavior of the method when a <see cref="JsonException"/> occurs while
76+
/// deserializing the settings file.</param>
77+
/// <param name="cancellationToken">The cancellation token that the operation will observe.</param>
78+
/// <returns>A <see cref="StyleCopSettings"/> instance that represents the StyleCop settings for the given context.</returns>
79+
internal static StyleCopSettings GetStyleCopSettings(this AnalyzerOptions options, DeserializationFailureBehavior failureBehavior, CancellationToken cancellationToken)
80+
{
81+
return GetStyleCopSettings(options != null ? options.AdditionalFiles : ImmutableArray.Create<AdditionalText>(), failureBehavior, cancellationToken);
82+
}
83+
84+
private static StyleCopSettings GetStyleCopSettings(ImmutableArray<AdditionalText> additionalFiles, DeserializationFailureBehavior failureBehavior, CancellationToken cancellationToken)
6485
{
6586
try
6687
{
@@ -74,7 +95,7 @@ private static StyleCopSettings GetStyleCopSettings(ImmutableArray<AdditionalTex
7495
}
7596
}
7697
}
77-
catch (JsonException)
98+
catch (JsonException) when (failureBehavior == DeserializationFailureBehavior.ReturnDefaultSettings)
7899
{
79100
// The settings file is invalid -> return the default settings.
80101
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
2+
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
3+
4+
namespace StyleCop.Analyzers.SpecialRules
5+
{
6+
using System;
7+
using System.Collections.Immutable;
8+
using System.Globalization;
9+
using Microsoft.CodeAnalysis;
10+
using Microsoft.CodeAnalysis.Diagnostics;
11+
using Newtonsoft.Json;
12+
13+
/// <summary>
14+
/// The <em>stylecop.json</em> settings file could not be loaded due to a deserialization failure.
15+
/// </summary>
16+
[NoCodeFix("No automatic code fix is possible for general JSON syntax errors.")]
17+
[DiagnosticAnalyzer(LanguageNames.CSharp)]
18+
internal class SA0002InvalidSettingsFile : DiagnosticAnalyzer
19+
{
20+
/// <summary>
21+
/// The ID for diagnostics produced by the <see cref="SA0002InvalidSettingsFile"/> analyzer.
22+
/// </summary>
23+
public const string DiagnosticId = "SA0002";
24+
private const string HelpLink = "https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/SA0002.md";
25+
private static readonly LocalizableString Title = new LocalizableResourceString(nameof(SpecialResources.SA0002Title), SpecialResources.ResourceManager, typeof(SpecialResources));
26+
private static readonly LocalizableString MessageFormat = new LocalizableResourceString(nameof(SpecialResources.SA0002MessageFormat), SpecialResources.ResourceManager, typeof(SpecialResources));
27+
private static readonly LocalizableString Description = new LocalizableResourceString(nameof(SpecialResources.SA0002Description), SpecialResources.ResourceManager, typeof(SpecialResources));
28+
29+
private static readonly DiagnosticDescriptor Descriptor =
30+
new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.SpecialRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, Description, HelpLink);
31+
32+
private static readonly Action<CompilationAnalysisContext> CompilationAction = HandleCompilation;
33+
34+
/// <inheritdoc/>
35+
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
36+
ImmutableArray.Create(Descriptor);
37+
38+
/// <inheritdoc/>
39+
public override void Initialize(AnalysisContext context)
40+
{
41+
context.RegisterCompilationAction(CompilationAction);
42+
}
43+
44+
private static void HandleCompilation(CompilationAnalysisContext context)
45+
{
46+
try
47+
{
48+
SettingsHelper.GetStyleCopSettings(context.Options, DeserializationFailureBehavior.ThrowException, context.CancellationToken);
49+
}
50+
catch (JsonException ex)
51+
{
52+
string details = ex.ToString();
53+
string completeDescription = string.Format(Description.ToString(CultureInfo.CurrentCulture), details);
54+
55+
var completeDescriptor = new DiagnosticDescriptor(DiagnosticId, Title, MessageFormat, AnalyzerCategory.SpecialRules, DiagnosticSeverity.Warning, AnalyzerConstants.EnabledByDefault, completeDescription, HelpLink);
56+
context.ReportDiagnostic(Diagnostic.Create(completeDescriptor, Location.None));
57+
}
58+
}
59+
}
60+
}

StyleCop.Analyzers/StyleCop.Analyzers/SpecialRules/SpecialResources.Designer.cs

Lines changed: 29 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

StyleCop.Analyzers/StyleCop.Analyzers/SpecialRules/SpecialResources.resx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,4 +142,15 @@ Note that some situations are not affected by the bug:
142142
<data name="SA0001Title" xml:space="preserve">
143143
<value>XML comment analysis disabled</value>
144144
</data>
145+
<data name="SA0002Description" xml:space="preserve">
146+
<value>Various errors in the stylecop.json file can prevent the file from being loaded by the analyzers. In this case, the default settings are used instead.
147+
148+
{0}</value>
149+
</data>
150+
<data name="SA0002MessageFormat" xml:space="preserve">
151+
<value>The stylecop.json settings file could not be loaded</value>
152+
</data>
153+
<data name="SA0002Title" xml:space="preserve">
154+
<value>Invalid settings file</value>
155+
</data>
145156
</root>

StyleCop.Analyzers/StyleCop.Analyzers/StyleCop.Analyzers.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@
267267
<Compile Include="ReadabilityRules\SA1133DoNotCombineAttributes.cs" />
268268
<Compile Include="ReadabilityRules\SA1134AttributesMustNotShareLine.cs" />
269269
<Compile Include="ReadabilityRules\SX1101DoNotPrefixLocalMembersWithThis.cs" />
270+
<Compile Include="Settings\DeserializationFailureBehavior.cs" />
270271
<Compile Include="Settings\ObjectModel\DocumentationSettings.cs" />
271272
<Compile Include="Settings\ObjectModel\EndOfFileHandling.cs" />
272273
<Compile Include="Settings\ObjectModel\FileNamingConvention.cs" />
@@ -323,6 +324,7 @@
323324
<Compile Include="SpacingRules\TokenSpacingProperties.cs" />
324325
<Compile Include="SpecialRules\SA0000Roslyn7446Workaround.cs" />
325326
<Compile Include="SpecialRules\SA0001XmlCommentAnalysisDisabled.cs" />
327+
<Compile Include="SpecialRules\SA0002InvalidSettingsFile.cs" />
326328
<Compile Include="SpecialRules\SpecialResources.Designer.cs">
327329
<AutoGen>True</AutoGen>
328330
<DesignTime>True</DesignTime>

StyleCopAnalyzers.sln

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "documentation", "documentat
3939
documentation\KnownChanges.md = documentation\KnownChanges.md
4040
documentation\SA0000Roslyn7446Workaround.md = documentation\SA0000Roslyn7446Workaround.md
4141
documentation\SA0001.md = documentation\SA0001.md
42+
documentation\SA0002.md = documentation\SA0002.md
4243
documentation\SA1000.md = documentation\SA1000.md
4344
documentation\SA1001.md = documentation\SA1001.md
4445
documentation\SA1002.md = documentation\SA1002.md

documentation/SA0002.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# SA0002
2+
3+
<table>
4+
<tr>
5+
<td>TypeName</td>
6+
<td>SA0002InvalidSettingsFile</td>
7+
</tr>
8+
<tr>
9+
<td>CheckId</td>
10+
<td>SA0002</td>
11+
</tr>
12+
<tr>
13+
<td>Category</td>
14+
<td>Special Rules</td>
15+
</tr>
16+
</table>
17+
18+
:memo: This rule is new for StyleCop Analyzers, and was not present in StyleCop Classic.
19+
20+
## Cause
21+
22+
The <em>stylecop.json</em> settings file could not be loaded due to a deserialization error.
23+
24+
## Rule description
25+
26+
This rule reports cases where the StyleCop Analyzers settings file could not be loaded. When this occurs, the various
27+
analyzers automatically fall back to using the default settings, which may not match the user's expectations.
28+
29+
## How to fix violations
30+
31+
To fix a violation of this rule, start by checking the following items:
32+
33+
* Ensure <em>stylecop.json</em> contains valid JSON syntax. The file may be opened in Visual Studio 2015 to check for
34+
common errors (they are reported by the IDE in the Errors window).
35+
* Review the [configuration](Configuration.md) documentation and ensure the contents of <em>stylecop.json</em> contain
36+
valid settings.
37+
38+
## How to suppress violations
39+
40+
This warning can only be suppressed by disabling the warning in the **ruleset** file for the project.

0 commit comments

Comments
 (0)