Skip to content

Commit

Permalink
Add MA0087
Browse files Browse the repository at this point in the history
  • Loading branch information
meziantou committed Jul 29, 2020
1 parent 85fd606 commit ef142d8
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 3 deletions.
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,4 @@
|[MA0084](Rules/MA0084.md)|Design|Local variable should not hide other symbols|<span title='Warning'>⚠️</span>|✔️||
|[MA0085](Rules/MA0085.md)|Usage|Anonymous delegates should not be used to unsubscribe from Events|<span title='Warning'>⚠️</span>|✔️||
|[MA0086](Rules/MA0086.md)|Design|Do not throw from a destructor|<span title='Warning'>⚠️</span>|✔️||
|[MA0087](Rules/MA0087.md)|Design|Parameters with [DefaultParameterValue] attributes should also be marked [Optional]|<span title='Warning'>⚠️</span>|✔️||
2 changes: 1 addition & 1 deletion docs/Rules/MA0084.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ class Test
string a; // not-compliant as it hides the field
}
}
````
````
2 changes: 1 addition & 1 deletion docs/Rules/MA0085.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
````c#
MyEvent += (sender, e) => { }
MyEvent -= (sender, e) => { }; // Non-compliant as it doesn't actually remove the handler
````
````
2 changes: 1 addition & 1 deletion docs/Rules/MA0086.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ class Test
throw new Exception(); // non-compliant
}
}
````
````
15 changes: 15 additions & 0 deletions docs/Rules/MA0087.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# MA0087 - Parameters with [DefaultParameterValue] attributes should also be marked [Optional]

````csharp
using System.Runtime.InteropServices;
class Test
{
void A([Optional, DefaultParameterValue(10)]int a)
{
}

void B([DefaultParameterValue(10)]int a) // Non-compliant
{
}
}
````
1 change: 1 addition & 0 deletions src/Meziantou.Analyzer/RuleIdentifiers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ internal static class RuleIdentifiers
public const string LocalVariablesShouldNotHideSymbols = "MA0084";
public const string AnonymousDelegatesShouldNotBeUsedToUnsubscribeFromEvents = "MA0085";
public const string DoNotThrowFromDestructor = "MA0086";
public const string ParametersWithDefaultValueShouldBeMarkedWithOptionalParameter = "MA0087";

public static string GetHelpUri(string idenfifier)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;

namespace Meziantou.Analyzer.Rules
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class OptionalParametersAttributeAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor s_rule = new DiagnosticDescriptor(
RuleIdentifiers.ParametersWithDefaultValueShouldBeMarkedWithOptionalParameter,
title: "Parameters with [DefaultParameterValue] attributes should also be marked [Optional]",
messageFormat: "Parameters with [DefaultParameterValue] attributes should also be marked [Optional]",
RuleCategories.Design,
DiagnosticSeverity.Warning,
isEnabledByDefault: true,
description: "",
helpLinkUri: RuleIdentifiers.GetHelpUri(RuleIdentifiers.ParametersWithDefaultValueShouldBeMarkedWithOptionalParameter));

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(s_rule);

public override void Initialize(AnalysisContext context)
{
context.EnableConcurrentExecution();
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

context.RegisterCompilationStartAction(ctx =>
{
var analyzerContext = new AnalyzerContext(ctx.Compilation);
if (analyzerContext.IsValid)
{
ctx.RegisterSymbolAction(analyzerContext.AnalyzerParameter, SymbolKind.Parameter);
}
});
}

private sealed class AnalyzerContext
{
public AnalyzerContext(Compilation compilation)
{
OptionalAttributeSymbol = compilation.GetTypeByMetadataName("System.Runtime.InteropServices.OptionalAttribute");
DefaultParameterValueAttributeSymbol = compilation.GetTypeByMetadataName("System.Runtime.InteropServices.DefaultParameterValueAttribute");
}

public INamedTypeSymbol? OptionalAttributeSymbol { get; set; }
public INamedTypeSymbol? DefaultParameterValueAttributeSymbol { get; set; }

public bool IsValid => OptionalAttributeSymbol != null && DefaultParameterValueAttributeSymbol != null;

public void AnalyzerParameter(SymbolAnalysisContext context)
{
var parameter = (IParameterSymbol)context.Symbol;
if (parameter.HasAttribute(DefaultParameterValueAttributeSymbol) && !parameter.HasAttribute(OptionalAttributeSymbol))
{
context.ReportDiagnostic(s_rule, parameter);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System.Threading.Tasks;
using Meziantou.Analyzer.Rules;
using TestHelper;
using Xunit;

namespace Meziantou.Analyzer.Test.Rules
{
public sealed class OptionalParametersAttributeAnalyzerTests
{
private static ProjectBuilder CreateProjectBuilder()
{
return new ProjectBuilder()
.WithAnalyzer<OptionalParametersAttributeAnalyzer>();
}

[Fact]
public async Task MissingOptionalAttribute()
{
const string SourceCode = @"using System.Runtime.InteropServices;
class Test
{
void A([DefaultParameterValue(10)]int [|a|])
{
}
}";
await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}

[Fact]
public async Task BothAttributes()
{
const string SourceCode = @"using System.Runtime.InteropServices;
class Test
{
void A([Optional, DefaultParameterValue(10)]int a)
{
}
}";
await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}

[Fact]
public async Task OptionalAttribute()
{
const string SourceCode = @"using System.Runtime.InteropServices;
class Test
{
void A([Optional]int a)
{
}
}";
await CreateProjectBuilder()
.WithSourceCode(SourceCode)
.ValidateAsync();
}
}
}

0 comments on commit ef142d8

Please sign in to comment.