Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// The stored relation is Microsoft.Sales.History/"Sales Cr.Memo Header" ->
// Microsoft.EServices.EDocument/"E-Invoice Export Header". Here the namespace is declared
// with different literal casing ("microsoft.sales.history"). AL namespaces are
// case-insensitive, so the relation must still match and the diagnostic must still fire.
namespace microsoft.sales.history;

table 50140 "Sales Cr.Memo Header"
{
fields
{
field(1; "No."; Code[20]) { }
}
}

table 50141 "E-Invoice Export Header"
{
fields
{
field(1; "No."; Code[20]) { }
}
}

tableextension 50142 MyCrMemoExt extends "Sales Cr.Memo Header"
{
fields
{
[|field(50100; MyFieldA; Integer) { }|]
}
}

tableextension 50143 MyEInvExt extends "E-Invoice Export Header"
{
fields
{
[|field(50100; MyFieldB; Integer) { }|] // Same ID (50100) as in MyCrMemoExt, different name
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ public void Setup()
[TestCase("InvocationWithTableExtension")]
[TestCase("TableExt_Multiple_SameBase")]
[TestCase("TableExtension")]
[TestCase("TableExt_NamespaceCasingMismatch")]
public async Task HasDiagnostic(string testCase)
{
SkipTestIfVersionIsTooLow(
["InvocationWithTableExtension", "TableExt_Multiple_SameBase", "TableExtension", "TableExtensionTypeWithLength"],
["InvocationWithTableExtension", "TableExt_Multiple_SameBase", "TableExtension", "TableExtensionTypeWithLength", "TableExt_NamespaceCasingMismatch"],
testCase,
"13.0",
"No support for tableextensions when target itself is already declared in the same module");
Expand Down
11 changes: 7 additions & 4 deletions src/ALCops.PlatformCop/Analyzers/TransferFieldsRelations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,16 @@ private static bool Matches(ObjectName configured, ITableTypeSymbol table)
var ns = table.GetContainingNamespaceQualifiedNameWithReflection() ?? string.Empty;
var name = table.Name ?? string.Empty;

if (StringComparer.Ordinal.Equals(configured.Name, name) &&
StringComparer.Ordinal.Equals(configured.Namespace, ns))
// AL namespaces and object identifiers are case-insensitive, but the runtime-resolved
// namespace casing (symbol.ContainingNamespace.QualifiedName) is not stable across
// compilations, so both comparisons must be case-insensitive.
if (SemanticFacts.IsSameName(configured.Name, name) &&
SemanticFacts.IsSameName(configured.Namespace, ns))
return true;

// Keep backwards comptibility for objects without namespace
// Keep backwards compatibility for objects without namespace
if (string.IsNullOrEmpty(ns) &&
StringComparer.Ordinal.Equals(configured.Name, name))
SemanticFacts.IsSameName(configured.Name, name))
return true;

return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,12 @@ private static void AnalyzeTableExtensionForRelation(SymbolAnalysisContext ctx,

var sourceTableExtensions =
tableExtensions
.Where(te => te.Target is not null && te.Target.Name.Equals(relation.Source.Name))
.Where(te => te.Target is not null && SemanticFacts.IsSameName(te.Target.Name, relation.Source.Name))
.SelectMany(x => x.AddedFields);

var targetTableExtensions =
tableExtensions
.Where(te => te.Target is not null && te.Target.Name.Equals(relation.Target.Name))
.Where(te => te.Target is not null && SemanticFacts.IsSameName(te.Target.Name, relation.Target.Name))
.SelectMany(x => x.AddedFields);

var sourceById = BuildFieldMapById(sourceTableExtensions);
Expand Down
Loading