Skip to content

Commit

Permalink
Merge pull request #383 from tinestaric/ComCopPR-Captions_CalcFields_…
Browse files Browse the repository at this point in the history
…InternalMethods

Companial Cop - PR: Locked Captions,  AutoCalcFields, Internal Method Parameter
  • Loading branch information
Arthurvdv authored Dec 5, 2023
2 parents 8e36325 + 5f21dfb commit 6c99403
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 0 deletions.
31 changes: 31 additions & 0 deletions Design/Rule0035BuiltInMethodsMustHaveExplicitParameters.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Collections.Immutable;
using Microsoft.Dynamics.Nav.CodeAnalysis;
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;

namespace BusinessCentral.LinterCop.Design
{
[DiagnosticAnalyzer]
public class Rule0035BuiltInMethodsMustHaveExplicitParameters : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0035BuiltInMethodsMustHaveExplicitParameters);

public override void Initialize(AnalysisContext context) => context.RegisterOperationAction(new Action<OperationAnalysisContext>(this.CheckCommitForExplainingComment), OperationKind.InvocationExpression);

private void CheckCommitForExplainingComment(OperationAnalysisContext ctx)
{
if (ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoletePending || ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoleteRemoved) return;
if (ctx.ContainingSymbol.IsObsoletePending || ctx.ContainingSymbol.IsObsoleteRemoved) return;

List<string> methodsToCheck = new List<string> { "INSERT", "MODIFY", "DELETE", "UPDATE", "DELETEALL" };

IInvocationExpression operation = (IInvocationExpression)ctx.Operation;
IMethodSymbol targetMethod = operation.TargetMethod;

if (targetMethod.MethodKind != MethodKind.BuiltInMethod) return;

if (methodsToCheck.Contains(targetMethod.Name.ToUpper()))
if (operation.Arguments.Length == 0)
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0035BuiltInMethodsMustHaveExplicitParameters, ctx.Operation.Syntax.GetLocation()));
}
}
}
41 changes: 41 additions & 0 deletions Design/Rule0036EmptyCaptionLocked.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using Microsoft.Dynamics.Nav.CodeAnalysis;
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
using Microsoft.Dynamics.Nav.CodeAnalysis.Syntax;
using System;
using System.Collections.Immutable;

namespace BusinessCentral.LinterCop.Design
{
[DiagnosticAnalyzer]
public class Rule0036EmptyCaptionLocked : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0036EmptyCaptionLocked);

public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(new Action<SyntaxNodeAnalysisContext>(AnalyzeCaptionProperty), SyntaxKind.EnumValue);

private void AnalyzeCaptionProperty(SyntaxNodeAnalysisContext ctx)
{
if (ctx.ContainingSymbol.IsObsoletePending || ctx.ContainingSymbol.IsObsoleteRemoved) return;
if (ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoletePending || ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoleteRemoved) return;

LabelPropertyValueSyntax captionProperty = ctx.Node?.GetProperty("Caption")?.Value as LabelPropertyValueSyntax;

if (captionProperty == null || captionProperty.Value.LabelText.Value.Value.ToString().Trim() != "" || ctx.ContainingSymbol.Kind != SymbolKind.Enum) return;

bool labelLocked = false;

if (captionProperty.Value.Properties != null)
foreach (IdentifierEqualsLiteralSyntax property in captionProperty.Value.Properties.Values)
{
if (property.Identifier.Text.ToLower() == "locked")
{
labelLocked = true;
break;
}
}

if (!labelLocked)
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0036EmptyCaptionLocked, captionProperty.GetLocation()));
}
}
}
29 changes: 29 additions & 0 deletions Design/Rule0037AutoCalcFieldsOnNormalFields.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.Dynamics.Nav.CodeAnalysis;
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;

namespace BusinessCentral.LinterCop.Design
{
[DiagnosticAnalyzer]
public class Rule0037AutoCalcFieldsOnNormalFields : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0037AutoCalcFieldsOnNormalFields);

public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(syntaxContext =>
{
if (!syntaxContext.Node.ToString().ToLowerInvariant().Contains("setautocalcfields"))
return;

IInvocationExpression operation = (IInvocationExpression)syntaxContext.SemanticModel.GetOperation(syntaxContext.Node);
IMethodSymbol targetMethod = operation.TargetMethod;
if (targetMethod == null || !SemanticFacts.IsSameName(targetMethod.Name, "setautocalcfields") || targetMethod.MethodKind != MethodKind.BuiltInMethod)
return;

foreach (IArgument obj in operation.Arguments)
{
if ((obj.Value is IConversionExpression conversionExpression2 ? conversionExpression2.Operand : (IOperation)null) is IFieldAccess fieldAccess2 && fieldAccess2.FieldSymbol.FieldClass != FieldClassKind.FlowField && fieldAccess2.Type.NavTypeKind != NavTypeKind.Blob)
syntaxContext.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0037AutoCalcFieldsOnNormalFields, fieldAccess2.Syntax.GetLocation(), (object)fieldAccess2.FieldSymbol.Name));
}
}, SyntaxKind.InvocationExpression);
}
}
3 changes: 3 additions & 0 deletions LinterCopAnalyzers.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ public static class DiagnosticDescriptors
public static readonly DiagnosticDescriptor Rule0032ClearCodeunitSingleInstance = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0032", (LocalizableString)new LocalizableResourceString("Rule0032ClearCodeunitSingleInstanceTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0032ClearCodeunitSingleInstanceFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Warning, true, (LocalizableString)new LocalizableResourceString("Rule0032ClearCodeunitSingleInstanceDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0032");
public static readonly DiagnosticDescriptor Rule0033AppManifestRuntimeBehind = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0033", (LocalizableString)new LocalizableResourceString("Rule0033AppManifestRuntimeBehindTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0033AppManifestRuntimeBehindFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0033AppManifestRuntimeBehindTitleDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0033");
public static readonly DiagnosticDescriptor Rule0034ExtensiblePropertyShouldAlwaysBeSet = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0034", (LocalizableString)new LocalizableResourceString("Rule0034ExtensiblePropertyShouldAlwaysBeSetTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0034ExtensiblePropertyShouldAlwaysBeSetFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Hidden, true, (LocalizableString)new LocalizableResourceString("Rule0034ExtensiblePropertyShouldAlwaysBeSetDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0034");
public static readonly DiagnosticDescriptor Rule0035BuiltInMethodsMustHaveExplicitParameters = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0035", (LocalizableString)new LocalizableResourceString("Rule0035BuiltInMethodsMustHaveExplicitParametersTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0035BuiltInMethodsMustHaveExplicitParametersFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0035BuiltInMethodsMustHaveExplicitParametersDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0035");
public static readonly DiagnosticDescriptor Rule0036EmptyCaptionLocked = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0036", (LocalizableString)new LocalizableResourceString("Rule0036EmptyCaptionLockedTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0036EmptyCaptionLockedFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0036EmptyCaptionLockedDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0036");
public static readonly DiagnosticDescriptor Rule0037AutoCalcFieldsOnNormalFields = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0032", (LocalizableString)new LocalizableResourceString("Rule0037AutoCalcFieldsOnNormalFieldsTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0037AutoCalcFieldsOnNormalFieldsFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0037AutoCalcFieldsOnNormalFieldsDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0032");
public static readonly DiagnosticDescriptor Rule0035ExplicitSetAllowInCustomizations = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0035", (LocalizableString)new LocalizableResourceString("Rule0035ExplicitSetAllowInCustomizationsTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0035ExplicitSetAllowInCustomizationsFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0035ExplicitSetAllowInCustomizationsDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0035");
public static readonly DiagnosticDescriptor Rule0036ToolTipShouldStartWithSpecifies = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0036", (LocalizableString)new LocalizableResourceString("Rule0036ToolTipShouldStartWithSpecifiesTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0036ToolTipShouldStartWithSpecifiesFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0036ToolTipShouldStartWithSpecifiesDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0036");
public static readonly DiagnosticDescriptor Rule0037ToolTipDoNotUseLineBreaks = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0037", (LocalizableString)new LocalizableResourceString("Rule0037ToolTipDoNotUseLineBreaksTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0037ToolTipDoNotUseLineBreaksFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0037ToolTipDoNotUseLineBreaksDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0037");
Expand Down
27 changes: 27 additions & 0 deletions LinterCopAnalyzers.resx
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,33 @@
<data name="Rule0034ExtensiblePropertyShouldAlwaysBeSetDescription" xml:space="preserve">
<value>The property Extensible should be explicitly set for {0} objects.</value>
</data>
<data name="Rule0035BuiltInMethodsMustHaveExplicitParametersDescription" xml:space="preserve">
<value>Built-In Methods must be invoked with explicit parameters.</value>
</data>
<data name="Rule0035BuiltInMethodsMustHaveExplicitParametersFormat" xml:space="preserve">
<value>Built-In Methods must be invoked with explicit parameters.</value>
</data>
<data name="Rule0035BuiltInMethodsMustHaveExplicitParametersTitle" xml:space="preserve">
<value>Built-In Methods must be invoked with explicit parameters.</value>
</data>
<data name="Rule0036EmptyCaptionLockedDescription" xml:space="preserve">
<value>Empty captions should be locked.</value>
</data>
<data name="Rule0036EmptyCaptionLockedFormat" xml:space="preserve">
<value>Empty captions should be locked.</value>
</data>
<data name="Rule0036EmptyCaptionLockedTitle" xml:space="preserve">
<value>Empty captions should be locked.</value>
</data>
<data name="Rule0037AutoCalcFieldsOnNormalFieldsDescription" xml:space="preserve">
<value>SetAutoCalcFields must not be invoked on Normal fields.</value>
</data>
<data name="Rule0037AutoCalcFieldsOnNormalFieldsFormat" xml:space="preserve">
<value>SetAutoCalcFields must not be invoked on Normal fields.</value>
</data>
<data name="Rule0037AutoCalcFieldsOnNormalFieldsTitle" xml:space="preserve">
<value>SetAutoCalcFields must not be invoked on Normal fields.</value>
</data>
<data name="Rule0035ExplicitSetAllowInCustomizationsTitle" xml:space="preserve">
<value>Explicitly set AllowInCustomizations for fields omitted on pages.</value>
</data>
Expand Down

0 comments on commit 6c99403

Please sign in to comment.