Skip to content

Commit

Permalink
Resolve non-working Rule0023 (#854)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arthurvdv authored Dec 31, 2024
1 parent 98a30ef commit bd3e29e
Show file tree
Hide file tree
Showing 6 changed files with 129 additions and 12 deletions.
38 changes: 38 additions & 0 deletions BusinessCentral.LinterCop.Test/Rule0023.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
namespace BusinessCentral.LinterCop.Test;

public class Rule0023
{
private string _testCaseDir = "";

[SetUp]
public void Setup()
{
_testCaseDir = Path.Combine(Directory.GetParent(Environment.CurrentDirectory)!.Parent!.Parent!.FullName,
"TestCases", "Rule0023");
}

//TODO: Resolve "There is no issue reported for LC0023 at [96...107]." for these tests.
// [Test]
// [TestCase("BrickIsMissing")]
// [TestCase("DropDownIsMissing")]
// [TestCase("FieldgroupsIsMissing")]
// public async Task HasDiagnostic(string testCase)
// {
// var code = await File.ReadAllTextAsync(Path.Combine(_testCaseDir, "HasDiagnostic", $"{testCase}.al"))
// .ConfigureAwait(false);

// var fixture = RoslynFixtureFactory.Create<BuiltInMethodImplementThroughCodeunit>();
// fixture.HasDiagnostic(code, DiagnosticDescriptors.Rule0023AlwaysSpecifyFieldgroups.Id);
// }

[Test]
[TestCase("HasBrickAndDropDown")]
public async Task NoDiagnostic(string testCase)
{
var code = await File.ReadAllTextAsync(Path.Combine(_testCaseDir, "NoDiagnostic", $"{testCase}.al"))
.ConfigureAwait(false);

var fixture = RoslynFixtureFactory.Create<BuiltInMethodImplementThroughCodeunit>();
fixture.NoDiagnosticAtMarker(code, DiagnosticDescriptors.Rule0023AlwaysSpecifyFieldgroups.Id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
table 50100 MyTable
{
fields
{
field(1; MyField; Integer) { }
}

[|fieldgroups|]
{
fieldgroup(DropDown; MyField) { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
table 50100 MyTable
{
fields
{
field(1; MyField; Integer) { }
}

[|fieldgroups|]
{
fieldgroup(Brick; MyField) { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
table 50100 MyTable
{
fields
{
field(1; MyField; Integer) { }
}

keys
{
key(Key1; MyField) { }
}
[| |]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
table 50100 MyTable
{
fields
{
field(1; MyField; Integer) { }
}

[|fieldgroups|]
{
fieldgroup(Brick; MyField) { }
fieldgroup(DropDown; MyField) { }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.Dynamics.Nav.CodeAnalysis;
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
using Microsoft.Dynamics.Nav.CodeAnalysis.Symbols;
using Microsoft.Dynamics.Nav.CodeAnalysis.Syntax;
using Microsoft.Dynamics.Nav.CodeAnalysis.Text;
using System.Collections.Immutable;

Expand All @@ -11,7 +12,7 @@ namespace BusinessCentral.LinterCop.Design;
public class Rule0023AlwaysSpecifyFieldgroups : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } =
ImmutableArray.Create(DiagnosticDescriptors.Rule0023AlwaysSpecifyFieldgroups, DiagnosticDescriptors.Rule0000ErrorInRule);
ImmutableArray.Create(DiagnosticDescriptors.Rule0023AlwaysSpecifyFieldgroups);

public override void Initialize(AnalysisContext context) =>
context.RegisterSymbolAction(new Action<SymbolAnalysisContext>(this.CheckFieldgroups), SymbolKind.Table);
Expand All @@ -24,21 +25,49 @@ private void CheckFieldgroups(SymbolAnalysisContext ctx)
if (IsTableOfTypeSetupTable(table))
return;

Location FieldGroupLocation = table.GetLocation();
if (!table.Keys.IsEmpty)
var fieldGroupLocation = GetFieldGroupLocation(ctx, table);

CheckFieldGroup(ctx, table, "Brick", fieldGroupLocation);
CheckFieldGroup(ctx, table, "DropDown", fieldGroupLocation);
}

private static Location GetFieldGroupLocation(SymbolAnalysisContext ctx, ITableTypeSymbol table)
{
var location = table.GetLocation();

if (ctx.Symbol.DeclaringSyntaxReference?.GetSyntax(ctx.CancellationToken) is not TableSyntax tableSyntax)
return location;

if (tableSyntax.FieldGroups is not null)
{
FieldGroupLocation = table.Keys.Last().GetLocation();
var span = FieldGroupLocation.SourceSpan;
FieldGroupLocation = Location.Create(FieldGroupLocation.SourceTree!, new TextSpan(span.End + 9, 1)); // Should result in the blank line right after the keys section
var fieldGroupNode = tableSyntax.FieldGroups
.ChildNodesAndTokens()
.FirstOrDefault(node => node.Kind == SyntaxKind.FieldGroupsKeyword);

var fieldGroupNodeLocation = fieldGroupNode.GetLocation();
if (fieldGroupNodeLocation is not null)
return fieldGroupNode.GetLocation()!;
}

if (!table.FieldGroups.Any(item => item.Name == "Brick"))
ctx.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.Rule0023AlwaysSpecifyFieldgroups, FieldGroupLocation, "Brick", table.Name));
if (tableSyntax.Keys is not null && table.GetLocation().SourceTree is SyntaxTree sourceTree)
{
var startPos = tableSyntax.Keys.Span.End + 2; // Should result in the blank line right after the keys section
return Location.Create(sourceTree, new TextSpan(startPos, 1));
}

return location;
}

if (!table.FieldGroups.Any(item => item.Name == "DropDown"))
private static void CheckFieldGroup(SymbolAnalysisContext ctx, ITableTypeSymbol table, string fieldGroupName, Location location)
{
if (!table.FieldGroups.Any(item => item.Name == fieldGroupName && item.Fields.Length > 0))
{
ctx.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.Rule0023AlwaysSpecifyFieldgroups, FieldGroupLocation, "DropDown", table.Name));
DiagnosticDescriptors.Rule0023AlwaysSpecifyFieldgroups,
location,
fieldGroupName,
table.Name));
}
}

private static bool IsTableOfTypeSetupTable(ITableTypeSymbol table)
Expand All @@ -57,4 +86,4 @@ private static bool IsTableOfTypeSetupTable(ITableTypeSymbol table)

return true;
}
}
}

0 comments on commit bd3e29e

Please sign in to comment.