From 789b81c4a648913d12540096f367968181522e95 Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Mon, 8 Jan 2024 10:48:49 +0100 Subject: [PATCH 1/3] Typo --- LinterCopAnalyzers.resx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LinterCopAnalyzers.resx b/LinterCopAnalyzers.resx index c95b9347..75b4a07c 100644 --- a/LinterCopAnalyzers.resx +++ b/LinterCopAnalyzers.resx @@ -547,12 +547,12 @@ Use Error with a ErrorInfo or Label variable to improve telemetry details. - "SourceTable property not defined on {0} '{1}'. + SourceTable property not defined on {0} '{1}'. - "SourceTable property not defined on {0} '{1}'. + SourceTable property not defined on {0} '{1}'. - "SourceTable property not defined on {0} '{1}'. + SourceTable property not defined on {0} '{1}'. \ No newline at end of file From abaac4343cd2a41974a3944bf1d59095cf3f8fdd Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Mon, 8 Jan 2024 12:07:21 +0100 Subject: [PATCH 2/3] New Rule0050 unsupported operator SetFilter --- ...SetFilterOperatorCharInFilterExpression.cs | 57 +++++++++++++++++++ LinterCop.ruleset.json | 5 ++ LinterCopAnalyzers.Generated.cs | 1 + LinterCopAnalyzers.resx | 9 +++ README.md | 1 + 5 files changed, 73 insertions(+) create mode 100644 Design/Rule0050SetFilterOperatorCharInFilterExpression.cs diff --git a/Design/Rule0050SetFilterOperatorCharInFilterExpression.cs b/Design/Rule0050SetFilterOperatorCharInFilterExpression.cs new file mode 100644 index 00000000..0cf772c6 --- /dev/null +++ b/Design/Rule0050SetFilterOperatorCharInFilterExpression.cs @@ -0,0 +1,57 @@ +using Microsoft.Dynamics.Nav.CodeAnalysis; +using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics; +using Microsoft.Dynamics.Nav.CodeAnalysis.Symbols; +using System.Collections.Immutable; + +namespace BusinessCentral.LinterCop.Design +{ + [DiagnosticAnalyzer] + public class Rule0050SetFilterOperatorCharInFilterExpression : DiagnosticAnalyzer + { + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0050SetFilterOperatorCharInFilterExpression); + private static readonly List unsupportedOperators = new List + { + '*', '?', '@' + }; + + public override void Initialize(AnalysisContext context) => context.RegisterOperationAction(new Action(this.AnalyzeInvocation), OperationKind.InvocationExpression); + + private void AnalyzeInvocation(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 (operation.TargetMethod == null || !SemanticFacts.IsSameName(operation.TargetMethod.Name, "SetFilter") || operation.Arguments.Count() < 2) + return; + + CheckParameter(operation.Arguments[1].Value, ref operation, ref ctx); + } + + private void CheckParameter(IOperation operand, ref IInvocationExpression operation, ref OperationAnalysisContext ctx) + { + if (operand.Type.GetNavTypeKindSafe() != NavTypeKind.String && operand.Type.GetNavTypeKindSafe() != NavTypeKind.Joker) + return; + + if (operand.Syntax.Kind != SyntaxKind.LiteralExpression) + return; + + string parameterString = operand.Syntax.ToFullString(); + foreach (char unsupportedOperator in unsupportedOperators) + { + ctx.CancellationToken.ThrowIfCancellationRequested(); + + if (parameterString.Contains(unsupportedOperator)) + { + ctx.ReportDiagnostic( + Diagnostic.Create( + DiagnosticDescriptors.Rule0050SetFilterOperatorCharInFilterExpression, + operation.Syntax.GetLocation(), new object[] { unsupportedOperator })); + break; + } + } + } + } +} \ No newline at end of file diff --git a/LinterCop.ruleset.json b/LinterCop.ruleset.json index 20934c11..9c474dd7 100644 --- a/LinterCop.ruleset.json +++ b/LinterCop.ruleset.json @@ -246,6 +246,11 @@ "id": "LC0049", "action": "Info", "justification": "SourceTable property not defined on Page." + }, + { + "id": "LC0050", + "action": "Info", + "justification": "SetFilter with unsupported operator in filter expression." } ] } \ No newline at end of file diff --git a/LinterCopAnalyzers.Generated.cs b/LinterCopAnalyzers.Generated.cs index b21712fa..67621a84 100644 --- a/LinterCopAnalyzers.Generated.cs +++ b/LinterCopAnalyzers.Generated.cs @@ -56,5 +56,6 @@ public static class DiagnosticDescriptors public static readonly DiagnosticDescriptor Rule0047LockedLabelsTok = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0047", (LocalizableString)new LocalizableResourceString("Rule0047LockedLabelsTokTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0047LockedLabelsTokFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0047LockedLabelsTokDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0047"); public static readonly DiagnosticDescriptor Rule0048ErrorWithTextConstant = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0048", (LocalizableString)new LocalizableResourceString("Rule0048ErrorWithTextConstantTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0048ErrorWithTextConstantFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0048ErrorWithTextConstantDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0048"); public static readonly DiagnosticDescriptor Rule0049PageWithoutSourceTable = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0049", (LocalizableString)new LocalizableResourceString("Rule0049PageWithoutSourceTableTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0049PageWithoutSourceTableFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0049PageWithoutSourceTableDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0049"); + public static readonly DiagnosticDescriptor Rule0050SetFilterOperatorCharInFilterExpression = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0050", (LocalizableString)new LocalizableResourceString("Rule0050SetFilterOperatorCharInFilterExpressionTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0050SetFilterOperatorCharInFilterExpressionFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0050SetFilterOperatorCharInFilterExpressionDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0050"); } } \ No newline at end of file diff --git a/LinterCopAnalyzers.resx b/LinterCopAnalyzers.resx index 75b4a07c..552fd24d 100644 --- a/LinterCopAnalyzers.resx +++ b/LinterCopAnalyzers.resx @@ -555,4 +555,13 @@ SourceTable property not defined on {0} '{1}'. + + Operator '{0}' found in filter expression, currently treated as a literal character. Implement StrSubstNo() to apply '{0}' as operator. + + + Operator '{0}' found in filter expression, currently treated as a literal character. Implement StrSubstNo() to apply '{0}' as operator. + + + Operator '{0}' found in filter expression, currently treated as a literal character. Implement StrSubstNo() to apply '{0}' as operator. + \ No newline at end of file diff --git a/README.md b/README.md index 5b3ff6a2..a3f1df49 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ Further note that you should have BcContainerHelper version 2.0.16 (or newer) in |[LC0047](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0047)|Locked `Label` must have a suffix Tok.|Info| |[LC0048](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0048)|Use Error with a `ErrorInfo` or `Label` variable to improve telemetry details.|Info| |[LC0049](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0049)|`SourceTable` property not defined on Page.|Info| +|[LC0050](https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0050)| `SetFilter` with unsupported operator in filter expression.|Info| ## Configuration From ea9ffc5e813000834e5423ad7f85ef461932f957 Mon Sep 17 00:00:00 2001 From: Arthur van de Vondervoort Date: Mon, 8 Jan 2024 12:09:53 +0100 Subject: [PATCH 3/3] Show all unsupported operators --- Design/Rule0050SetFilterOperatorCharInFilterExpression.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Design/Rule0050SetFilterOperatorCharInFilterExpression.cs b/Design/Rule0050SetFilterOperatorCharInFilterExpression.cs index 0cf772c6..3b9f4b16 100644 --- a/Design/Rule0050SetFilterOperatorCharInFilterExpression.cs +++ b/Design/Rule0050SetFilterOperatorCharInFilterExpression.cs @@ -49,7 +49,6 @@ private void CheckParameter(IOperation operand, ref IInvocationExpression operat Diagnostic.Create( DiagnosticDescriptors.Rule0050SetFilterOperatorCharInFilterExpression, operation.Syntax.GetLocation(), new object[] { unsupportedOperator })); - break; } } }