From e38bb42b47393959795c730cfec728b524b5dff9 Mon Sep 17 00:00:00 2001 From: Tine Staric Date: Wed, 29 Nov 2023 13:32:02 +0200 Subject: [PATCH 01/12] Add Rule0035BuiltInMethodsMustHaveExplicitParameters analyzer --- ...uiltInMethodsMustHaveExplicitParameters.cs | 31 +++++++++++++++++++ LinterCopAnalyzers.Generated.cs | 1 + LinterCopAnalyzers.resx | 9 ++++++ 3 files changed, 41 insertions(+) create mode 100644 Design/Rule0035BuiltInMethodsMustHaveExplicitParameters.cs diff --git a/Design/Rule0035BuiltInMethodsMustHaveExplicitParameters.cs b/Design/Rule0035BuiltInMethodsMustHaveExplicitParameters.cs new file mode 100644 index 00000000..a52ac318 --- /dev/null +++ b/Design/Rule0035BuiltInMethodsMustHaveExplicitParameters.cs @@ -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 SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0035BuiltInMethodsMustHaveExplicitParameters); + + public override void Initialize(AnalysisContext context) => context.RegisterOperationAction(new Action(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 methodsToCheck = new List { "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())); + } + } +} \ No newline at end of file diff --git a/LinterCopAnalyzers.Generated.cs b/LinterCopAnalyzers.Generated.cs index 82c244e9..68f1d580 100644 --- a/LinterCopAnalyzers.Generated.cs +++ b/LinterCopAnalyzers.Generated.cs @@ -41,5 +41,6 @@ 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"); } } \ No newline at end of file diff --git a/LinterCopAnalyzers.resx b/LinterCopAnalyzers.resx index 236e6e58..098a70ef 100644 --- a/LinterCopAnalyzers.resx +++ b/LinterCopAnalyzers.resx @@ -411,4 +411,13 @@ The property Extensible should be explicitly set for {0} objects. + + Built-In Methods must be invoked with explicit parameters. + + + Built-In Methods must be invoked with explicit parameters. + + + Built-In Methods must be invoked with explicit parameters. + \ No newline at end of file From 7b1fb341dc1e885c8e5fa4563674b76991821197 Mon Sep 17 00:00:00 2001 From: Tine Staric Date: Wed, 29 Nov 2023 13:38:21 +0200 Subject: [PATCH 02/12] Add Rule0036EmptyCaptionLocked diagnostic analyzer --- Design/Rule0036Rule0036EmptyCaptionLocked.cs | 41 ++++++++++++++++++++ LinterCopAnalyzers.Generated.cs | 1 + LinterCopAnalyzers.resx | 9 +++++ 3 files changed, 51 insertions(+) create mode 100644 Design/Rule0036Rule0036EmptyCaptionLocked.cs diff --git a/Design/Rule0036Rule0036EmptyCaptionLocked.cs b/Design/Rule0036Rule0036EmptyCaptionLocked.cs new file mode 100644 index 00000000..9a92a80c --- /dev/null +++ b/Design/Rule0036Rule0036EmptyCaptionLocked.cs @@ -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 SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0036EmptyCaptionLocked); + + public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(new Action(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())); + } + } +} \ No newline at end of file diff --git a/LinterCopAnalyzers.Generated.cs b/LinterCopAnalyzers.Generated.cs index 68f1d580..ce6ebd52 100644 --- a/LinterCopAnalyzers.Generated.cs +++ b/LinterCopAnalyzers.Generated.cs @@ -42,5 +42,6 @@ public static class DiagnosticDescriptors 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"); } } \ No newline at end of file diff --git a/LinterCopAnalyzers.resx b/LinterCopAnalyzers.resx index 098a70ef..e2e10fb3 100644 --- a/LinterCopAnalyzers.resx +++ b/LinterCopAnalyzers.resx @@ -420,4 +420,13 @@ Built-In Methods must be invoked with explicit parameters. + + Empty captions should be locked. + + + Empty captions should be locked. + + + Empty captions should be locked. + \ No newline at end of file From 40ae640faeb2e7a5bf911d3e7a8411afbe377352 Mon Sep 17 00:00:00 2001 From: Tine Staric Date: Wed, 29 Nov 2023 13:43:44 +0200 Subject: [PATCH 03/12] Add Rule0037AutoCalcFieldsOnNormalFields diagnostic analyzer --- .../Rule0037AutoCalcFieldsOnNormalFields.cs | 29 +++++++++++++++++++ LinterCopAnalyzers.Generated.cs | 1 + LinterCopAnalyzers.resx | 9 ++++++ 3 files changed, 39 insertions(+) create mode 100644 Design/Rule0037AutoCalcFieldsOnNormalFields.cs diff --git a/Design/Rule0037AutoCalcFieldsOnNormalFields.cs b/Design/Rule0037AutoCalcFieldsOnNormalFields.cs new file mode 100644 index 00000000..e002fff7 --- /dev/null +++ b/Design/Rule0037AutoCalcFieldsOnNormalFields.cs @@ -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 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); + } +} \ No newline at end of file diff --git a/LinterCopAnalyzers.Generated.cs b/LinterCopAnalyzers.Generated.cs index ce6ebd52..1edcf8e1 100644 --- a/LinterCopAnalyzers.Generated.cs +++ b/LinterCopAnalyzers.Generated.cs @@ -43,5 +43,6 @@ public static class DiagnosticDescriptors 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"); } } \ No newline at end of file diff --git a/LinterCopAnalyzers.resx b/LinterCopAnalyzers.resx index e2e10fb3..0af3a8e4 100644 --- a/LinterCopAnalyzers.resx +++ b/LinterCopAnalyzers.resx @@ -429,4 +429,13 @@ Empty captions should be locked. + + SetAutoCalcFields must not be invoked on Normal fields. + + + SetAutoCalcFields must not be invoked on Normal fields. + + + SetAutoCalcFields must not be invoked on Normal fields. + \ No newline at end of file From 50b423a10ac7ad724fac5ac35d9193063fab7631 Mon Sep 17 00:00:00 2001 From: Tine Staric Date: Wed, 29 Nov 2023 13:50:25 +0200 Subject: [PATCH 04/12] Fix File Name for Rule 0036 --- ...ule0036EmptyCaptionLocked.cs => Rule0036EmptyCaptionLocked.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Design/{Rule0036Rule0036EmptyCaptionLocked.cs => Rule0036EmptyCaptionLocked.cs} (100%) diff --git a/Design/Rule0036Rule0036EmptyCaptionLocked.cs b/Design/Rule0036EmptyCaptionLocked.cs similarity index 100% rename from Design/Rule0036Rule0036EmptyCaptionLocked.cs rename to Design/Rule0036EmptyCaptionLocked.cs From c988f22b3ea12e015c2d2607791e1eeb862ad6dd Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Tue, 5 Dec 2023 19:37:35 +0100 Subject: [PATCH 05/12] Renumber --- ...iltInMethodsMustHaveExplicitParameters.cs} | 6 +-- ...ocked.cs => Rule0041EmptyCaptionLocked.cs} | 6 +-- ...> Rule0042AutoCalcFieldsOnNormalFields.cs} | 6 +-- LinterCopAnalyzers.Generated.cs | 6 +-- LinterCopAnalyzers.resx | 54 +++++++++---------- 5 files changed, 39 insertions(+), 39 deletions(-) rename Design/{Rule0035BuiltInMethodsMustHaveExplicitParameters.cs => Rule0040BuiltInMethodsMustHaveExplicitParameters.cs} (89%) rename Design/{Rule0036EmptyCaptionLocked.cs => Rule0041EmptyCaptionLocked.cs} (91%) rename Design/{Rule0037AutoCalcFieldsOnNormalFields.cs => Rule0042AutoCalcFieldsOnNormalFields.cs} (89%) diff --git a/Design/Rule0035BuiltInMethodsMustHaveExplicitParameters.cs b/Design/Rule0040BuiltInMethodsMustHaveExplicitParameters.cs similarity index 89% rename from Design/Rule0035BuiltInMethodsMustHaveExplicitParameters.cs rename to Design/Rule0040BuiltInMethodsMustHaveExplicitParameters.cs index a52ac318..2757dba7 100644 --- a/Design/Rule0035BuiltInMethodsMustHaveExplicitParameters.cs +++ b/Design/Rule0040BuiltInMethodsMustHaveExplicitParameters.cs @@ -5,9 +5,9 @@ namespace BusinessCentral.LinterCop.Design { [DiagnosticAnalyzer] - public class Rule0035BuiltInMethodsMustHaveExplicitParameters : DiagnosticAnalyzer + public class Rule0040BuiltInMethodsMustHaveExplicitParameters : DiagnosticAnalyzer { - public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0035BuiltInMethodsMustHaveExplicitParameters); + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0040BuiltInMethodsMustHaveExplicitParameters); public override void Initialize(AnalysisContext context) => context.RegisterOperationAction(new Action(this.CheckCommitForExplainingComment), OperationKind.InvocationExpression); @@ -25,7 +25,7 @@ private void CheckCommitForExplainingComment(OperationAnalysisContext ctx) if (methodsToCheck.Contains(targetMethod.Name.ToUpper())) if (operation.Arguments.Length == 0) - ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0035BuiltInMethodsMustHaveExplicitParameters, ctx.Operation.Syntax.GetLocation())); + ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0040BuiltInMethodsMustHaveExplicitParameters, ctx.Operation.Syntax.GetLocation())); } } } \ No newline at end of file diff --git a/Design/Rule0036EmptyCaptionLocked.cs b/Design/Rule0041EmptyCaptionLocked.cs similarity index 91% rename from Design/Rule0036EmptyCaptionLocked.cs rename to Design/Rule0041EmptyCaptionLocked.cs index 9a92a80c..79df6488 100644 --- a/Design/Rule0036EmptyCaptionLocked.cs +++ b/Design/Rule0041EmptyCaptionLocked.cs @@ -7,9 +7,9 @@ namespace BusinessCentral.LinterCop.Design { [DiagnosticAnalyzer] - public class Rule0036EmptyCaptionLocked : DiagnosticAnalyzer + public class Rule0041EmptyCaptionLocked : DiagnosticAnalyzer { - public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0036EmptyCaptionLocked); + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0041EmptyCaptionLocked); public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(new Action(AnalyzeCaptionProperty), SyntaxKind.EnumValue); @@ -35,7 +35,7 @@ private void AnalyzeCaptionProperty(SyntaxNodeAnalysisContext ctx) } if (!labelLocked) - ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0036EmptyCaptionLocked, captionProperty.GetLocation())); + ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0041EmptyCaptionLocked, captionProperty.GetLocation())); } } } \ No newline at end of file diff --git a/Design/Rule0037AutoCalcFieldsOnNormalFields.cs b/Design/Rule0042AutoCalcFieldsOnNormalFields.cs similarity index 89% rename from Design/Rule0037AutoCalcFieldsOnNormalFields.cs rename to Design/Rule0042AutoCalcFieldsOnNormalFields.cs index e002fff7..02e7553c 100644 --- a/Design/Rule0037AutoCalcFieldsOnNormalFields.cs +++ b/Design/Rule0042AutoCalcFieldsOnNormalFields.cs @@ -5,9 +5,9 @@ namespace BusinessCentral.LinterCop.Design { [DiagnosticAnalyzer] - public class Rule0037AutoCalcFieldsOnNormalFields : DiagnosticAnalyzer + public class Rule0042AutoCalcFieldsOnNormalFields : DiagnosticAnalyzer { - public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0037AutoCalcFieldsOnNormalFields); + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0042AutoCalcFieldsOnNormalFields); public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(syntaxContext => { @@ -22,7 +22,7 @@ public override void Initialize(AnalysisContext context) => context.RegisterSynt 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)); + syntaxContext.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0042AutoCalcFieldsOnNormalFields, fieldAccess2.Syntax.GetLocation(), (object)fieldAccess2.FieldSymbol.Name)); } }, SyntaxKind.InvocationExpression); } diff --git a/LinterCopAnalyzers.Generated.cs b/LinterCopAnalyzers.Generated.cs index ab4aafac..c6f59561 100644 --- a/LinterCopAnalyzers.Generated.cs +++ b/LinterCopAnalyzers.Generated.cs @@ -41,13 +41,13 @@ 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"); public static readonly DiagnosticDescriptor Rule0038ToolTipMaximumLength = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0038", (LocalizableString)new LocalizableResourceString("Rule0038ToolTipMaximumLengthTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0038ToolTipMaximumLengthFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0038ToolTipMaximumLengthDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0038"); public static readonly DiagnosticDescriptor Rule0039ArgumentDifferentTypeThenExpected = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0039", (LocalizableString)new LocalizableResourceString("Rule0039ArgumentDifferentTypeThenExpectedTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0039ArgumentDifferentTypeThenExpectedFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Warning, true, (LocalizableString)new LocalizableResourceString("Rule0039ArgumentDifferentTypeThenExpectedDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0039"); + public static readonly DiagnosticDescriptor Rule0040BuiltInMethodsMustHaveExplicitParameters = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0040", (LocalizableString)new LocalizableResourceString("Rule0040BuiltInMethodsMustHaveExplicitParametersTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0040BuiltInMethodsMustHaveExplicitParametersFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0040BuiltInMethodsMustHaveExplicitParametersDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0040"); + public static readonly DiagnosticDescriptor Rule0041EmptyCaptionLocked = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0041", (LocalizableString)new LocalizableResourceString("Rule0041EmptyCaptionLockedTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0041EmptyCaptionLockedFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0041EmptyCaptionLockedDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0041"); + public static readonly DiagnosticDescriptor Rule0042AutoCalcFieldsOnNormalFields = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0042", (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0042"); } } \ No newline at end of file diff --git a/LinterCopAnalyzers.resx b/LinterCopAnalyzers.resx index f7536858..7292299c 100644 --- a/LinterCopAnalyzers.resx +++ b/LinterCopAnalyzers.resx @@ -411,33 +411,6 @@ The property Extensible should be explicitly set for {0} objects. - - Built-In Methods must be invoked with explicit parameters. - - - Built-In Methods must be invoked with explicit parameters. - - - Built-In Methods must be invoked with explicit parameters. - - - Empty captions should be locked. - - - Empty captions should be locked. - - - Empty captions should be locked. - - - SetAutoCalcFields must not be invoked on Normal fields. - - - SetAutoCalcFields must not be invoked on Normal fields. - - - SetAutoCalcFields must not be invoked on Normal fields. - Explicitly set AllowInCustomizations for fields omitted on pages. @@ -483,4 +456,31 @@ Argument {0}: cannot convert from '{1}' to '{2}'. + + Built-In Methods must be invoked with explicit parameters. + + + Built-In Methods must be invoked with explicit parameters. + + + Built-In Methods must be invoked with explicit parameters. + + + Empty captions should be locked. + + + Empty captions should be locked. + + + Empty captions should be locked. + + + SetAutoCalcFields must not be invoked on Normal fields. + + + SetAutoCalcFields must not be invoked on Normal fields. + + + SetAutoCalcFields must not be invoked on Normal fields. + \ No newline at end of file From 90bd7a745f5fa7bb057a2fd1ba1d2ab4399db6cd Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Wed, 6 Dec 2023 15:10:29 +0100 Subject: [PATCH 06/12] Adapt rule to RunTrigger and include ModifyAll() --- ...uiltInMethodsMustHaveExplicitParameters.cs | 31 ---------------- Design/Rule0040ExplicitlySetRunTrigger.cs | 36 +++++++++++++++++++ LinterCopAnalyzers.Generated.cs | 3 +- LinterCopAnalyzers.resx | 12 +++---- 4 files changed, 43 insertions(+), 39 deletions(-) delete mode 100644 Design/Rule0040BuiltInMethodsMustHaveExplicitParameters.cs create mode 100644 Design/Rule0040ExplicitlySetRunTrigger.cs diff --git a/Design/Rule0040BuiltInMethodsMustHaveExplicitParameters.cs b/Design/Rule0040BuiltInMethodsMustHaveExplicitParameters.cs deleted file mode 100644 index 2757dba7..00000000 --- a/Design/Rule0040BuiltInMethodsMustHaveExplicitParameters.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System.Collections.Immutable; -using Microsoft.Dynamics.Nav.CodeAnalysis; -using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics; - -namespace BusinessCentral.LinterCop.Design -{ - [DiagnosticAnalyzer] - public class Rule0040BuiltInMethodsMustHaveExplicitParameters : DiagnosticAnalyzer - { - public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0040BuiltInMethodsMustHaveExplicitParameters); - - public override void Initialize(AnalysisContext context) => context.RegisterOperationAction(new Action(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 methodsToCheck = new List { "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.Rule0040BuiltInMethodsMustHaveExplicitParameters, ctx.Operation.Syntax.GetLocation())); - } - } -} \ No newline at end of file diff --git a/Design/Rule0040ExplicitlySetRunTrigger.cs b/Design/Rule0040ExplicitlySetRunTrigger.cs new file mode 100644 index 00000000..5a786aaf --- /dev/null +++ b/Design/Rule0040ExplicitlySetRunTrigger.cs @@ -0,0 +1,36 @@ +using System.Collections.Immutable; +using Microsoft.Dynamics.Nav.CodeAnalysis; +using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics; + +namespace BusinessCentral.LinterCop.Design +{ + [DiagnosticAnalyzer] + public class Rule0040ExplicitlySetRunTrigger : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0040ExplicitlySetRunTrigger); + + private static readonly List buildInMethodNames = new List + { + "insert", + "modify", + "modifyall", + "delete", + "deleteall" + }; + + public override void Initialize(AnalysisContext context) => context.RegisterOperationAction(new Action(this.AnalyzeRunTriggerParameters), OperationKind.InvocationExpression); + + private void AnalyzeRunTriggerParameters(OperationAnalysisContext ctx) + { + if (ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoletePending || ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoleteRemoved) return; + if (ctx.ContainingSymbol.IsObsoletePending || ctx.ContainingSymbol.IsObsoleteRemoved) return; + + IInvocationExpression operation = (IInvocationExpression)ctx.Operation; + if (operation.TargetMethod.MethodKind != MethodKind.BuiltInMethod) return; + if (!buildInMethodNames.Contains(operation.TargetMethod.Name.ToLowerInvariant())) return; + + if (operation.Arguments.Where(args => args.Parameter.Name.ToLowerInvariant() == "runtrigger").SingleOrDefault() == null) + ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0040ExplicitlySetRunTrigger, ctx.Operation.Syntax.GetLocation())); + } + } +} \ No newline at end of file diff --git a/LinterCopAnalyzers.Generated.cs b/LinterCopAnalyzers.Generated.cs index c6f59561..69e51f5c 100644 --- a/LinterCopAnalyzers.Generated.cs +++ b/LinterCopAnalyzers.Generated.cs @@ -1,5 +1,4 @@ using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics; -using System; namespace BusinessCentral.LinterCop { @@ -46,7 +45,7 @@ public static class DiagnosticDescriptors 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"); public static readonly DiagnosticDescriptor Rule0038ToolTipMaximumLength = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0038", (LocalizableString)new LocalizableResourceString("Rule0038ToolTipMaximumLengthTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0038ToolTipMaximumLengthFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0038ToolTipMaximumLengthDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0038"); public static readonly DiagnosticDescriptor Rule0039ArgumentDifferentTypeThenExpected = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0039", (LocalizableString)new LocalizableResourceString("Rule0039ArgumentDifferentTypeThenExpectedTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0039ArgumentDifferentTypeThenExpectedFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Warning, true, (LocalizableString)new LocalizableResourceString("Rule0039ArgumentDifferentTypeThenExpectedDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0039"); - public static readonly DiagnosticDescriptor Rule0040BuiltInMethodsMustHaveExplicitParameters = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0040", (LocalizableString)new LocalizableResourceString("Rule0040BuiltInMethodsMustHaveExplicitParametersTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0040BuiltInMethodsMustHaveExplicitParametersFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0040BuiltInMethodsMustHaveExplicitParametersDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0040"); + public static readonly DiagnosticDescriptor Rule0040ExplicitlySetRunTrigger = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0040", (LocalizableString)new LocalizableResourceString("Rule0040ExplicitlySetRunTriggerTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0040ExplicitlySetRunTriggerFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0040ExplicitlySetRunTriggerDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0040"); public static readonly DiagnosticDescriptor Rule0041EmptyCaptionLocked = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0041", (LocalizableString)new LocalizableResourceString("Rule0041EmptyCaptionLockedTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0041EmptyCaptionLockedFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0041EmptyCaptionLockedDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0041"); public static readonly DiagnosticDescriptor Rule0042AutoCalcFieldsOnNormalFields = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0042", (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0042"); } diff --git a/LinterCopAnalyzers.resx b/LinterCopAnalyzers.resx index 7292299c..a033ff5a 100644 --- a/LinterCopAnalyzers.resx +++ b/LinterCopAnalyzers.resx @@ -456,14 +456,14 @@ Argument {0}: cannot convert from '{1}' to '{2}'. - - Built-In Methods must be invoked with explicit parameters. + + Explicitly set the RunTigger parameter on build-in methods. - - Built-In Methods must be invoked with explicit parameters. + + Explicitly set the RunTigger parameter on build-in methods. - - Built-In Methods must be invoked with explicit parameters. + + Explicitly set the RunTigger parameter on build-in methods. Empty captions should be locked. From 189a126df9ec91641c8556751f9cc18b0ecd75fd Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Wed, 6 Dec 2023 15:12:10 +0100 Subject: [PATCH 07/12] Expand to more objects and controls --- Design/Rule0041EmptyCaptionLocked.cs | 55 +++++++++++++++++++--------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/Design/Rule0041EmptyCaptionLocked.cs b/Design/Rule0041EmptyCaptionLocked.cs index 79df6488..0d96d4ec 100644 --- a/Design/Rule0041EmptyCaptionLocked.cs +++ b/Design/Rule0041EmptyCaptionLocked.cs @@ -1,7 +1,6 @@ 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 @@ -11,31 +10,53 @@ public class Rule0041EmptyCaptionLocked : DiagnosticAnalyzer { public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0041EmptyCaptionLocked); - public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(new Action(AnalyzeCaptionProperty), SyntaxKind.EnumValue); + // List based on https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/properties/devenv-caption-property + public override void Initialize(AnalysisContext context) + => context.RegisterSyntaxNodeAction(new Action(AnalyzeCaptionProperty), new SyntaxKind[] { + SyntaxKind.TableObject, + SyntaxKind.Field, // TableField + SyntaxKind.PageField, + SyntaxKind.PageGroup, + SyntaxKind.PageObject, + SyntaxKind.RequestPage, + SyntaxKind.PageLabel, + SyntaxKind.PageGroup, + SyntaxKind.PagePart, + SyntaxKind.PageSystemPart, + SyntaxKind.PageAction, + SyntaxKind.PageActionSeparator, + SyntaxKind.PageActionGroup, + SyntaxKind.XmlPortObject, + SyntaxKind.ReportObject, + SyntaxKind.QueryObject, + SyntaxKind.QueryColumn, + SyntaxKind.QueryFilter, + SyntaxKind.ReportColumn, + SyntaxKind.EnumValue, + SyntaxKind.PageCustomAction, + SyntaxKind.PageSystemAction, + SyntaxKind.PageView, + SyntaxKind.ReportLayout, + SyntaxKind.ProfileObject, + SyntaxKind.EnumType, + SyntaxKind.PermissionSet, + SyntaxKind.TableExtensionObject, + SyntaxKind.PageExtensionObject + }); 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; + if (ctx.Node.IsKind(SyntaxKind.EnumValue) && ctx.ContainingSymbol.Kind == SymbolKind.Enum) return; // Prevent double raising the rule on EnumValue in a EnumObject - bool labelLocked = false; + LabelPropertyValueSyntax captionProperty = ctx.Node?.GetProperty("Caption")?.Value as LabelPropertyValueSyntax; + if (captionProperty?.Value.LabelText.GetLiteralValue() == null || captionProperty.Value.LabelText.GetLiteralValue().ToString().Trim() != "") return; - if (captionProperty.Value.Properties != null) - foreach (IdentifierEqualsLiteralSyntax property in captionProperty.Value.Properties.Values) - { - if (property.Identifier.Text.ToLower() == "locked") - { - labelLocked = true; - break; - } - } + if (captionProperty.Value.Properties?.Values.Where(prop => prop.Identifier.Text.ToLowerInvariant() == "locked").FirstOrDefault() != null) return; - if (!labelLocked) - ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0041EmptyCaptionLocked, captionProperty.GetLocation())); + ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0041EmptyCaptionLocked, captionProperty.GetLocation())); } } } \ No newline at end of file From e9b4c29a39e11f579e50cbc1c2e01f9f5e8d1c89 Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Wed, 6 Dec 2023 15:12:38 +0100 Subject: [PATCH 08/12] Housekeeping --- Design/Rule0039ArgumentDifferentTypeThenExpected.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Design/Rule0039ArgumentDifferentTypeThenExpected.cs b/Design/Rule0039ArgumentDifferentTypeThenExpected.cs index 368e1fb2..3371528d 100644 --- a/Design/Rule0039ArgumentDifferentTypeThenExpected.cs +++ b/Design/Rule0039ArgumentDifferentTypeThenExpected.cs @@ -1,7 +1,6 @@ using Microsoft.Dynamics.Nav.CodeAnalysis; using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics; using Microsoft.Dynamics.Nav.CodeAnalysis.Symbols; -using System.Collections; using System.Collections.Immutable; namespace BusinessCentral.LinterCop.Design @@ -10,6 +9,7 @@ namespace BusinessCentral.LinterCop.Design public class Rule0039ArgumentDifferentTypeThenExpected : DiagnosticAnalyzer { public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected); + private static readonly List referencePageProviders = new List { PropertyKind.LookupPageId, From 59416caf9ac9053cfbdfaaf2b101ffa3adc941f5 Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Wed, 6 Dec 2023 15:19:10 +0100 Subject: [PATCH 09/12] Use IsSameName method --- Design/Rule0040ExplicitlySetRunTrigger.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Design/Rule0040ExplicitlySetRunTrigger.cs b/Design/Rule0040ExplicitlySetRunTrigger.cs index 5a786aaf..f903eb39 100644 --- a/Design/Rule0040ExplicitlySetRunTrigger.cs +++ b/Design/Rule0040ExplicitlySetRunTrigger.cs @@ -29,7 +29,7 @@ private void AnalyzeRunTriggerParameters(OperationAnalysisContext ctx) if (operation.TargetMethod.MethodKind != MethodKind.BuiltInMethod) return; if (!buildInMethodNames.Contains(operation.TargetMethod.Name.ToLowerInvariant())) return; - if (operation.Arguments.Where(args => args.Parameter.Name.ToLowerInvariant() == "runtrigger").SingleOrDefault() == null) + if (operation.Arguments.Where(args => SemanticFacts.IsSameName(args.Parameter.Name, "RunTrigger")).SingleOrDefault() == null) ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0040ExplicitlySetRunTrigger, ctx.Operation.Syntax.GetLocation())); } } From 5dcd58b171d964cf73d55009c05dc8fc1e6ff386 Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Wed, 6 Dec 2023 15:30:54 +0100 Subject: [PATCH 10/12] Set description to match with AA0211 rule --- LinterCopAnalyzers.resx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LinterCopAnalyzers.resx b/LinterCopAnalyzers.resx index a033ff5a..cfca8930 100644 --- a/LinterCopAnalyzers.resx +++ b/LinterCopAnalyzers.resx @@ -475,12 +475,12 @@ Empty captions should be locked. - SetAutoCalcFields must not be invoked on Normal fields. + The SetAutoCalcFields method should only be used with FlowFields or fields of type Blob. The field {0} is not a FlowField or of type Blob. - SetAutoCalcFields must not be invoked on Normal fields. + The SetAutoCalcFields method should only be used with FlowFields or fields of type Blob. The field {0} is not a FlowField or of type Blob. - SetAutoCalcFields must not be invoked on Normal fields. + The SetAutoCalcFields method should only be used with FlowFields or fields of type Blob. The field {0} is not a FlowField or of type Blob. \ No newline at end of file From d0aa20f8b3f81e68ddb97e90af3b119b83f62a1f Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Wed, 6 Dec 2023 15:32:27 +0100 Subject: [PATCH 11/12] Raise default severity to Warning --- LinterCopAnalyzers.Generated.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LinterCopAnalyzers.Generated.cs b/LinterCopAnalyzers.Generated.cs index 69e51f5c..3a8283a8 100644 --- a/LinterCopAnalyzers.Generated.cs +++ b/LinterCopAnalyzers.Generated.cs @@ -47,6 +47,6 @@ public static class DiagnosticDescriptors public static readonly DiagnosticDescriptor Rule0039ArgumentDifferentTypeThenExpected = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0039", (LocalizableString)new LocalizableResourceString("Rule0039ArgumentDifferentTypeThenExpectedTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0039ArgumentDifferentTypeThenExpectedFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Warning, true, (LocalizableString)new LocalizableResourceString("Rule0039ArgumentDifferentTypeThenExpectedDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0039"); public static readonly DiagnosticDescriptor Rule0040ExplicitlySetRunTrigger = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0040", (LocalizableString)new LocalizableResourceString("Rule0040ExplicitlySetRunTriggerTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0040ExplicitlySetRunTriggerFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0040ExplicitlySetRunTriggerDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0040"); public static readonly DiagnosticDescriptor Rule0041EmptyCaptionLocked = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0041", (LocalizableString)new LocalizableResourceString("Rule0041EmptyCaptionLockedTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0041EmptyCaptionLockedFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0041EmptyCaptionLockedDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0041"); - public static readonly DiagnosticDescriptor Rule0042AutoCalcFieldsOnNormalFields = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0042", (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0042"); + public static readonly DiagnosticDescriptor Rule0042AutoCalcFieldsOnNormalFields = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0042", (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Warning, true, (LocalizableString)new LocalizableResourceString("Rule0042AutoCalcFieldsOnNormalFieldsDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0042"); } } \ No newline at end of file From d597b8828443531302204d58f7256aa04ec54a32 Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Wed, 6 Dec 2023 15:38:06 +0100 Subject: [PATCH 12/12] Add new rules to the documentation --- LinterCop.ruleset.json | 15 +++++++++++++++ README.md | 3 +++ 2 files changed, 18 insertions(+) diff --git a/LinterCop.ruleset.json b/LinterCop.ruleset.json index ab409fc9..8eb136fd 100644 --- a/LinterCop.ruleset.json +++ b/LinterCop.ruleset.json @@ -196,6 +196,21 @@ "id": "LC0039", "action": "Warning", "justification": "The given argument has a different type from the one expected." + }, + { + "id": "LC0040", + "action": "Info", + "justification": "Explicitly set the RunTrigger parameter on build-in methods." + }, + { + "id": "LC0041", + "action": "Info", + "justification": "Empty Captions should be Locked." + }, + { + "id": "LC0042", + "action": "Warning", + "justification": "AutoCalcFields should only be used for FlowFields or Blob fields." } ] } \ No newline at end of file diff --git a/README.md b/README.md index 7de633c9..3f1385ab 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,9 @@ Further note that you should have BcContainerHelper version 2.0.16 (or newer) in |[LC0037](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0037)|Do not use line breaks in ToolTip.|Info| |[LC0038](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0038)|Try to not exceed 200 characters (including spaces).|Info| |[LC0039](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0039)|The given argument has a different type from the one expected.|Warning| +|[LC0040](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0040)|Explicitly set the `RunTrigger` parameter on build-in methods.|Info| +|[LC0041](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0041)|Empty Captions should be `Locked`.|Info| +|[LC0042](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0042)|`AutoCalcFields` should only be used for FlowFields or Blob fields.|Warning| ## Configuration