Skip to content

Commit

Permalink
Merge pull request #366 from StefanMaron/development
Browse files Browse the repository at this point in the history
Extend rule0026 with guidelines for tooltip text
  • Loading branch information
Arthurvdv authored Nov 26, 2023
2 parents f804a39 + ea1018c commit 7252c60
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 35 deletions.
18 changes: 14 additions & 4 deletions Design/Rule0026ToolTipPunctuation.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using System.Collections.Immutable;
using Microsoft.Dynamics.Nav.CodeAnalysis;
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
using Microsoft.Dynamics.Nav.CodeAnalysis.Symbols;
using Microsoft.Dynamics.Nav.CodeAnalysis.Syntax;

namespace BusinessCentral.LinterCop.Design
{
[DiagnosticAnalyzer]
public class Rule0026ToolTipPunctuation : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0026ToolTipPunctuation);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0026ToolTipMustEndWithDot, DiagnosticDescriptors.Rule0026ToolTipMaximumLength, DiagnosticDescriptors.Rule0026ToolTipDoNotUseLineBreaks, DiagnosticDescriptors.Rule0026ToolTipShouldStartWithSpecifies);

public override void Initialize(AnalysisContext context) => context.RegisterSyntaxNodeAction(new Action<SyntaxNodeAnalysisContext>(this.AnalyzeToolTipPunctuation), SyntaxKind.PageField, SyntaxKind.PageAction);

Expand All @@ -18,12 +19,21 @@ private void AnalyzeToolTipPunctuation(SyntaxNodeAnalysisContext ctx)
if (ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoletePending || ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoleteRemoved) return;

PropertyValueSyntax tooltipProperty = ctx.Node.GetPropertyValue(PropertyKind.ToolTip);
if (tooltipProperty == null)
return;
if (tooltipProperty == null) return;

StringLiteralValueSyntax tooltipLabel = ((LabelPropertyValueSyntax)tooltipProperty).Value.LabelText;
if (!tooltipLabel.Value.ToString().EndsWith(".'"))
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0026ToolTipPunctuation, tooltipProperty.GetLocation()));
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0026ToolTipMustEndWithDot, tooltipProperty.GetLocation()));

if (tooltipLabel.Value.ToString().Count() > 200)
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0026ToolTipMaximumLength, tooltipProperty.GetLocation()));

if (tooltipLabel.Value.ToString().Contains("\\"))
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0026ToolTipDoNotUseLineBreaks, tooltipProperty.GetLocation()));

if (((IControlSymbol)ctx.ContainingSymbol).ControlKind == ControlKind.Field)
if (!tooltipLabel.Value.ToString().StartsWith("Specifies"))
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0026ToolTipShouldStartWithSpecifies, tooltipProperty.GetLocation()));
}
}
}
19 changes: 9 additions & 10 deletions Design/Rule0028CodeNavigabilityOnEventSubscribers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,20 @@ public class Rule0028CodeNavigabilityOnEventSubscribers : DiagnosticAnalyzer

private void CodeNavigabilityOnEventSubscribers(CodeBlockAnalysisContext context)
{
// Support for using Identifiers instead of Literals in event subscribers is supported from runtime versions: '11.0' or greater.
var manifest = AppSourceCopConfigurationProvider.GetManifest(context.SemanticModel.Compilation);
if (manifest.Runtime < RuntimeVersion.Spring2023) return;

if (context.OwningSymbol.GetContainingObjectTypeSymbol().IsObsoletePending || context.OwningSymbol.GetContainingObjectTypeSymbol().IsObsoleteRemoved) return;
if (context.OwningSymbol.IsObsoletePending || context.OwningSymbol.IsObsoleteRemoved) return;

if (!context.CodeBlock.IsKind(SyntaxKind.MethodDeclaration)) return;
var SyntaxList = ((MethodDeclarationSyntax)context.CodeBlock).Attributes.Where(value => value.GetIdentifierOrLiteralValue().ToUpper() == "EVENTSUBSCRIBER");

foreach (var Syntax in SyntaxList)
{
if (Syntax.ArgumentList.Arguments[2].IsKind(SyntaxKind.LiteralAttributeArgument))
context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0028CodeNavigabilityOnEventSubscribers, context.OwningSymbol.GetLocation()));
}
IEnumerable<MemberAttributeSyntax> MemberAttributeSyntaxList = ((MethodDeclarationSyntax)context.CodeBlock).Attributes.Where(value => SemanticFacts.IsSameName(value.GetIdentifierOrLiteralValue(), "EventSubscriber"));
if (!MemberAttributeSyntaxList.Select(value => value.ArgumentList.Arguments[2]).Where(syntax => syntax.IsKind(SyntaxKind.LiteralAttributeArgument)).Any() &&
!MemberAttributeSyntaxList.Select(value => value.ArgumentList.Arguments[3]).Where(syntax => syntax.IsKind(SyntaxKind.LiteralAttributeArgument)).Any()) return;

// Support for using Identifiers instead of Literals in event subscribers is supported from runtime versions: '11.0' or greater.
var manifest = AppSourceCopConfigurationProvider.GetManifest(context.SemanticModel.Compilation);
if (manifest.Runtime < RuntimeVersion.Spring2023) return;

context.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0028CodeNavigabilityOnEventSubscribers, context.OwningSymbol.GetLocation()));
}
}
}
13 changes: 7 additions & 6 deletions Design/Rule0031RecordInstanceIsolationLevel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ public class Rule0031RecordInstanceIsolationLevel : DiagnosticAnalyzer

private void CheckLockTable(OperationAnalysisContext ctx)
{
// ReadIsolation is supported from runtime versions 11.0 or greater.
var manifest = AppSourceCopConfigurationProvider.GetManifest(ctx.Compilation);
if (manifest.Runtime < RuntimeVersion.Spring2023) return;

if (ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoletePending || ctx.ContainingSymbol.GetContainingObjectTypeSymbol().IsObsoleteRemoved) return;
if (ctx.ContainingSymbol.IsObsoletePending || ctx.ContainingSymbol.IsObsoleteRemoved) return;

IInvocationExpression operation = (IInvocationExpression)ctx.Operation;
if (operation.TargetMethod.MethodKind != MethodKind.BuiltInMethod) return;

if (SemanticFacts.IsSameName(operation.TargetMethod.Name, "LockTable"))
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0031RecordInstanceIsolationLevel, ctx.Operation.Syntax.GetLocation()));
if (!SemanticFacts.IsSameName(operation.TargetMethod.Name, "LockTable")) return;

// ReadIsolation is supported from runtime versions 11.0 or greater.
var manifest = AppSourceCopConfigurationProvider.GetManifest(ctx.Compilation);
if (manifest.Runtime < RuntimeVersion.Spring2023) return;

ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0031RecordInstanceIsolationLevel, ctx.Operation.Syntax.GetLocation()));
}
}
}
13 changes: 7 additions & 6 deletions Design/Rule0034ExtensiblePropertyShouldAlwaysBeSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ public override void Initialize(AnalysisContext context)

private void CheckForMissingExtensibleProperty(SymbolAnalysisContext ctx)
{
// The Extensible property (and DeclaredAccessibility) is supported from runtime versions 4.0 or greater.
var manifest = AppSourceCopConfigurationProvider.GetManifest(ctx.Compilation);
if (manifest.Runtime < RuntimeVersion.Fall2019) return;

if (ctx.Symbol.IsObsoletePending || ctx.Symbol.IsObsoleteRemoved) return;

if (ctx.Symbol.GetTypeSymbol().Kind == SymbolKind.Table && ctx.Symbol.DeclaredAccessibility != Accessibility.Public) return;
if (ctx.Symbol.GetTypeSymbol().Kind == SymbolKind.Page && ((IPageTypeSymbol)ctx.Symbol.GetTypeSymbol()).PageType == PageTypeKind.API) return;

if (ctx.Symbol.GetProperty(PropertyKind.Extensible) is null)
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0034ExtensiblePropertyShouldAlwaysBeSet, ctx.Symbol.GetLocation(), new object[] { Accessibility.Public.ToString().ToLower() }));
if (ctx.Symbol.GetProperty(PropertyKind.Extensible) != null) return;

// The Extensible property (and DeclaredAccessibility) is supported from runtime versions 4.0 or greater.
var manifest = AppSourceCopConfigurationProvider.GetManifest(ctx.Compilation);
if (manifest.Runtime < RuntimeVersion.Fall2019) return;

ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0034ExtensiblePropertyShouldAlwaysBeSet, ctx.Symbol.GetLocation(), new object[] { Accessibility.Public.ToString().ToLower() }));
}
}
}
6 changes: 3 additions & 3 deletions Design/Rule0035ExplicitSetAllowInCustomizations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ public override void Initialize(AnalysisContext context)

private void AnalyzeAllowInCustomization(SymbolAnalysisContext ctx)
{
if (ctx.Symbol.IsObsoletePending || ctx.Symbol.IsObsoleteRemoved) return;
if (ctx.Symbol.GetContainingObjectTypeSymbol().IsObsoletePending || ctx.Symbol.GetContainingObjectTypeSymbol().IsObsoleteRemoved) return;

// The AllowInCustomizations property is supported from runtime versions 12.0 or greater.
var manifest = AppSourceCopConfigurationProvider.GetManifest(ctx.Compilation);
if (manifest.Runtime < RuntimeVersion.Fall2023) return;

if (ctx.Symbol.IsObsoletePending || ctx.Symbol.IsObsoleteRemoved) return;
if (ctx.Symbol.GetContainingObjectTypeSymbol().IsObsoletePending || ctx.Symbol.GetContainingObjectTypeSymbol().IsObsoleteRemoved) return;

ICollection<IFieldSymbol> tableFields = GetTableFields(ctx.Symbol).Where(x => x.Id > 0 && x.Id < 2000000000)
.Where(x => x.GetProperty(PropertyKind.AllowInCustomizations) is null)
.ToList();
Expand Down
2 changes: 1 addition & 1 deletion LinterCop.ruleset.json
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@
{
"id": "LC0026",
"action": "Info",
"justification": "ToolTip must end with a dot."
"justification": "Guidelines for ToolTip text."
},
{
"id": "LC0027",
Expand Down
5 changes: 4 additions & 1 deletion LinterCopAnalyzers.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ public static class DiagnosticDescriptors
public static readonly DiagnosticDescriptor Rule0023AlwaysSpecifyFieldgroups = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0023", (LocalizableString)new LocalizableResourceString("Rule0023AlwaysSpecifyFieldgroups", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0023AlwaysSpecifyFieldgroups", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0023AlwaysSpecifyFieldgroups", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0023");
public static readonly DiagnosticDescriptor Rule0024SemicolonAfterProcedureDeclaration = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0024", (LocalizableString)new LocalizableResourceString("Rule0024SemicolonAfterProcedureDeclarationTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0024SemicolonAfterProcedureDeclarationFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0024SemicolonAfterProcedureDeclarationDescription", 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 Rule0026ToolTipPunctuation = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0026", (LocalizableString)new LocalizableResourceString("Rule0026ToolTipPunctuationTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0026ToolTipPunctuationFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0026ToolTipPunctuationDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0026");
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 Rule0026ToolTipMaximumLength = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0026", (LocalizableString)new LocalizableResourceString("Rule0026ToolTipMaximumLengthTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0026ToolTipMaximumLengthFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0026ToolTipMaximumLengthDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0026");
public static readonly DiagnosticDescriptor Rule0026ToolTipDoNotUseLineBreaks = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0026", (LocalizableString)new LocalizableResourceString("Rule0026ToolTipDoNotUseLineBreaksTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0026ToolTipDoNotUseLineBreaksFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0026ToolTipDoNotUseLineBreaksDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0026");
public static readonly DiagnosticDescriptor Rule0026ToolTipShouldStartWithSpecifies = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0026", (LocalizableString)new LocalizableResourceString("Rule0026ToolTipShouldStartWithSpecifiesTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0026ToolTipShouldStartWithSpecifiesFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0026ToolTipShouldStartWithSpecifiesDescription", 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 Rule0028CodeNavigabilityOnEventSubscribers = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0028", (LocalizableString)new LocalizableResourceString("Rule0028CodeNavigabilityOnEventSubscribersTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0028CodeNavigabilityOnEventSubscribersFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0028CodeNavigabilityOnEventSubscribersDescription", 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");
Expand Down
Loading

0 comments on commit 7252c60

Please sign in to comment.