diff --git a/BusinessCentral.LinterCop.Test/Rule0068.cs b/BusinessCentral.LinterCop.Test/Rule0068.cs index a26ddbe3..f3189453 100644 --- a/BusinessCentral.LinterCop.Test/Rule0068.cs +++ b/BusinessCentral.LinterCop.Test/Rule0068.cs @@ -39,6 +39,8 @@ public async Task HasDiagnostic(string testCase) #if Fall2023RV1 [TestCase("ProcedureCallsPermissionsPropertyFullyQualified")] #endif + // [TestCase("IntegerTable")] + [TestCase("XMLPortWithTableElementProps")] public async Task NoDiagnostic(string testCase) { var code = await File.ReadAllTextAsync(Path.Combine(_testCaseDir, "NoDiagnostic", $"{testCase}.al")) diff --git a/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/IntegerTable.al b/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/IntegerTable.al new file mode 100644 index 00000000..151fad63 --- /dev/null +++ b/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/IntegerTable.al @@ -0,0 +1,10 @@ +codeunit 50000 MyCodeunit +{ + trigger OnRun() + var + Integer: Record Integer; + begin + [|Integer.FindFirst();|] + end; +} + diff --git a/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/ProcedureCallsInherentPermissionsAttribute.al b/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/ProcedureCallsInherentPermissionsAttribute.al index 28f54c6e..14d4e16c 100644 --- a/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/ProcedureCallsInherentPermissionsAttribute.al +++ b/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/ProcedureCallsInherentPermissionsAttribute.al @@ -1,7 +1,7 @@ codeunit 50000 MyCodeunit { - [InherentPermissions(PermissionObjectType::TableData, Database::MyTable, 'rimd')] + [InherentPermissions(PermissionObjectType::TableData, Database::MyTable, 'RIMD')] local procedure Test() var MyTable: Record MyTable; diff --git a/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/XMLPortWithTableElementProps.al b/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/XMLPortWithTableElementProps.al new file mode 100644 index 00000000..ed61e052 --- /dev/null +++ b/BusinessCentral.LinterCop.Test/TestCases/Rule0068/NoDiagnostic/XMLPortWithTableElementProps.al @@ -0,0 +1,41 @@ +xmlport 50000 MyXmlport +{ + Direction = Import; + + schema + { + textelement(NodeName1) + { + [|tableelement(NodeName2; MyTable)|] + { + AutoReplace = false; // modify permissions + AutoSave = false; // insert permissions + AutoUpdate = false; //modify permissions + + fieldattribute(NodeName3; NodeName2.MyField) + { + + } + } + } + } +} + +table 50000 MyTable +{ + Caption = '', Locked = true; + + fields + { + field(1; MyField; Integer) + { + Caption = '', Locked = true; + DataClassification = ToBeClassified; + } + field(2; MyField2; Integer) + { + Caption = '', Locked = true; + DataClassification = ToBeClassified; + } + } +} \ No newline at end of file diff --git a/BusinessCentral.LinterCop/Design/Rule0025InternalProcedureModifier.cs b/BusinessCentral.LinterCop/Design/Rule0025InternalProcedureModifier.cs index 3102eb16..9956e7d3 100644 --- a/BusinessCentral.LinterCop/Design/Rule0025InternalProcedureModifier.cs +++ b/BusinessCentral.LinterCop/Design/Rule0025InternalProcedureModifier.cs @@ -19,15 +19,20 @@ private void AnalyzeInternalProcedures(SyntaxNodeAnalysisContext ctx) if (ctx.IsObsoletePendingOrRemoved()) return; if (ctx.ContainingSymbol.GetContainingObjectTypeSymbol().DeclaredAccessibility != Accessibility.Public) return; - - MethodDeclarationSyntax methodDeclarationSyntax = (MethodDeclarationSyntax)ctx.Node; - SyntaxNodeOrToken accessModifier = methodDeclarationSyntax.ProcedureKeyword.GetPreviousToken(); - - if (accessModifier.Kind == SyntaxKind.LocalKeyword || accessModifier.Kind == SyntaxKind.InternalKeyword) return; - - if (methodDeclarationSyntax.GetLeadingTrivia().Where(x => x.Kind == SyntaxKind.SingleLineDocumentationCommentTrivia).Any()) return; - - ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0025InternalProcedureModifier, methodDeclarationSyntax.ProcedureKeyword.GetLocation())); + if (!ctx.Node.IsKind(SyntaxKind.MethodDeclaration)) return; + + try + { + MethodDeclarationSyntax methodDeclarationSyntax = (MethodDeclarationSyntax)ctx.Node; + SyntaxNodeOrToken accessModifier = methodDeclarationSyntax.ProcedureKeyword.GetPreviousToken(); + if (accessModifier.Kind == SyntaxKind.LocalKeyword || accessModifier.Kind == SyntaxKind.InternalKeyword) return; + if (methodDeclarationSyntax.GetLeadingTrivia().Where(x => x.Kind == SyntaxKind.SingleLineDocumentationCommentTrivia).Any()) return; + ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0025InternalProcedureModifier, methodDeclarationSyntax.ProcedureKeyword.GetLocation())); + } + catch (System.InvalidCastException) + { + return; + } } } } \ No newline at end of file diff --git a/BusinessCentral.LinterCop/Design/Rule0068CheckObjectPermission.cs b/BusinessCentral.LinterCop/Design/Rule0068CheckObjectPermission.cs index 8be317ee..f8b2efbb 100644 --- a/BusinessCentral.LinterCop/Design/Rule0068CheckObjectPermission.cs +++ b/BusinessCentral.LinterCop/Design/Rule0068CheckObjectPermission.cs @@ -63,12 +63,22 @@ private void CheckXmlportNodeObjectPermission(SymbolAnalysisContext ctx) else direction = directionProperty.ValueText; + bool? AutoReplace = (bool?)ctx.Symbol.Properties.FirstOrDefault(property => property.PropertyKind == PropertyKind.AutoReplace)?.Value; // modify permissions + bool? AutoUpdate = (bool?)ctx.Symbol.Properties.FirstOrDefault(property => property.PropertyKind == PropertyKind.AutoUpdate)?.Value; // modify permissions + bool? AutoSave = (bool?)ctx.Symbol.Properties.FirstOrDefault(property => property.PropertyKind == PropertyKind.AutoSave)?.Value; // insert permissions + + AutoReplace ??= true; + AutoUpdate ??= true; + AutoSave ??= true; + direction = direction.ToLowerInvariant(); if (direction == "import" || direction == "both") { - CheckProcedureInvocation(objectPermissions, targetSymbol, 'm', ctx.ReportDiagnostic, ctx.Symbol.GetLocation(), (ITableTypeSymbol)targetSymbol.OriginalDefinition); - CheckProcedureInvocation(objectPermissions, targetSymbol, 'i', ctx.ReportDiagnostic, ctx.Symbol.GetLocation(), (ITableTypeSymbol)targetSymbol.OriginalDefinition); + if (AutoReplace == true || AutoUpdate == true) + CheckProcedureInvocation(objectPermissions, targetSymbol, 'm', ctx.ReportDiagnostic, ctx.Symbol.GetLocation(), (ITableTypeSymbol)targetSymbol.OriginalDefinition); + if (AutoSave == true) + CheckProcedureInvocation(objectPermissions, targetSymbol, 'i', ctx.ReportDiagnostic, ctx.Symbol.GetLocation(), (ITableTypeSymbol)targetSymbol.OriginalDefinition); } if (direction == "export" || direction == "both") CheckProcedureInvocation(objectPermissions, targetSymbol, 'r', ctx.ReportDiagnostic, ctx.Symbol.GetLocation(), (ITableTypeSymbol)targetSymbol.OriginalDefinition); @@ -161,7 +171,7 @@ private bool ProcedureHasInherentPermission(IEnumerable inhere if (permissions?[1].Trim() != "PermissionObjectType::TableData") continue; var typeAndObjectName = permissions[2].Trim(); - var permissionValue = permissions[3].Trim().Trim(new[] { '\'', ' ' }); + var permissionValue = permissions[3].Trim().Trim(new[] { '\'', ' ' }).ToLowerInvariant(); var typeParts = typeAndObjectName.Split(new[] { "::" }, StringSplitOptions.RemoveEmptyEntries); if (typeParts.Length < 2) continue; @@ -173,7 +183,7 @@ private bool ProcedureHasInherentPermission(IEnumerable inhere #endif continue; - if (permissionValue.Contains(requestedPermission)) + if (permissionValue.Contains(requestedPermission.ToString().ToLowerInvariant()[0])) { return true; } @@ -183,6 +193,7 @@ private bool ProcedureHasInherentPermission(IEnumerable inhere private void CheckProcedureInvocation(IPropertySymbol? objectPermissions, ITypeSymbol variableType, char requestedPermission, Action ReportDiagnostic, Microsoft.Dynamics.Nav.CodeAnalysis.Text.Location location, ITableTypeSymbol targetTable) { + if (targetTable.Id > 2000000000) return; if (TableHasInherentPermission(targetTable, requestedPermission)) return; if (objectPermissions == null)