-
-
Notifications
You must be signed in to change notification settings - Fork 403
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add analyzer which check how ObjectAuthorizationRules applied (#4051)
* Add analyzer which check how ObjectAuthorizationRules applied and make sure that methods is public and static. Fixes #1561 Fixes #1560 * Address PR feedback --------- Co-authored-by: Rockford Lhotka <rocky@lhotka.net>
- Loading branch information
1 parent
3f19935
commit ea08ad3
Showing
13 changed files
with
384 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<configuration> | ||
<packageSources> | ||
<!--To inherit the global NuGet package sources remove the <clear/> line below --> | ||
<clear /> | ||
<add key="nuget" value="https://api.nuget.org/v3/index.json" /> | ||
<add key="clsa" value="C:\d\github\csla\NuGet\Packages" /> | ||
</packageSources> | ||
<packageSourceMapping> | ||
<!-- key value for <packageSource> should match key values from <packageSources> element --> | ||
<!--<packageSource key="nuget.org"> | ||
<package pattern="*" /> | ||
</packageSource> | ||
<packageSource key="clsa"> | ||
<package pattern="Csla" /> | ||
<package pattern="Csla.*" /> | ||
</packageSource>--> | ||
<clear /> | ||
</packageSourceMapping> | ||
|
||
</configuration> |
159 changes: 159 additions & 0 deletions
159
Source/Csla.Analyzers/Csla.Analyzers.Tests/ObjectAuthorizationRulesAttributeAnalyzerTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.VisualStudio.TestTools.UnitTesting; | ||
|
||
namespace Csla.Analyzers.Tests | ||
{ | ||
[TestClass] | ||
public sealed class ObjectAuthorizationRulesAttributeAnalyzerTests | ||
{ | ||
[TestMethod] | ||
public void VerifySupportedDiagnostics() | ||
{ | ||
var analyzer = new ObjectAuthorizationRulesAttributeAnalyzer(); | ||
var diagnostics = analyzer.SupportedDiagnostics; | ||
Assert.AreEqual(3, diagnostics.Length); | ||
|
||
var attributeMissingDiagnostic = diagnostics[0]; | ||
Assert.AreEqual(Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesAttributeMissing, attributeMissingDiagnostic.Id, | ||
nameof(DiagnosticDescriptor.Id)); | ||
Assert.AreEqual(ObjectAuthorizationRulesAttributeAnalyzerConstants.AttributeMissingTitle, attributeMissingDiagnostic.Title.ToString(), | ||
nameof(DiagnosticDescriptor.Title)); | ||
Assert.AreEqual(ObjectAuthorizationRulesAttributeAnalyzerConstants.AttributeMissingMessage, attributeMissingDiagnostic.MessageFormat.ToString(), | ||
nameof(DiagnosticDescriptor.MessageFormat)); | ||
Assert.AreEqual(Constants.Categories.Usage, attributeMissingDiagnostic.Category, | ||
nameof(DiagnosticDescriptor.Category)); | ||
Assert.AreEqual(DiagnosticSeverity.Warning, attributeMissingDiagnostic.DefaultSeverity, | ||
nameof(DiagnosticDescriptor.DefaultSeverity)); | ||
Assert.AreEqual(HelpUrlBuilder.Build(Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesAttributeMissing, nameof(ObjectAuthorizationRulesAttributeAnalyzer)), | ||
attributeMissingDiagnostic.HelpLinkUri, | ||
nameof(DiagnosticDescriptor.HelpLinkUri)); | ||
|
||
var rulesConfigurationPublicDiagnostic = diagnostics[1]; | ||
Assert.AreEqual(Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesPublic, rulesConfigurationPublicDiagnostic.Id, | ||
nameof(DiagnosticDescriptor.Id)); | ||
Assert.AreEqual(ObjectAuthorizationRulesAttributeAnalyzerConstants.RulesPublicTitle, rulesConfigurationPublicDiagnostic.Title.ToString(), | ||
nameof(DiagnosticDescriptor.Title)); | ||
Assert.AreEqual(ObjectAuthorizationRulesAttributeAnalyzerConstants.RulesPublicMessage, rulesConfigurationPublicDiagnostic.MessageFormat.ToString(), | ||
nameof(DiagnosticDescriptor.MessageFormat)); | ||
Assert.AreEqual(Constants.Categories.Usage, rulesConfigurationPublicDiagnostic.Category, | ||
nameof(DiagnosticDescriptor.Category)); | ||
Assert.AreEqual(DiagnosticSeverity.Info, rulesConfigurationPublicDiagnostic.DefaultSeverity, | ||
nameof(DiagnosticDescriptor.DefaultSeverity)); | ||
Assert.AreEqual(HelpUrlBuilder.Build(Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesPublic, nameof(ObjectAuthorizationRulesAttributeAnalyzer)), | ||
rulesConfigurationPublicDiagnostic.HelpLinkUri, | ||
nameof(DiagnosticDescriptor.HelpLinkUri)); | ||
|
||
var rulesConfigurationStaticDiagnostic = diagnostics[2]; | ||
Assert.AreEqual(Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesStatic, rulesConfigurationStaticDiagnostic.Id, | ||
nameof(DiagnosticDescriptor.Id)); | ||
Assert.AreEqual(ObjectAuthorizationRulesAttributeAnalyzerConstants.RulesStaticTitle, rulesConfigurationStaticDiagnostic.Title.ToString(), | ||
nameof(DiagnosticDescriptor.Title)); | ||
Assert.AreEqual(ObjectAuthorizationRulesAttributeAnalyzerConstants.RulesStaticMessage, rulesConfigurationStaticDiagnostic.MessageFormat.ToString(), | ||
nameof(DiagnosticDescriptor.MessageFormat)); | ||
Assert.AreEqual(Constants.Categories.Usage, rulesConfigurationStaticDiagnostic.Category, | ||
nameof(DiagnosticDescriptor.Category)); | ||
Assert.AreEqual(DiagnosticSeverity.Warning, rulesConfigurationStaticDiagnostic.DefaultSeverity, | ||
nameof(DiagnosticDescriptor.DefaultSeverity)); | ||
Assert.AreEqual(HelpUrlBuilder.Build(Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesStatic, nameof(ObjectAuthorizationRulesAttributeAnalyzer)), | ||
rulesConfigurationStaticDiagnostic.HelpLinkUri, | ||
nameof(DiagnosticDescriptor.HelpLinkUri)); | ||
} | ||
|
||
[TestMethod] | ||
public async Task AnalyzeWhenClassIsNotMobileObject() | ||
{ | ||
var code = "public class A { }"; | ||
await TestHelpers.RunAnalysisAsync<ObjectAuthorizationRulesAttributeAnalyzer>(code, []); | ||
} | ||
|
||
[TestMethod] | ||
public async Task AnalyzeWhenClassIsMobileObjectAndObjectAuthorizationRulesHasAttribute() | ||
{ | ||
var code = | ||
""" | ||
using Csla; | ||
|
||
public class A : BusinessBase<A> | ||
{ | ||
[ObjectAuthorizationRules] | ||
public static void ConfigureObjectAuthorizationRules() | ||
{ | ||
} | ||
} | ||
"""; | ||
await TestHelpers.RunAnalysisAsync<ObjectAuthorizationRulesAttributeAnalyzer>(code, []); | ||
} | ||
|
||
[TestMethod] | ||
public async Task AnalyzeWhenClassIsMobileObjectAndDoesNotHaveObjectAuthorizationRules() | ||
{ | ||
var code = | ||
""" | ||
using Csla; | ||
|
||
public class A : BusinessBase<A> | ||
{ | ||
[Fetch] | ||
private void Fetch() { } | ||
} | ||
"""; | ||
await TestHelpers.RunAnalysisAsync<ObjectAuthorizationRulesAttributeAnalyzer>(code, []); | ||
} | ||
|
||
[TestMethod] | ||
public async Task AnalyzeWhenClassIsMobileObjectAndOperationHasNamingConvention() | ||
{ | ||
var code = | ||
""" | ||
using Csla; | ||
|
||
public class A : BusinessBase<A> | ||
{ | ||
public static void AddObjectAuthorizationRules() | ||
{ | ||
} | ||
} | ||
"""; | ||
await TestHelpers.RunAnalysisAsync<ObjectAuthorizationRulesAttributeAnalyzer>( | ||
code, [Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesAttributeMissing]); | ||
} | ||
|
||
[TestMethod] | ||
public async Task ObjectAuthorizationRulesMethodShouldBePublic() | ||
{ | ||
var code = | ||
""" | ||
using Csla; | ||
|
||
public class A : BusinessBase<A> | ||
{ | ||
[ObjectAuthorizationRules] | ||
private static void AddObjectAuthorizationRules() | ||
{ | ||
} | ||
} | ||
"""; | ||
await TestHelpers.RunAnalysisAsync<ObjectAuthorizationRulesAttributeAnalyzer>( | ||
code, [Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesPublic]); | ||
} | ||
|
||
[TestMethod] | ||
public async Task ObjectAuthorizationRulesMethodShouldBeStatic() | ||
{ | ||
var code = | ||
""" | ||
using Csla; | ||
|
||
public class A : BusinessBase<A> | ||
{ | ||
[ObjectAuthorizationRules] | ||
public void AddObjectAuthorizationRules() | ||
{ | ||
} | ||
} | ||
"""; | ||
await TestHelpers.RunAnalysisAsync<ObjectAuthorizationRulesAttributeAnalyzer>( | ||
code, [Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesStatic]); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
...Analyzers/Csla.Analyzers/Extensions/ConfigurationObjectAuthorizationRulesQualification.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
namespace Csla.Analyzers.Extensions | ||
{ | ||
public readonly struct CslaOperationQualification | ||
{ | ||
public CslaOperationQualification(bool byNamingConvention, bool byAttribute) => | ||
(ByNamingConvention, ByAttribute) = (byNamingConvention, byAttribute); | ||
|
||
public static implicit operator bool(CslaOperationQualification qualification) => | ||
qualification.ByAttribute | qualification.ByNamingConvention; | ||
|
||
public void Deconstruct(out bool byNamingConvention, out bool byAttribute) => | ||
(byNamingConvention, byAttribute) = (ByNamingConvention, ByAttribute); | ||
|
||
public bool ByAttribute { get; } | ||
public bool ByNamingConvention { get; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
Source/Csla.Analyzers/Csla.Analyzers/ObjectAuthorizationRulesAttributeAnalyzer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
using Csla.Analyzers.Extensions; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using System.Collections.Immutable; | ||
|
||
namespace Csla.Analyzers | ||
{ | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public sealed class ObjectAuthorizationRulesAttributeAnalyzer | ||
: DiagnosticAnalyzer | ||
{ | ||
private static readonly DiagnosticDescriptor missingAttributeRule = | ||
new DiagnosticDescriptor( | ||
Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesAttributeMissing, ObjectAuthorizationRulesAttributeAnalyzerConstants.AttributeMissingTitle, | ||
ObjectAuthorizationRulesAttributeAnalyzerConstants.AttributeMissingMessage, Constants.Categories.Usage, | ||
DiagnosticSeverity.Warning, true, | ||
helpLinkUri: HelpUrlBuilder.Build( | ||
Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesAttributeMissing, nameof(ObjectAuthorizationRulesAttributeAnalyzer))); | ||
private static readonly DiagnosticDescriptor shouldBePublicRule = | ||
new DiagnosticDescriptor( | ||
Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesPublic, ObjectAuthorizationRulesAttributeAnalyzerConstants.RulesPublicTitle, | ||
ObjectAuthorizationRulesAttributeAnalyzerConstants.RulesPublicMessage, Constants.Categories.Usage, | ||
DiagnosticSeverity.Info, true, | ||
helpLinkUri: HelpUrlBuilder.Build( | ||
Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesPublic, nameof(ObjectAuthorizationRulesAttributeAnalyzer))); | ||
private static readonly DiagnosticDescriptor shouldBeStaticRule = | ||
new DiagnosticDescriptor( | ||
Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesStatic, ObjectAuthorizationRulesAttributeAnalyzerConstants.RulesStaticTitle, | ||
ObjectAuthorizationRulesAttributeAnalyzerConstants.RulesStaticMessage, Constants.Categories.Usage, | ||
DiagnosticSeverity.Warning, true, | ||
helpLinkUri: HelpUrlBuilder.Build( | ||
Constants.AnalyzerIdentifiers.ObjectAuthorizationRulesStatic, nameof(ObjectAuthorizationRulesAttributeAnalyzer))); | ||
|
||
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(missingAttributeRule, shouldBePublicRule, shouldBeStaticRule); | ||
|
||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); | ||
context.EnableConcurrentExecution(); | ||
context.RegisterSyntaxNodeAction(AnalyzeMethodDeclaration, SyntaxKind.MethodDeclaration); | ||
} | ||
|
||
private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context) | ||
{ | ||
var methodNode = (MethodDeclarationSyntax)context.Node; | ||
|
||
var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodNode); | ||
var typeSymbol = methodSymbol.ContainingType; | ||
|
||
if (typeSymbol.IsStereotype()) | ||
{ | ||
var qualification = methodSymbol.IsAddObjectAuthorizationRulesOperation(); | ||
|
||
if(qualification.ByNamingConvention && !qualification.ByAttribute) | ||
{ | ||
context.ReportDiagnostic(Diagnostic.Create( | ||
missingAttributeRule, methodSymbol.Locations[0])); | ||
} | ||
if (methodSymbol.DeclaredAccessibility != Accessibility.Public && (qualification.ByNamingConvention || qualification.ByAttribute)) | ||
{ | ||
context.ReportDiagnostic(Diagnostic.Create( | ||
shouldBePublicRule, methodSymbol.Locations[0])); | ||
} | ||
if (!methodSymbol.IsStatic && (qualification.ByNamingConvention || qualification.ByAttribute)) | ||
{ | ||
context.ReportDiagnostic(Diagnostic.Create( | ||
shouldBeStaticRule, methodSymbol.Locations[0])); | ||
} | ||
} | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
Source/Csla.Analyzers/Csla.Analyzers/ObjectAuthorizationRulesAttributeAnalyzerConstants.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
namespace Csla.Analyzers | ||
{ | ||
public static class ObjectAuthorizationRulesAttributeAnalyzerConstants | ||
{ | ||
public const string AttributeMissingTitle = "Find Authorization Rules Configuration That Do Not Have an Operation Attribute"; | ||
public const string AttributeMissingMessage = "Authorization rules should use the appropriate operation attribute"; | ||
public const string RulesPublicTitle = "Find Authorization Rules Configuration That Is Not Public"; | ||
public const string RulesPublicMessage = "Authorization rules should be declared as public methods"; | ||
public const string RulesStaticTitle = "Find Authorization Rules Configuration That Is Not Static"; | ||
public const string RulesStaticMessage = "Authorization rules should be declared as static methods"; | ||
} | ||
|
||
public static class ObjectAuthorizationRulesAttributeAnalyzerAddAttributeCodeFixConstants | ||
{ | ||
public const string AddAttributeAndUsingDescription = "Add attribute and using statement"; | ||
public const string AddAttributeDescription = "Add attribute"; | ||
public const string CslaNamespace = "Csla"; | ||
} | ||
} |
20 changes: 20 additions & 0 deletions
20
docs/analyzers/CSLA0020-ObjectAuthorizationRulesAttributeMissing.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
# Object authorization rules configuration should be marked with attribute. | ||
|
||
## Issue | ||
This analyzer is informing developer, that `AddObjectAuthorizationRules` method should be marked with `[ObjectAuthorizationRules]` attribute: | ||
|
||
``` | ||
public class Customer | ||
: BusinessBase<Customer> | ||
{ | ||
public static void AddObjectAuthorizationRules() | ||
{ | ||
} | ||
} | ||
``` | ||
|
||
Please add `[ObjectAuthorizationRules]` attribute to the method. | ||
|
||
## Code Fix | ||
|
||
No code fix exists for this analyzer. |
Oops, something went wrong.