diff --git a/src/ALCops.ApplicationCop/Analyzers/IntegrationEventInInternalCodeunit.cs b/src/ALCops.ApplicationCop/Analyzers/IntegrationEventInInternalCodeunit.cs
index 925a35d1..d6357fa3 100644
--- a/src/ALCops.ApplicationCop/Analyzers/IntegrationEventInInternalCodeunit.cs
+++ b/src/ALCops.ApplicationCop/Analyzers/IntegrationEventInInternalCodeunit.cs
@@ -28,7 +28,8 @@ private void AnalyzeIntegrationEvent(SymbolAnalysisContext ctx)
return;
IApplicationObjectTypeSymbol? applicationObject = methodSymbol.GetContainingApplicationObjectTypeSymbol();
- if (applicationObject is null || !IsInternalCodeunit(applicationObject) || applicationObject.IsObsolete())
+
+ if (applicationObject is null || !applicationObject.IsInternalCodeunit())
return;
if (!IsIntegrationEvent(methodSymbol))
@@ -41,10 +42,6 @@ private void AnalyzeIntegrationEvent(SymbolAnalysisContext ctx)
applicationObject.Name));
}
- private static bool IsInternalCodeunit(IApplicationObjectTypeSymbol applicationObject) =>
- applicationObject.Kind == EnumProvider.SymbolKind.Codeunit &&
- applicationObject.DeclaredAccessibility == EnumProvider.Accessibility.Internal;
-
private static bool IsIntegrationEvent(IMethodSymbol methodSymbol) =>
methodSymbol.Attributes.Any(attr => attr.AttributeKind == EnumProvider.AttributeKind.IntegrationEvent);
}
\ No newline at end of file
diff --git a/src/ALCops.ApplicationCop/Analyzers/TableDataAccessRequiresPermissions.cs b/src/ALCops.ApplicationCop/Analyzers/TableDataAccessRequiresPermissions.cs
index cbaf0acd..4969be8d 100644
--- a/src/ALCops.ApplicationCop/Analyzers/TableDataAccessRequiresPermissions.cs
+++ b/src/ALCops.ApplicationCop/Analyzers/TableDataAccessRequiresPermissions.cs
@@ -48,7 +48,7 @@ private void AnalyzeInvocation(OperationAnalysisContext ctx)
if (required is null)
return;
- if (RequiredPermissionDetector.IsTestCodeunitWithPermissionsDisabled(containingObject))
+ if (containingObject.IsTestCodeunitWithPermissionsDisabled())
return;
var pageContext = PermissionResolver.GetPageContext(containingObject);
diff --git a/src/ALCops.ApplicationCop/Analyzers/TableDataAccessUnusedPermissions.cs b/src/ALCops.ApplicationCop/Analyzers/TableDataAccessUnusedPermissions.cs
index af7888d9..c953c4f9 100644
--- a/src/ALCops.ApplicationCop/Analyzers/TableDataAccessUnusedPermissions.cs
+++ b/src/ALCops.ApplicationCop/Analyzers/TableDataAccessUnusedPermissions.cs
@@ -42,7 +42,7 @@ private static void AnalyzeApplicationObject(SyntaxNodeAnalysisContext ctx)
if (containingObject.Kind == EnumProvider.SymbolKind.PermissionSet
|| containingObject.Kind == EnumProvider.SymbolKind.PermissionSetExtension
|| containingObject.IsObsolete()
- || RequiredPermissionDetector.IsTestCodeunitWithPermissionsDisabled(containingObject))
+ || containingObject.IsTestCodeunitWithPermissionsDisabled())
return;
var permissionsProperty = containingObject.GetProperty(EnumProvider.PropertyKind.Permissions);
diff --git a/src/ALCops.Common/Extensions/ApplicationObjectTypeSymbolInterfaceExtensions.cs b/src/ALCops.Common/Extensions/ApplicationObjectTypeSymbolInterfaceExtensions.cs
index e1522a7e..1c776220 100644
--- a/src/ALCops.Common/Extensions/ApplicationObjectTypeSymbolInterfaceExtensions.cs
+++ b/src/ALCops.Common/Extensions/ApplicationObjectTypeSymbolInterfaceExtensions.cs
@@ -44,6 +44,43 @@ public static bool MethodImplementsInterfaceMethod(this IApplicationObjectTypeSy
return false;
}
+ ///
+ /// Returns true if the object is a test codeunit with TestPermissions = Disabled.
+ ///
+ public static bool IsTestCodeunitWithPermissionsDisabled(this IApplicationObjectTypeSymbol? containingObject)
+ {
+ if (!containingObject.IsTestCodeunit())
+ {
+ return false;
+ }
+
+ var testPermissions = (containingObject as ICodeunitTypeSymbol)?.GetEnumPropertyValue(EnumProvider.PropertyKind.TestPermissions);
+
+ return testPermissions is not null && testPermissions == EnumProvider.TestPermissionsKind.Disabled;
+ }
+
+ ///
+ /// Returns true if the object is a test codeunit.
+ ///
+ public static bool IsTestCodeunit(this IApplicationObjectTypeSymbol? objectSymbol)
+ {
+ if (objectSymbol is not ICodeunitTypeSymbol codeunit)
+ {
+ return false;
+ }
+
+ var subtype = codeunit.GetEnumPropertyValue(EnumProvider.PropertyKind.Subtype);
+
+ return (subtype is not null) && (subtype == EnumProvider.CodeunitSubtypeKind.Test);
+ }
+
+ ///
+ /// Returns true if the object is a codeunit with accessability internal.
+ ///
+ public static bool IsInternalCodeunit(this IApplicationObjectTypeSymbol applicationObject) =>
+ applicationObject.Kind == EnumProvider.SymbolKind.Codeunit &&
+ applicationObject.DeclaredAccessibility == EnumProvider.Accessibility.Internal;
+
///
/// Gets the flattened list of all xmlport nodes (including deeply nested) for xmlport objects.
/// Uses reflection to access the internal SourceXmlPortTypeSymbol.FlattenedNodes property,
diff --git a/src/ALCops.Common/Extensions/MethodSymbolInterfaceExtensions.cs b/src/ALCops.Common/Extensions/MethodSymbolInterfaceExtensions.cs
index b01f7421..9bd179a7 100644
--- a/src/ALCops.Common/Extensions/MethodSymbolInterfaceExtensions.cs
+++ b/src/ALCops.Common/Extensions/MethodSymbolInterfaceExtensions.cs
@@ -22,6 +22,19 @@ public static bool MethodImplementsInterfaceMethod(this IMethodSymbol methodSymb
public static bool IsHandler(this IMethodSymbol method)
=> method.GetPropertyIfExists("IsHandler");
+ ///
+ /// Checks whether the method is an IntegrationEvent or BusinessEvent.
+ ///
+ public static bool IsIntegrationOrBusinessEvent(this IMethodSymbol methodSymbol) =>
+ methodSymbol.Attributes.Any(attr => (attr.AttributeKind == EnumProvider.AttributeKind.IntegrationEvent) || (attr.AttributeKind == EnumProvider.AttributeKind.BusinessEvent));
+
+ ///
+ /// Checks whether the method is an InternalEvent.
+ ///
+ public static bool IsInternalEvent(this IMethodSymbol methodSymbol) =>
+ methodSymbol.Attributes.Any(attr => attr.AttributeKind == EnumProvider.AttributeKind.InternalEvent);
+
+
public static bool MethodImplementsInterfaceMethod(this IMethodSymbol methodSymbol, IMethodSymbol interfaceMethodSymbol)
{
if (methodSymbol is null || interfaceMethodSymbol is null)
diff --git a/src/ALCops.Common/Permissions/RequiredPermissionDetector.cs b/src/ALCops.Common/Permissions/RequiredPermissionDetector.cs
index 17735269..087fc293 100644
--- a/src/ALCops.Common/Permissions/RequiredPermissionDetector.cs
+++ b/src/ALCops.Common/Permissions/RequiredPermissionDetector.cs
@@ -125,21 +125,6 @@ public static IEnumerable GetFromXmlPortNode(ISymbol symbol,
///
public static bool IsSystemTable(ITableTypeSymbol table) => table.Id > 2000000000;
- ///
- /// Returns true if the object is a test codeunit with TestPermissions = Disabled.
- ///
- public static bool IsTestCodeunitWithPermissionsDisabled(IApplicationObjectTypeSymbol? containingObject)
- {
- if (containingObject is not ICodeunitTypeSymbol codeunit)
- return false;
-
- var subtype = codeunit.GetEnumPropertyValue(EnumProvider.PropertyKind.Subtype);
- if (subtype is null || subtype != EnumProvider.CodeunitSubtypeKind.Test)
- return false;
-
- var testPermissions = codeunit.GetEnumPropertyValue(EnumProvider.PropertyKind.TestPermissions);
- return testPermissions is not null && testPermissions == EnumProvider.TestPermissionsKind.Disabled;
- }
private static DirectionKind ResolveXmlPortDirection(IXmlPortTypeSymbol xmlPort)
{
diff --git a/src/ALCops.Common/Reflection/EnumProvider.cs b/src/ALCops.Common/Reflection/EnumProvider.cs
index bfe14f68..6f27aca0 100644
--- a/src/ALCops.Common/Reflection/EnumProvider.cs
+++ b/src/ALCops.Common/Reflection/EnumProvider.cs
@@ -796,6 +796,8 @@ public static class SymbolKind
new(() => ParseEnum(nameof(NavCodeAnalysis.SymbolKind.Codeunit)));
private static readonly Lazy _control =
new(() => ParseEnum(nameof(NavCodeAnalysis.SymbolKind.Control)));
+ private static readonly Lazy _controlAddIn =
+ new(() => ParseEnum(nameof(NavCodeAnalysis.SymbolKind.ControlAddIn)));
private static readonly Lazy _entitlement =
new(() => ParseEnum(nameof(NavCodeAnalysis.SymbolKind.Entitlement)));
private static readonly Lazy _enum =
@@ -864,6 +866,7 @@ public static class SymbolKind
public static NavCodeAnalysis.SymbolKind Action => _action.Value;
public static NavCodeAnalysis.SymbolKind Class => _class.Value;
public static NavCodeAnalysis.SymbolKind Codeunit => _codeunit.Value;
+ public static NavCodeAnalysis.SymbolKind ControlAddIn => _controlAddIn.Value;
public static NavCodeAnalysis.SymbolKind Control => _control.Value;
public static NavCodeAnalysis.SymbolKind Entitlement => _entitlement.Value;
public static NavCodeAnalysis.SymbolKind Enum => _enum.Value;
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/InternalHasDiagnostic/InternalCodeunit.al b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/InternalHasDiagnostic/InternalCodeunit.al
new file mode 100644
index 00000000..b76b2bc5
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/InternalHasDiagnostic/InternalCodeunit.al
@@ -0,0 +1,8 @@
+codeunit 50100 [|MyCodeunit|]
+{
+ Access = Internal;
+
+ procedure MyProcedure()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/InternalNoDiagnostic/InternalCodeunit.al b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/InternalNoDiagnostic/InternalCodeunit.al
new file mode 100644
index 00000000..7847b803
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/InternalNoDiagnostic/InternalCodeunit.al
@@ -0,0 +1,11 @@
+///
+/// A great piece of code that solves all problems.
+///
+codeunit 50100 [|MyCodeunit|]
+{
+ Access = Internal;
+
+ procedure MyProcedure()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/ObjectRequiresDocumentation.cs b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/ObjectRequiresDocumentation.cs
new file mode 100644
index 00000000..5f67cd53
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/ObjectRequiresDocumentation.cs
@@ -0,0 +1,66 @@
+using RoslynTestKit;
+
+namespace ALCops.DocumentationCop.Test
+{
+ public class ObjectRequiresDocumentation : NavCodeAnalysisBase
+ {
+ private AnalyzerTestFixture _fixture;
+ private string _testCasePath;
+
+ [SetUp]
+ public void Setup()
+ {
+ _testCasePath = Path.Combine(
+ Directory.GetParent(
+ Environment.CurrentDirectory)!.Parent!.Parent!.FullName,
+ Path.Combine("Rules", nameof(ObjectRequiresDocumentation)));
+
+ _fixture = RoslynFixtureFactory.Create(
+ // Inject a ruleset to enable testing for rules, that are not enabled by default (isEnabledByDefault: false).
+ new AnalyzerTestFixtureConfig
+ {
+ RuleSetPath = Path.Combine(_testCasePath, $"{nameof(ObjectRequiresDocumentation)}.ruleset.json")
+ });
+ }
+
+ [Test]
+ [TestCase("PublicCodeunit")]
+ public async Task PublicHasDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(PublicHasDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.PublicObjectRequiresDocumentation);
+ }
+
+ [Test]
+ [TestCase("PublicCodeunit")]
+ public async Task PublicNoDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(PublicNoDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.PublicObjectRequiresDocumentation);
+ }
+
+ [Test]
+ [TestCase("InternalCodeunit")]
+ public async Task InternalHasDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(InternalHasDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.InternalObjectRequiresDocumentation);
+ }
+
+ [Test]
+ [TestCase("InternalCodeunit")]
+ public async Task InternalNoDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(InternalNoDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.InternalObjectRequiresDocumentation);
+ }
+ }
+}
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/ObjectRequiresDocumentation.ruleset.json b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/ObjectRequiresDocumentation.ruleset.json
new file mode 100644
index 00000000..ddf7f1c5
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/ObjectRequiresDocumentation.ruleset.json
@@ -0,0 +1,10 @@
+{
+ "name": "Enable DC0008",
+ "description": "Enables the default-disabled ObjectRequiresDocumentation.ruleset rule so it can be tested.",
+ "rules": [
+ {
+ "id": "DC0008",
+ "action": "Info"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/PublicHasDiagnostic/PublicCodeunit.al b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/PublicHasDiagnostic/PublicCodeunit.al
new file mode 100644
index 00000000..3e8c38bc
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/PublicHasDiagnostic/PublicCodeunit.al
@@ -0,0 +1,6 @@
+codeunit 50100 [|MyCodeunit|]
+{
+ procedure MyProcedure()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/PublicNoDiagnostic/PublicCodeunit.al b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/PublicNoDiagnostic/PublicCodeunit.al
new file mode 100644
index 00000000..f053326b
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ObjectRequiresDocumentation/PublicNoDiagnostic/PublicCodeunit.al
@@ -0,0 +1,9 @@
+///
+/// A great piece of code that solves all problems.
+///
+codeunit 50100 [|MyCodeunit|]
+{
+ procedure MyProcedure()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/BusinessEvent.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/BusinessEvent.al
new file mode 100644
index 00000000..d0c4fa9d
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/BusinessEvent.al
@@ -0,0 +1,7 @@
+codeunit 50100 MyCodeunit
+{
+ [BusinessEvent(false)]
+ local procedure [|OnBeforeTheWorldGoesLight|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/BusinessEventWithComment.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/BusinessEventWithComment.al
new file mode 100644
index 00000000..e9ae55bc
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/BusinessEventWithComment.al
@@ -0,0 +1,8 @@
+codeunit 50100 MyCodeunit
+{
+ // This is a comment
+ [BusinessEvent(false)]
+ local procedure [|OnBeforeTheWorldGoesLight|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/BusinessEventWithParameters.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/BusinessEventWithParameters.al
new file mode 100644
index 00000000..71bfe5c6
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/BusinessEventWithParameters.al
@@ -0,0 +1,7 @@
+codeunit 50100 MyCodeunit
+{
+ [BusinessEvent(false)]
+ local procedure [|OnBeforeTheWorldGoesLight|](i: Integer; d: Decimal; var returnText: Text)
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/IntegrationEvent.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/IntegrationEvent.al
new file mode 100644
index 00000000..1bd609af
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/IntegrationEvent.al
@@ -0,0 +1,7 @@
+codeunit 50100 MyCodeunit
+{
+ [IntegrationEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/IntegrationEventWithComment.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/IntegrationEventWithComment.al
new file mode 100644
index 00000000..5c88ff76
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/IntegrationEventWithComment.al
@@ -0,0 +1,8 @@
+codeunit 50100 MyCodeunit
+{
+ // This is a comment
+ [IntegrationEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/IntegrationEventWithParameters.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/IntegrationEventWithParameters.al
new file mode 100644
index 00000000..8e78d783
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventHasDiagnostic/IntegrationEventWithParameters.al
@@ -0,0 +1,7 @@
+codeunit 50100 MyCodeunit
+{
+ [IntegrationEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|](i: Integer; d: Decimal; var returnText: Text)
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/BusinessEvent.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/BusinessEvent.al
new file mode 100644
index 00000000..ca68cba5
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/BusinessEvent.al
@@ -0,0 +1,10 @@
+codeunit 50100 MyCodeunit
+{
+ ///
+ /// Triggered just before the world goes light.
+ ///
+ [BusinessEvent(false)]
+ local procedure [|OnBeforeTheWorldGoesLight|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/BusinessEventWithParameters.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/BusinessEventWithParameters.al
new file mode 100644
index 00000000..e1ff03a8
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/BusinessEventWithParameters.al
@@ -0,0 +1,13 @@
+codeunit 50100 MyCodeunit
+{
+ ///
+ /// Triggered just before the world goes light.
+ ///
+ /// An integer value.
+ /// A decimal value.
+ /// A text to return.
+ [BusinessEvent(false)]
+ local procedure [|OnBeforeTheWorldGoesLight|](i: Integer; d: Decimal; var returnText: Text)
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/IntegrationEvent.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/IntegrationEvent.al
new file mode 100644
index 00000000..a6c7caeb
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/IntegrationEvent.al
@@ -0,0 +1,10 @@
+codeunit 50100 MyCodeunit
+{
+ ///
+ /// Triggered just before the world goes light.
+ ///
+ [IntegrationEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/IntegrationEventWithParameters.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/IntegrationEventWithParameters.al
new file mode 100644
index 00000000..c572759d
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/IntegrationEventNoDiagnostic/IntegrationEventWithParameters.al
@@ -0,0 +1,13 @@
+codeunit 50100 MyCodeunit
+{
+ ///
+ /// Triggered just before the world goes light.
+ ///
+ /// An integer value.
+ /// A decimal value.
+ /// A text to return.
+ [IntegrationEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|](i: Integer; d: Decimal; var returnText: Text)
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventHasDiagnostic/InternalEvent.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventHasDiagnostic/InternalEvent.al
new file mode 100644
index 00000000..ba5eead3
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventHasDiagnostic/InternalEvent.al
@@ -0,0 +1,7 @@
+codeunit 50100 MyCodeunit
+{
+ [InternalEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventHasDiagnostic/InternalEventWithComment.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventHasDiagnostic/InternalEventWithComment.al
new file mode 100644
index 00000000..44d579ff
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventHasDiagnostic/InternalEventWithComment.al
@@ -0,0 +1,8 @@
+codeunit 50100 MyCodeunit
+{
+ // This is a comment
+ [InternalEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventHasDiagnostic/InternalEventWithParameters.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventHasDiagnostic/InternalEventWithParameters.al
new file mode 100644
index 00000000..621af1e0
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventHasDiagnostic/InternalEventWithParameters.al
@@ -0,0 +1,7 @@
+codeunit 50100 MyCodeunit
+{
+ [InternalEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|](i: Integer; d: Decimal; var returnText: Text)
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventNoDiagnostic/InternalEvent.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventNoDiagnostic/InternalEvent.al
new file mode 100644
index 00000000..de55ac36
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventNoDiagnostic/InternalEvent.al
@@ -0,0 +1,10 @@
+codeunit 50100 MyCodeunit
+{
+ ///
+ /// Triggered just before the world goes light.
+ ///
+ [InternalEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventNoDiagnostic/InternalEventWithParameters.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventNoDiagnostic/InternalEventWithParameters.al
new file mode 100644
index 00000000..fbf6215e
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalEventNoDiagnostic/InternalEventWithParameters.al
@@ -0,0 +1,13 @@
+codeunit 50100 MyCodeunit
+{
+ ///
+ /// Triggered just before the world goes light.
+ ///
+ /// An integer value.
+ /// A decimal value.
+ /// A text to return.
+ [InternalEvent(false, false)]
+ local procedure [|OnBeforeTheWorldGoesLight|](i: Integer; d: Decimal; var returnText: Text)
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/CodeunitAccessInternal.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/CodeunitAccessInternal.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/CodeunitAccessInternal.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/CodeunitAccessInternal.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/CodeunitAccessInternalProcedureWithAttribute.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/CodeunitAccessInternalProcedureWithAttribute.al
new file mode 100644
index 00000000..9f60c304
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/CodeunitAccessInternalProcedureWithAttribute.al
@@ -0,0 +1,9 @@
+codeunit 50100 MyCodeunit
+{
+ Access = Internal;
+
+ [NonDebuggable]
+ procedure [|MyProcedure|]()
+ begin
+ end;
+}
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/CodeunitAccessInternalProcedureWithComment.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/CodeunitAccessInternalProcedureWithComment.al
new file mode 100644
index 00000000..e31cf541
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/CodeunitAccessInternalProcedureWithComment.al
@@ -0,0 +1,9 @@
+codeunit 50100 MyCodeunit
+{
+ Access = Internal;
+
+ // This is a comment
+ procedure [|MyProcedure|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureInternal.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/InternalProcedure.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureInternal.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/InternalProcedure.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/InternalProcedureWithAttribute.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/InternalProcedureWithAttribute.al
new file mode 100644
index 00000000..874cf0f8
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/InternalProcedureWithAttribute.al
@@ -0,0 +1,7 @@
+codeunit 50100 MyCodeunit
+{
+ [NonDebuggable]
+ internal procedure [|MyProcedure|]()
+ begin
+ end;
+}
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/InternalProcedureWithComment.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/InternalProcedureWithComment.al
new file mode 100644
index 00000000..762d6585
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalHasDiagnostic/InternalProcedureWithComment.al
@@ -0,0 +1,7 @@
+codeunit 50100 MyCodeunit
+{
+ // This is a comment
+ internal procedure [|MyProcedure|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/CodeunitAccessInternalProcedureDocumentationComment.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/CodeunitAccessInternalProcedureDocumentationComment.al
new file mode 100644
index 00000000..e2967afe
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/CodeunitAccessInternalProcedureDocumentationComment.al
@@ -0,0 +1,12 @@
+codeunit 50100 MyCodeunit
+{
+ Access = Internal;
+
+ ///
+ /// This method...
+ ///
+ procedure [|MyProcedure|]()
+ begin
+
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/CodeunitAccessInternalProcedureDocumentationCommentWithAttribute.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/CodeunitAccessInternalProcedureDocumentationCommentWithAttribute.al
new file mode 100644
index 00000000..16e28a71
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/CodeunitAccessInternalProcedureDocumentationCommentWithAttribute.al
@@ -0,0 +1,13 @@
+codeunit 50100 MyCodeunit
+{
+ Access = Internal;
+
+ ///
+ /// Sets the call body content from a stream.
+ ///
+ /// The instream containing the call body.
+ [NonDebuggable]
+ procedure [|MyProcedure|](ContentStream: InStream)
+ begin
+ end;
+}
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/CodeunitAccessInternalProcedureDocumentationCommentWithMultipleAttributes.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/CodeunitAccessInternalProcedureDocumentationCommentWithMultipleAttributes.al
new file mode 100644
index 00000000..ea490a6a
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/CodeunitAccessInternalProcedureDocumentationCommentWithMultipleAttributes.al
@@ -0,0 +1,13 @@
+codeunit 50100 MyCodeunit
+{
+ Access = Internal;
+
+ ///
+ /// My procedure.
+ ///
+ [NonDebuggable]
+ [Scope('OnPrem')]
+ procedure [|MyProcedure|]()
+ begin
+ end;
+}
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/HasDiagnostic/Procedure.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/Procedure.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/HasDiagnostic/Procedure.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/Procedure.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureLocal.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/ProcedureLocal.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureLocal.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/ProcedureLocal.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/TestCodeunit.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/TestCodeunit.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/TestCodeunit.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/TestCodeunit.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/TestCodeunitHandlerMethod.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/TestCodeunitHandlerMethod.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/TestCodeunitHandlerMethod.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/InternalNoDiagnostic/TestCodeunitHandlerMethod.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/ProcedureRequiresDocumentation.cs b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/ProcedureRequiresDocumentation.cs
new file mode 100644
index 00000000..675f7759
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/ProcedureRequiresDocumentation.cs
@@ -0,0 +1,138 @@
+using RoslynTestKit;
+
+namespace ALCops.DocumentationCop.Test
+{
+ public class ProcedureRequiresDocumentation : NavCodeAnalysisBase
+ {
+ private AnalyzerTestFixture _fixture;
+ private string _testCasePath;
+
+ [SetUp]
+ public void Setup()
+ {
+ _testCasePath = Path.Combine(
+ Directory.GetParent(
+ Environment.CurrentDirectory)!.Parent!.Parent!.FullName,
+ Path.Combine("Rules", nameof(ProcedureRequiresDocumentation)));
+
+ _fixture = RoslynFixtureFactory.Create(
+ // Inject a ruleset to enable testing for rules, that are not enabled by default (isEnabledByDefault: false).
+ new AnalyzerTestFixtureConfig
+ {
+ RuleSetPath = Path.Combine(_testCasePath, $"{nameof(ProcedureRequiresDocumentation)}.ruleset.json")
+ });
+ }
+
+ [Test]
+ [TestCase("BusinessEvent")]
+ [TestCase("BusinessEventWithComment")]
+ [TestCase("BusinessEventWithParameters")]
+ [TestCase("IntegrationEvent")]
+ [TestCase("IntegrationEventWithComment")]
+ [TestCase("IntegrationEventWithParameters")]
+ public async Task IntegrationEventHasDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(IntegrationEventHasDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.EventRequiresDocumentation);
+ }
+
+ [Test]
+ [TestCase("BusinessEvent")]
+ [TestCase("BusinessEventWithParameters")]
+ [TestCase("IntegrationEvent")]
+ [TestCase("IntegrationEventWithParameters")]
+ public async Task IntegrationEventNoDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(IntegrationEventNoDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.EventRequiresDocumentation);
+ }
+
+ [Test]
+ [TestCase("InternalEvent")]
+ [TestCase("InternalEventWithComment")]
+ [TestCase("InternalEventWithParameters")]
+ public async Task InternalEventHasDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(InternalEventHasDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.InternalEventRequiresDocumentation);
+ }
+
+ [Test]
+ [TestCase("InternalEvent")]
+ [TestCase("InternalEventWithParameters")]
+ public async Task InternalEventNoDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(InternalEventNoDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.InternalEventRequiresDocumentation);
+ }
+
+ //-----------------------
+ [Test]
+ [TestCase("CodeunitAccessInternal")]
+ [TestCase("CodeunitAccessInternalProcedureWithAttribute")]
+ [TestCase("CodeunitAccessInternalProcedureWithComment")]
+ [TestCase("InternalProcedure")]
+ [TestCase("InternalProcedureWithAttribute")]
+ [TestCase("InternalProcedureWithComment")]
+ public async Task InternalHasDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(InternalHasDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.InternalProcedureRequiresDocumentation);
+ }
+
+ [Test]
+ [TestCase("CodeunitAccessInternalProcedureDocumentationComment")]
+ [TestCase("CodeunitAccessInternalProcedureDocumentationCommentWithAttribute")]
+ [TestCase("CodeunitAccessInternalProcedureDocumentationCommentWithMultipleAttributes")]
+ [TestCase("Procedure")]
+ [TestCase("ProcedureLocal")]
+ [TestCase("TestCodeunit")]
+ [TestCase("TestCodeunitHandlerMethod")]
+ public async Task InternalNoDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(InternalNoDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.InternalProcedureRequiresDocumentation);
+ }
+
+ [Test]
+ [TestCase("Procedure")]
+ [TestCase("ProcedureWithAttribute")]
+ [TestCase("ProcedureWithComment")]
+ public async Task PublicHasDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(PublicHasDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.PublicProcedureRequiresDocumentation);
+ }
+
+ [Test]
+ [TestCase("CodeunitAccessInternal")]
+ [TestCase("ProcedureDocumentationComment")]
+ [TestCase("ProcedureDocumentationCommentWithAttribute")]
+ [TestCase("ProcedureDocumentationCommentWithMultipleAttributes")]
+ [TestCase("ProcedureInternal")]
+ [TestCase("ProcedureLocal")]
+ [TestCase("TestCodeunit")]
+ [TestCase("TestCodeunitHandlerMethod")]
+ public async Task PublicNoDiagnostic(string testCase)
+ {
+ var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(PublicNoDiagnostic), $"{testCase}.al"))
+ .ConfigureAwait(false);
+
+ _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.PublicProcedureRequiresDocumentation);
+ }
+ }
+}
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/ProcedureRequiresDocumentation.ruleset.json b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/ProcedureRequiresDocumentation.ruleset.json
new file mode 100644
index 00000000..a6a57dfb
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/ProcedureRequiresDocumentation.ruleset.json
@@ -0,0 +1,14 @@
+{
+ "name": "Enable DC0006, DC0010",
+ "description": "Enables the default-disabled ProcedureRequiresDocumentation.ruleset rule so it can be tested.",
+ "rules": [
+ {
+ "id": "DC0006",
+ "action": "Info"
+ },
+ {
+ "id": "DC0010",
+ "action": "Info"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicHasDiagnostic/Procedure.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicHasDiagnostic/Procedure.al
new file mode 100644
index 00000000..ffd4a138
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicHasDiagnostic/Procedure.al
@@ -0,0 +1,6 @@
+codeunit 50100 MyCodeunit
+{
+ procedure [|MyProcedure|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/HasDiagnostic/ProcedureWithAttribute.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicHasDiagnostic/ProcedureWithAttribute.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/HasDiagnostic/ProcedureWithAttribute.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicHasDiagnostic/ProcedureWithAttribute.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/HasDiagnostic/ProcedureWithComment.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicHasDiagnostic/ProcedureWithComment.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/HasDiagnostic/ProcedureWithComment.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicHasDiagnostic/ProcedureWithComment.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/CodeunitAccessInternal.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/CodeunitAccessInternal.al
new file mode 100644
index 00000000..720b3f9b
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/CodeunitAccessInternal.al
@@ -0,0 +1,8 @@
+codeunit 50100 MyCodeunit
+{
+ Access = Internal;
+
+ procedure [|MyProcedure|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureDocumentationComment.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureDocumentationComment.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureDocumentationComment.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureDocumentationComment.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureDocumentationCommentWithAttribute.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureDocumentationCommentWithAttribute.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureDocumentationCommentWithAttribute.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureDocumentationCommentWithAttribute.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureDocumentationCommentWithMultipleAttributes.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureDocumentationCommentWithMultipleAttributes.al
similarity index 100%
rename from src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/NoDiagnostic/ProcedureDocumentationCommentWithMultipleAttributes.al
rename to src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureDocumentationCommentWithMultipleAttributes.al
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureInternal.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureInternal.al
new file mode 100644
index 00000000..0bfd9ef6
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureInternal.al
@@ -0,0 +1,6 @@
+codeunit 50100 MyCodeunit
+{
+ internal procedure [|MyProcedure|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureLocal.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureLocal.al
new file mode 100644
index 00000000..3bc4dd3e
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/ProcedureLocal.al
@@ -0,0 +1,6 @@
+codeunit 50100 MyCodeunit
+{
+ local procedure [|MyProcedure|]()
+ begin
+ end;
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/TestCodeunit.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/TestCodeunit.al
new file mode 100644
index 00000000..8a20c657
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/TestCodeunit.al
@@ -0,0 +1,9 @@
+codeunit 50100 MyTestCodeunit
+{
+ Subtype = Test;
+
+ [Test]
+ procedure [|MyTestProcedure|]()
+ begin
+ end;
+}
diff --git a/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/TestCodeunitHandlerMethod.al b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/TestCodeunitHandlerMethod.al
new file mode 100644
index 00000000..47c3f727
--- /dev/null
+++ b/src/ALCops.DocumentationCop.Test/Rules/ProcedureRequiresDocumentation/PublicNoDiagnostic/TestCodeunitHandlerMethod.al
@@ -0,0 +1,19 @@
+codeunit 50100 MyTestCodeunit
+{
+ Subtype = Test;
+
+ [Test]
+ procedure [|MyTestProcedure|]()
+ begin
+ end;
+
+ [MessageHandler]
+ procedure [|MyMessageHandler|](Message: Text[1024])
+ begin
+ end;
+
+ [ConfirmHandler]
+ procedure [|MyConfirmHandler|](Question: Text[1024]; var Reply: Boolean)
+ begin
+ end;
+}
diff --git a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/PublicProcedureRequiresDocumentation.cs b/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/PublicProcedureRequiresDocumentation.cs
deleted file mode 100644
index c75ae8d5..00000000
--- a/src/ALCops.DocumentationCop.Test/Rules/PublicProcedureRequiresDocumentation/PublicProcedureRequiresDocumentation.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using RoslynTestKit;
-
-namespace ALCops.DocumentationCop.Test
-{
- public class PublicProcedureRequiresDocumentation : NavCodeAnalysisBase
- {
- private AnalyzerTestFixture _fixture;
- private string _testCasePath;
-
- [SetUp]
- public void Setup()
- {
- _fixture = RoslynFixtureFactory.Create();
-
- _testCasePath = Path.Combine(
- Directory.GetParent(
- Environment.CurrentDirectory)!.Parent!.Parent!.FullName,
- Path.Combine("Rules", nameof(PublicProcedureRequiresDocumentation)));
- }
-
- [Test]
- [TestCase("Procedure")]
- [TestCase("ProcedureWithComment")]
- [TestCase("ProcedureWithAttribute")]
- public async Task HasDiagnostic(string testCase)
- {
- var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(HasDiagnostic), $"{testCase}.al"))
- .ConfigureAwait(false);
-
- _fixture.HasDiagnosticAtAllMarkers(code, DiagnosticIds.PublicProcedureRequiresDocumentation);
- }
-
- [Test]
- [TestCase("CodeunitAccessInternal")]
- [TestCase("ProcedureDocumentationComment")]
- [TestCase("ProcedureDocumentationCommentWithAttribute")]
- [TestCase("ProcedureDocumentationCommentWithMultipleAttributes")]
- [TestCase("ProcedureInternal")]
- [TestCase("ProcedureLocal")]
- [TestCase("TestCodeunit")]
- [TestCase("TestCodeunitHandlerMethod")]
- public async Task NoDiagnostic(string testCase)
- {
- var code = await File.ReadAllTextAsync(Path.Combine(_testCasePath, nameof(NoDiagnostic), $"{testCase}.al"))
- .ConfigureAwait(false);
-
- _fixture.NoDiagnosticAtAllMarkers(code, DiagnosticIds.PublicProcedureRequiresDocumentation);
- }
- }
-}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop/ALCops.DocumentationCopAnalyzers.resx b/src/ALCops.DocumentationCop/ALCops.DocumentationCopAnalyzers.resx
index 3d4a5d3a..4dda25b4 100644
--- a/src/ALCops.DocumentationCop/ALCops.DocumentationCopAnalyzers.resx
+++ b/src/ALCops.DocumentationCop/ALCops.DocumentationCopAnalyzers.resx
@@ -136,10 +136,10 @@
Empty statements (standalone ;) reduce readability and are commonly introduced by mistake. This rule flags empty statement expressions (excess semicolons) so they can be removed.
- Public procedures must have XML documentation
+ Public procedures must include XML documentation comments
- Public procedure '{0}' must have XML documentation (or be restricted to local or internal scope).
+ Public procedure '{0}' must include XML documentation comments (or be restricted to local or internal scope).
Public procedures are part of the exposed API and must be explicitly documented to justify their availability. XML documentation comments communicate intent, usage, and guarantees to consumers of the extension.
@@ -162,4 +162,49 @@
The XML documentation for a procedure must accurately reflect its signature.
+
+ Internal procedures must include XML documentation comments
+
+
+ Internal procedure '{0}' must include XML documentation comments (or be restricted to local scope).
+
+
+ Internal procedures can be part of the exposed API (internalsVisibleTo) and should be explicitly documented to justify their availability. XML documentation comments communicate intent, usage, and guarantees to consumers of the extension.
+
+
+ Public objects must include XML documentation comments
+
+
+ Public object '{0}' must include XML documentation comments.
+
+
+ Public objects are part of the exposed API and must be explicitly documented to justify their availability. XML documentation comments communicate intent, usage, and guarantees to consumers of the extension.
+
+
+ Internal objects must include XML documentation comments
+
+
+ Internal object '{0}' must include XML documentation comments.
+
+
+ Internal objects can be part of the exposed API (internalsVisibleTo) and should be explicitly documented to justify their availability. XML documentation comments communicate intent, usage, and guarantees to consumers of the extension.
+
+
+ An integration or business event must include XML documentation comments
+
+
+ Event '{0}' must include XML documentation comments.
+
+
+ Integration events and business events are part of the exposed API and must be explicitly documented to justify their availability. XML documentation comments communicate intent, usage, and guarantees to consumers of the extension.
+
+
+ Internal event must include XML documentation comments
+
+
+ Internal event '{0}' must include XML documentation comments.
+
+
+ Internal events can be part of the exposed API (internalsVisibleTo) and should be explicitly documented to justify their availability. XML documentation comments communicate intent, usage, and guarantees to consumers of the extension.
+
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop/Analyzers/ObjectRequiresDocumentation.cs b/src/ALCops.DocumentationCop/Analyzers/ObjectRequiresDocumentation.cs
new file mode 100644
index 00000000..90847bd3
--- /dev/null
+++ b/src/ALCops.DocumentationCop/Analyzers/ObjectRequiresDocumentation.cs
@@ -0,0 +1,70 @@
+using System.Collections.Immutable;
+using ALCops.Common.Extensions;
+using ALCops.Common.Reflection;
+using Microsoft.Dynamics.Nav.CodeAnalysis;
+using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
+
+namespace ALCops.DocumentationCop.Analyzers;
+
+[DiagnosticAnalyzer]
+public sealed class ObjectRequiresDocumentation : DiagnosticAnalyzer
+{
+ public override ImmutableArray SupportedDiagnostics { get; } =
+ ImmutableArray.Create(
+ DiagnosticDescriptors.PublicObjectRequiresDocumentation,
+ DiagnosticDescriptors.InternalObjectRequiresDocumentation);
+
+ public override void Initialize(AnalysisContext context)
+ => context.RegisterSymbolAction(
+ CheckObjectDocumentation,
+ EnumProvider.SymbolKind.Codeunit,
+ EnumProvider.SymbolKind.ControlAddIn,
+ EnumProvider.SymbolKind.Enum,
+ EnumProvider.SymbolKind.Interface,
+ EnumProvider.SymbolKind.Page,
+ EnumProvider.SymbolKind.PermissionSet,
+ EnumProvider.SymbolKind.Profile,
+ EnumProvider.SymbolKind.Query,
+ EnumProvider.SymbolKind.Report,
+ EnumProvider.SymbolKind.Table,
+ EnumProvider.SymbolKind.XmlPort);
+
+ private void CheckObjectDocumentation(SymbolAnalysisContext ctx)
+ {
+ if (ctx.IsObsolete())
+ {
+ return;
+ }
+
+ if (ctx.Symbol is not IApplicationObjectTypeSymbol appObjectTypeSymbol)
+ {
+ return;
+ }
+
+ if (appObjectTypeSymbol.IsTestCodeunit())
+ {
+ return;
+ }
+
+ var xmlComment = appObjectTypeSymbol.GetDocumentationCommentXml();
+
+ if (string.IsNullOrWhiteSpace(xmlComment))
+ {
+ if (appObjectTypeSymbol.DeclaredAccessibility == EnumProvider.Accessibility.Public)
+ {
+ ctx.ReportDiagnostic(Diagnostic.Create(
+ DiagnosticDescriptors.PublicObjectRequiresDocumentation,
+ appObjectTypeSymbol.GetLocation(),
+ appObjectTypeSymbol.Name));
+ }
+
+ else if (appObjectTypeSymbol.DeclaredAccessibility == EnumProvider.Accessibility.Internal)
+ {
+ ctx.ReportDiagnostic(Diagnostic.Create(
+ DiagnosticDescriptors.InternalObjectRequiresDocumentation,
+ appObjectTypeSymbol.GetLocation(),
+ appObjectTypeSymbol.Name));
+ }
+ }
+ }
+}
diff --git a/src/ALCops.DocumentationCop/Analyzers/ProcedureRequiresDocumentation.cs b/src/ALCops.DocumentationCop/Analyzers/ProcedureRequiresDocumentation.cs
new file mode 100644
index 00000000..6a5f7b66
--- /dev/null
+++ b/src/ALCops.DocumentationCop/Analyzers/ProcedureRequiresDocumentation.cs
@@ -0,0 +1,93 @@
+using System.Collections.Immutable;
+using ALCops.Common.Extensions;
+using ALCops.Common.Reflection;
+using Microsoft.Dynamics.Nav.CodeAnalysis;
+using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
+using Microsoft.Dynamics.Nav.CodeAnalysis.Syntax;
+
+namespace ALCops.DocumentationCop.Analyzers;
+
+[DiagnosticAnalyzer]
+public sealed class ProcedureRequiresDocumentation : DiagnosticAnalyzer
+{
+ public override ImmutableArray SupportedDiagnostics { get; } =
+ ImmutableArray.Create(
+ DiagnosticDescriptors.PublicProcedureRequiresDocumentation,
+ DiagnosticDescriptors.InternalProcedureRequiresDocumentation,
+ DiagnosticDescriptors.EventRequiresDocumentation,
+ DiagnosticDescriptors.InternalEventRequiresDocumentation);
+
+ public override void Initialize(AnalysisContext context) =>
+ context.RegisterSyntaxNodeAction(
+ AnalyzeProcedures,
+ EnumProvider.SyntaxKind.MethodDeclaration
+ );
+
+ private void AnalyzeProcedures(SyntaxNodeAnalysisContext ctx)
+ {
+ if (ctx.IsObsolete() || ctx.Node is not MethodDeclarationSyntax method)
+ return;
+
+ var containingObject = ctx.ContainingSymbol.GetContainingApplicationObjectTypeSymbol();
+
+ if (containingObject.IsTestCodeunit())
+ return;
+
+ if (HasXmlDocumentation(method))
+ return;
+
+ var accessibilityToken = method.ProcedureKeyword.GetPreviousToken();
+
+ if (ctx.ContainingSymbol is IMethodSymbol methodSymbol && (methodSymbol is not null))
+ {
+ if (methodSymbol.IsIntegrationOrBusinessEvent())
+ {
+ ctx.ReportDiagnostic(Diagnostic.Create(
+ DiagnosticDescriptors.EventRequiresDocumentation,
+ method.Name.GetLocation(),
+ method.Name.Identifier.ToString()));
+ }
+
+ else if (methodSymbol.IsInternalEvent())
+ {
+ ctx.ReportDiagnostic(Diagnostic.Create(
+ DiagnosticDescriptors.InternalEventRequiresDocumentation,
+ method.Name.GetLocation(),
+ method.Name.Identifier.ToString()));
+ }
+
+ else
+ {
+ if (accessibilityToken.Kind == EnumProvider.SyntaxKind.LocalKeyword)
+ {
+ return;
+ }
+
+ if ((accessibilityToken.Kind == EnumProvider.SyntaxKind.InternalKeyword) ||
+ (containingObject?.DeclaredAccessibility == EnumProvider.Accessibility.Internal))
+ {
+ ctx.ReportDiagnostic(Diagnostic.Create(
+ DiagnosticDescriptors.InternalProcedureRequiresDocumentation,
+ method.Name.GetLocation(),
+ method.Name.Identifier.ToString()));
+ }
+ else
+ {
+ ctx.ReportDiagnostic(Diagnostic.Create(
+ DiagnosticDescriptors.PublicProcedureRequiresDocumentation,
+ method.Name.GetLocation(),
+ method.Name.Identifier.ToString()));
+ }
+ }
+ }
+ }
+
+ private static bool HasXmlDocumentation(MethodDeclarationSyntax method)
+ {
+ var trivia = method.GetLeadingTrivia();
+
+ return trivia.Any(t =>
+ t.Kind == EnumProvider.SyntaxKind.SingleLineDocumentationCommentTrivia ||
+ t.Kind == EnumProvider.SyntaxKind.MultiLineDocumentationCommentTrivia);
+ }
+}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop/Analyzers/PublicProcedureRequiresDocumentation.cs b/src/ALCops.DocumentationCop/Analyzers/PublicProcedureRequiresDocumentation.cs
deleted file mode 100644
index 9c86bd24..00000000
--- a/src/ALCops.DocumentationCop/Analyzers/PublicProcedureRequiresDocumentation.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-using System.Collections.Immutable;
-using ALCops.Common.Extensions;
-using ALCops.Common.Reflection;
-using Microsoft.Dynamics.Nav.CodeAnalysis;
-using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
-using Microsoft.Dynamics.Nav.CodeAnalysis.Syntax;
-
-namespace ALCops.DocumentationCop.Analyzers;
-
-[DiagnosticAnalyzer]
-public sealed class PublicProcedureRequiresDocumentation : DiagnosticAnalyzer
-{
- public override ImmutableArray SupportedDiagnostics { get; } =
- ImmutableArray.Create(
- DiagnosticDescriptors.PublicProcedureRequiresDocumentation);
-
- public override void Initialize(AnalysisContext context) =>
- context.RegisterSyntaxNodeAction(
- AnalyzePublicProcedures,
- EnumProvider.SyntaxKind.MethodDeclaration
- );
-
- private void AnalyzePublicProcedures(SyntaxNodeAnalysisContext ctx)
- {
- if (ctx.IsObsolete() || ctx.Node is not MethodDeclarationSyntax method)
- return;
-
- var containingObject = ctx.ContainingSymbol.GetContainingObjectTypeSymbol();
-
- // Rule applies only when the containing object itself is public
- if (containingObject.DeclaredAccessibility != EnumProvider.Accessibility.Public)
- return;
-
- if (IsTestCodeunit(containingObject))
- return;
-
- var accessibilityToken = method.ProcedureKeyword.GetPreviousToken();
- if (accessibilityToken.Kind == EnumProvider.SyntaxKind.LocalKeyword ||
- accessibilityToken.Kind == EnumProvider.SyntaxKind.InternalKeyword)
- return;
-
- if (HasXmlDocumentation(method))
- return;
-
- ctx.ReportDiagnostic(Diagnostic.Create(
- DiagnosticDescriptors.PublicProcedureRequiresDocumentation,
- method.Name.GetLocation(),
- method.Name.Identifier.ToString()));
- }
-
- private static bool HasXmlDocumentation(MethodDeclarationSyntax method)
- {
- var trivia = method.GetLeadingTrivia();
-
- return trivia.Any(t =>
- t.Kind == EnumProvider.SyntaxKind.SingleLineDocumentationCommentTrivia ||
- t.Kind == EnumProvider.SyntaxKind.MultiLineDocumentationCommentTrivia);
- }
-
- private static bool IsTestCodeunit(IObjectTypeSymbol symbol)
- {
- var subtype = symbol.GetEnumPropertyValue(EnumProvider.PropertyKind.Subtype);
- return subtype is not null && subtype == EnumProvider.CodeunitSubtypeKind.Test;
- }
-}
\ No newline at end of file
diff --git a/src/ALCops.DocumentationCop/DiagnosticDescriptors.cs b/src/ALCops.DocumentationCop/DiagnosticDescriptors.cs
index cf23b60e..514071da 100644
--- a/src/ALCops.DocumentationCop/DiagnosticDescriptors.cs
+++ b/src/ALCops.DocumentationCop/DiagnosticDescriptors.cs
@@ -55,6 +55,56 @@ public static class DiagnosticDescriptors
description: DocumentationCopAnalyzers.XmlDocumentationProcedureConsistencyDescription,
helpLinkUri: GetHelpUri(DiagnosticIds.XmlDocumentationProcedureConsistency));
+ public static readonly DiagnosticDescriptor InternalProcedureRequiresDocumentation = new(
+ id: DiagnosticIds.InternalProcedureRequiresDocumentation,
+ title: DocumentationCopAnalyzers.InternalProcedureRequiresDocumentationTitle,
+ messageFormat: DocumentationCopAnalyzers.InternalProcedureRequiresDocumentationMessageFormat,
+ category: Category.Design,
+ defaultSeverity: DiagnosticSeverity.Info,
+ isEnabledByDefault: false,
+ description: DocumentationCopAnalyzers.InternalProcedureRequiresDocumentationDescription,
+ helpLinkUri: GetHelpUri(DiagnosticIds.InternalProcedureRequiresDocumentation));
+
+ public static readonly DiagnosticDescriptor PublicObjectRequiresDocumentation = new(
+ id: DiagnosticIds.PublicObjectRequiresDocumentation,
+ title: DocumentationCopAnalyzers.PublicObjectRequiresDocumentationTitle,
+ messageFormat: DocumentationCopAnalyzers.PublicObjectRequiresDocumentationMessageFormat,
+ category: Category.Design,
+ defaultSeverity: DiagnosticSeverity.Info,
+ isEnabledByDefault: true,
+ description: DocumentationCopAnalyzers.PublicObjectRequiresDocumentationDescription,
+ helpLinkUri: GetHelpUri(DiagnosticIds.PublicObjectRequiresDocumentation));
+
+ public static readonly DiagnosticDescriptor InternalObjectRequiresDocumentation = new(
+ id: DiagnosticIds.InternalObjectRequiresDocumentation,
+ title: DocumentationCopAnalyzers.InternalObjectRequiresDocumentationTitle,
+ messageFormat: DocumentationCopAnalyzers.InternalObjectRequiresDocumentationMessageFormat,
+ category: Category.Design,
+ defaultSeverity: DiagnosticSeverity.Info,
+ isEnabledByDefault: false,
+ description: DocumentationCopAnalyzers.InternalObjectRequiresDocumentationDescription,
+ helpLinkUri: GetHelpUri(DiagnosticIds.InternalObjectRequiresDocumentation));
+
+ public static readonly DiagnosticDescriptor EventRequiresDocumentation = new(
+ id: DiagnosticIds.EventRequiresDocumentation,
+ title: DocumentationCopAnalyzers.EventRequiresDocumentationTitle,
+ messageFormat: DocumentationCopAnalyzers.EventRequiresDocumentationMessageFormat,
+ category: Category.Design,
+ defaultSeverity: DiagnosticSeverity.Info,
+ isEnabledByDefault: true,
+ description: DocumentationCopAnalyzers.EventRequiresDocumentationDescription,
+ helpLinkUri: GetHelpUri(DiagnosticIds.EventRequiresDocumentation));
+
+ public static readonly DiagnosticDescriptor InternalEventRequiresDocumentation = new(
+ id: DiagnosticIds.InternalEventRequiresDocumentation,
+ title: DocumentationCopAnalyzers.InternalEventRequiresDocumentationTitle,
+ messageFormat: DocumentationCopAnalyzers.InternalEventRequiresDocumentationMessageFormat,
+ category: Category.Design,
+ defaultSeverity: DiagnosticSeverity.Info,
+ isEnabledByDefault: false,
+ description: DocumentationCopAnalyzers.InternalEventRequiresDocumentationDescription,
+ helpLinkUri: GetHelpUri(DiagnosticIds.InternalEventRequiresDocumentation));
+
public static string GetHelpUri(string identifier)
{
return string.Format(CultureInfo.InvariantCulture, "https://alcops.dev/docs/analyzers/documentationcop/{0}/", identifier.ToLower());
diff --git a/src/ALCops.DocumentationCop/DiagnosticIds.cs b/src/ALCops.DocumentationCop/DiagnosticIds.cs
index 4b25f7c0..1493e9dc 100644
--- a/src/ALCops.DocumentationCop/DiagnosticIds.cs
+++ b/src/ALCops.DocumentationCop/DiagnosticIds.cs
@@ -7,4 +7,9 @@ public static class DiagnosticIds
public static readonly string EmptyStatementRequiresComment = "DC0003";
public static readonly string PublicProcedureRequiresDocumentation = "DC0004";
public static readonly string XmlDocumentationProcedureConsistency = "DC0005";
+ public static readonly string InternalProcedureRequiresDocumentation = "DC0006";
+ public static readonly string PublicObjectRequiresDocumentation = "DC0007";
+ public static readonly string InternalObjectRequiresDocumentation = "DC0008";
+ public static readonly string EventRequiresDocumentation = "DC0009";
+ public static readonly string InternalEventRequiresDocumentation = "DC0010";
}
\ No newline at end of file
diff --git a/src/ALCops.LinterCop/Analyzers/ApplicationAreaRedundancy.cs b/src/ALCops.LinterCop/Analyzers/ApplicationAreaRedundancy.cs
index 60f64dcb..fc6926e4 100644
--- a/src/ALCops.LinterCop/Analyzers/ApplicationAreaRedundancy.cs
+++ b/src/ALCops.LinterCop/Analyzers/ApplicationAreaRedundancy.cs
@@ -26,7 +26,7 @@ private void CheckDataClassificationRedundancy(SymbolAnalysisContext ctx)
return;
IApplicationObjectTypeSymbol? applicationObject = control.GetContainingApplicationObjectTypeSymbol();
- if (applicationObject is not IPageTypeSymbol page || applicationObject.IsObsolete())
+ if (applicationObject is not IPageTypeSymbol page)
return;
IPropertySymbol? controlApplicationArea = control.GetProperty(EnumProvider.PropertyKind.ApplicationArea);