diff --git a/BusinessCentral.LinterCop/Design/Rule0027RunPageImplementPageManagement.cs b/BusinessCentral.LinterCop/Design/Rule0027RunPageImplementPageManagement.cs index 0aaba4e2..90dfc905 100644 --- a/BusinessCentral.LinterCop/Design/Rule0027RunPageImplementPageManagement.cs +++ b/BusinessCentral.LinterCop/Design/Rule0027RunPageImplementPageManagement.cs @@ -10,9 +10,39 @@ namespace BusinessCentral.LinterCop.Design [DiagnosticAnalyzer] public class Rule0027RunPageImplementPageManagement : DiagnosticAnalyzer { - public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0027RunPageImplementPageManagement, DiagnosticDescriptors.Rule0000ErrorInRule); + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(DiagnosticDescriptors.Rule0027RunPageImplementPageManagement); - public override void Initialize(AnalysisContext context) => context.RegisterOperationAction(new Action(this.CheckRunPageImplementPageManagement), OperationKind.InvocationExpression); + private static readonly Dictionary _supportedRecords = new Dictionary + { + { 36, "Sales Header" }, + { 38, "Purchase Header" }, + { 79, "Company Information" }, + { 80, "Gen. Journal Template" }, + { 81, "Gen. Journal Line" }, + { 91, "User Setup" }, + { 98, "General Ledger Setup" }, + { 112, "Sales Invoice Header" }, + { 131, "Incoming Documents Setup" }, + { 207, "Res. Journal Line" }, + { 210, "Job Journal Line" }, + { 232, "Gen. Journal Batch" }, + { 312, "Purchases & Payables Setup" }, + { 454, "Approval Entry" }, + { 843, "Cash Flow Setup" }, + { 1251, "Text-to-Account Mapping" }, + { 1275, "Doc. Exch. Service Setup" }, + { 5107, "Sales Header Archive" }, + { 5109, "Purchase Header Archive" }, + { 5200, "Employee" }, + { 5405, "Production Order" }, + { 5900, "Service Header" }, + { 5965, "Service Contract Header" }, + { 7152, "Item Analysis View" }, + { 2000000120, "User" } + }; + + public override void Initialize(AnalysisContext context) + => context.RegisterOperationAction(new Action(this.CheckRunPageImplementPageManagement), OperationKind.InvocationExpression); private void CheckRunPageImplementPageManagement(OperationAnalysisContext ctx) { @@ -20,7 +50,6 @@ private void CheckRunPageImplementPageManagement(OperationAnalysisContext ctx) IInvocationExpression operation = (IInvocationExpression)ctx.Operation; if (operation.TargetMethod.MethodKind != MethodKind.BuiltInMethod) return; - if (operation.TargetMethod.ContainingType.GetTypeSymbol().GetNavTypeKindSafe() != NavTypeKind.Page) return; if (operation.Arguments.Count() < 2) return; @@ -38,15 +67,8 @@ private void CheckRunPageImplementPageManagement(OperationAnalysisContext ctx) break; case SyntaxKind.OptionAccessExpression: - try // Investigate https://github.com/StefanMaron/BusinessCentral.LinterCop/issues/682 - { - if (IsSupportedRecord(((IConversionExpression)operation.Arguments[1].Value).Operand)) - ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0027RunPageImplementPageManagement, ctx.Operation.Syntax.GetLocation())); - } - catch - { - ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0000ErrorInRule, ctx.Operation.Syntax.GetLocation(), new Object[] { "Rule0027", "IsSupportedRecord", "" })); - } + if (IsSupportedRecord(((IConversionExpression)operation.Arguments[1].Value).Operand)) + ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0027RunPageImplementPageManagement, ctx.Operation.Syntax.GetLocation())); break; default: @@ -57,52 +79,37 @@ private void CheckRunPageImplementPageManagement(OperationAnalysisContext ctx) private static bool IsSupportedRecord(IOperation operation) { IRecordTypeSymbol recordTypeSymbol = null; - - if (operation.Kind == OperationKind.GlobalReferenceExpression || operation.Kind == OperationKind.LocalReferenceExpression) - recordTypeSymbol = (IRecordTypeSymbol)operation.GetSymbol().GetTypeSymbol(); - - if (operation.Kind == OperationKind.InvocationExpression) - recordTypeSymbol = (IRecordTypeSymbol)operation.Type.GetTypeSymbol(); + switch (operation.Kind) + { + case OperationKind.GlobalReferenceExpression: + case OperationKind.LocalReferenceExpression: + recordTypeSymbol = operation.GetSymbol().GetTypeSymbol() as IRecordTypeSymbol; + break; + case OperationKind.InvocationExpression: + recordTypeSymbol = operation.Type.GetTypeSymbol() as IRecordTypeSymbol; + break; + default: + return false; + } if (recordTypeSymbol == null || recordTypeSymbol.Temporary) return false; - if (GetSupportedRecords().ContainsKey(recordTypeSymbol.Id)) - return SemanticFacts.IsSameName(recordTypeSymbol.Name, GetSupportedRecords()[recordTypeSymbol.Id]); + if (_supportedRecords.ContainsKey(recordTypeSymbol.Id)) + return SemanticFacts.IsSameName(recordTypeSymbol.Name, _supportedRecords[recordTypeSymbol.Id]); return false; } - private static Dictionary GetSupportedRecords() + public static class DiagnosticDescriptors { - Dictionary SupportedRecords = new Dictionary - { - { 36, "Sales Header" }, - { 38, "Purchase Header" }, - { 79, "Company Information" }, - { 80, "Gen. Journal Template" }, - { 81, "Gen. Journal Line" }, - { 91, "User Setup" }, - { 98, "General Ledger Setup" }, - { 112, "Sales Invoice Header" }, - { 131, "Incoming Documents Setup" }, - { 207, "Res. Journal Line" }, - { 210, "Job Journal Line" }, - { 232, "Gen. Journal Batch" }, - { 312, "Purchases & Payables Setup" }, - { 454, "Approval Entry" }, - { 843, "Cash Flow Setup" }, - { 1251, "Text-to-Account Mapping" }, - { 1275, "Doc. Exch. Service Setup" }, - { 5107, "Sales Header Archive" }, - { 5109, "Purchase Header Archive" }, - { 5200, "Employee" }, - { 5405, "Production Order" }, - { 5900, "Service Header" }, - { 5965, "Service Contract Header" }, - { 7152, "Item Analysis View" }, - { 2000000120, "User" } - }; - return SupportedRecords; + public static readonly DiagnosticDescriptor Rule0027RunPageImplementPageManagement = new( + id: LinterCopAnalyzers.AnalyzerPrefix + "0027", + title: LinterCopAnalyzers.GetLocalizableString("Rule0027RunPageImplementPageManagementTitle"), + messageFormat: LinterCopAnalyzers.GetLocalizableString("Rule0027RunPageImplementPageManagementFormat"), + category: "Design", + defaultSeverity: DiagnosticSeverity.Info, isEnabledByDefault: true, + description: LinterCopAnalyzers.GetLocalizableString("Rule0027RunPageImplementPageManagementDescription"), + helpLinkUri: "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0027"); } } } \ No newline at end of file diff --git a/BusinessCentral.LinterCop/Design/Rule0039ArgumentDifferentTypeThenExpected.cs b/BusinessCentral.LinterCop/Design/Rule0039ArgumentDifferentTypeThenExpected.cs index 70e653e1..23fae32e 100644 --- a/BusinessCentral.LinterCop/Design/Rule0039ArgumentDifferentTypeThenExpected.cs +++ b/BusinessCentral.LinterCop/Design/Rule0039ArgumentDifferentTypeThenExpected.cs @@ -49,7 +49,8 @@ private void AnalyzeRunPageArguments(OperationAnalysisContext ctx) if (pageSourceTable == null) return; IOperation operand = ((IConversionExpression)operation.Arguments[1].Value).Operand; - ITableTypeSymbol recordArgument = ((IRecordTypeSymbol)operand.GetSymbol().GetTypeSymbol()).BaseTable; + if (operand.GetSymbol().GetTypeSymbol() is not IRecordTypeSymbol recordTypeSymbol) return; + ITableTypeSymbol recordArgument = recordTypeSymbol.BaseTable; if (!AreTheSameNavObjects(recordArgument, pageSourceTable)) ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0039ArgumentDifferentTypeThenExpected, ctx.Operation.Syntax.GetLocation(), new object[] { 2, operand.GetSymbol().GetTypeSymbol().ToString(), pageSourceTable.GetNavTypeKindSafe() + pageSourceTable.Name.QuoteIdentifierIfNeeded() })); diff --git a/BusinessCentral.LinterCop/LinterCopAnalyzers.Generated.cs b/BusinessCentral.LinterCop/LinterCopAnalyzers.Generated.cs index 36c54f43..dce1b8e0 100644 --- a/BusinessCentral.LinterCop/LinterCopAnalyzers.Generated.cs +++ b/BusinessCentral.LinterCop/LinterCopAnalyzers.Generated.cs @@ -32,7 +32,6 @@ public static class DiagnosticDescriptors public static readonly DiagnosticDescriptor Rule0024SemicolonAfterMethodOrTriggerDeclaration = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0024", (LocalizableString)new LocalizableResourceString("Rule0024SemicolonAfterMethodOrTriggerDeclarationTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0024SemicolonAfterMethodOrTriggerDeclarationFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0024SemicolonAfterMethodOrTriggerDeclarationDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0024"); public static readonly DiagnosticDescriptor Rule0025InternalProcedureModifier = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0025", (LocalizableString)new LocalizableResourceString("Rule0025InternalProcedureModifierTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0025InternalProcedureModifierFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Hidden, true, (LocalizableString)new LocalizableResourceString("Rule0025InternalProcedureModifierDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0025"); public static readonly DiagnosticDescriptor Rule0026ToolTipMustEndWithDot = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0026", (LocalizableString)new LocalizableResourceString("Rule0026ToolTipMustEndWithDotTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0026ToolTipMustEndWithDotFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0026ToolTipMustEndWithDotDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0026"); - public static readonly DiagnosticDescriptor Rule0027RunPageImplementPageManagement = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0027", (LocalizableString)new LocalizableResourceString("Rule0027RunPageImplementPageManagement", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0027RunPageImplementPageManagement", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0027RunPageImplementPageManagement", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0027"); public static readonly DiagnosticDescriptor Rule0028IdentifiersInEventSubscribers = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0028", (LocalizableString)new LocalizableResourceString("Rule0028IdentifiersInEventSubscribersTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0028IdentifiersInEventSubscribersFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0028IdentifiersInEventSubscribersDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0028"); public static readonly DiagnosticDescriptor Rule0029CompareDateTimeThroughCodeunit = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0029", (LocalizableString)new LocalizableResourceString("Rule0029CompareDateTimeThroughCodeunitTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0029CompareDateTimeThroughCodeunitFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0029CompareDateTimeThroughCodeunitDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0029"); public static readonly DiagnosticDescriptor Rule0030AccessInternalForInstallAndUpgradeCodeunits = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0030", (LocalizableString)new LocalizableResourceString("Rule0030AccessInternalForInstallAndUpgradeCodeunitsTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0030AccessInternalForInstallAndUpgradeCodeunitsFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0030AccessInternalForInstallAndUpgradeCodeunitsDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0030"); diff --git a/BusinessCentral.LinterCop/LinterCopAnalyzers.resx b/BusinessCentral.LinterCop/LinterCopAnalyzers.resx index e48c5db3..eac3d811 100644 --- a/BusinessCentral.LinterCop/LinterCopAnalyzers.resx +++ b/BusinessCentral.LinterCop/LinterCopAnalyzers.resx @@ -345,9 +345,15 @@ ToolTip must end with a dot. - + + Utilize Page Management codeunit for launching page. + + Utilize the "Page Management" codeunit for launching page. + + Utilizing the Page Management codeunit rather than invoking Page.Run directly. + Event subscriber arguments now use identifier syntax instead of string literals.