Skip to content

Commit

Permalink
Merge pull request #356 from StefanMaron/development
Browse files Browse the repository at this point in the history
New rule LC0033 runtime falling behind
  • Loading branch information
Arthurvdv authored Nov 21, 2023
2 parents baafaff + f434706 commit 866670f
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 0 deletions.
85 changes: 85 additions & 0 deletions Design/Rule0033AppManifestRuntimeBehind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
using Microsoft.Dynamics.Nav.Analyzers.Common.AppSourceCopConfiguration;
using Microsoft.Dynamics.Nav.CodeAnalysis;
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
using Microsoft.Dynamics.Nav.CodeAnalysis.Packaging;
using System.Collections.Immutable;

namespace BusinessCentral.LinterCop.Design
{
[DiagnosticAnalyzer]
class Rule0033AppManifestRuntimeBehind : DiagnosticAnalyzer
{
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create<DiagnosticDescriptor>(DiagnosticDescriptors.Rule0033AppManifestRuntimeBehind);

public override void Initialize(AnalysisContext context) => context.RegisterCompilationAction(new Action<CompilationAnalysisContext>(this.CheckAppManifestRuntime));

private void CheckAppManifestRuntime(CompilationAnalysisContext ctx)
{
NavAppManifest manifest = AppSourceCopConfigurationProvider.GetManifest(ctx.Compilation);
if (manifest == null) return;
if (manifest.Runtime == (Version)null) return;

GetTargetProperty(manifest, out string propertyName, out Version propertyVersion);

Version supportedRuntime = FindValueOfFirstValueLessThan(GetSupportedRuntimeVersions(), propertyVersion);
if (manifest.Runtime < supportedRuntime)
ctx.ReportDiagnostic(Diagnostic.Create(DiagnosticDescriptors.Rule0033AppManifestRuntimeBehind, manifest.GetDiagnosticLocation("runtime"), new object[] { propertyName, propertyVersion, manifest.Runtime, supportedRuntime }));
}

private static void GetTargetProperty(NavAppManifest manifest, out string propertyName, out Version propertyVersion)
{
if (manifest.Application >= manifest.Platform)
{
propertyName = "application";
propertyVersion = manifest.Application;
}
else
{
propertyName = "platform";
propertyVersion = manifest.Platform;
}
}

private static SortedList<Version, Version> GetSupportedRuntimeVersions()
{
// Populate a SortedList with platform version and runtime version combined
SortedList<Version, Version> AvailableRuntimeVersion = new SortedList<Version, Version>();

// https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/developer/devenv-choosing-runtime#currently-available-runtime-versions
// When in the future the offset between the platform and runtime versions isn't exactly is eleven, we're in trouble
// By populating a list here, in stead of just adding up eleven somewhere else, we probably can resolve this here
int offset = 11;

foreach (var v in RuntimeVersion.SupportedVersions)
{
AvailableRuntimeVersion.Add(new Version(v.Major + offset, v.Minor), new Version(v.Major, v.Minor));
}
return AvailableRuntimeVersion;
}

private static Version FindValueOfFirstValueLessThan(SortedList<Version, Version> sortedList, Version version)
{
int index = FindIndexOfFirstValueLessThan(sortedList.Keys.ToList(), version);
return sortedList.ElementAt(index).Value;
}

private static int FindIndexOfFirstValueLessThan<T>(List<T> sortedList, T value, IComparer<T> comparer = null)
{
var index = sortedList.BinarySearch(value, comparer);

// The value was found in the list. Just return its index.
if (index >= 0)
return index;

// The value was not found and "~index" is the index of the next value greater than the search value.
index = ~index;

// There are values in the list less than the search value. Return the index of the closest one.
if (index > 0)
return index - 1;

// All values in the list are greater than the search value.
return -1;
}
}
}
1 change: 1 addition & 0 deletions LinterCopAnalyzers.Generated.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ public static class DiagnosticDescriptors
public static readonly DiagnosticDescriptor Rule0030AccessInternalForInstallAndUpgradeCodeunits = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0030", (LocalizableString)new LocalizableResourceString("Rule0030AccessInternalForInstallAndUpgradeCodeunitsTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0030AccessInternalForInstallAndUpgradeCodeunitsFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0030AccessInternalForInstallAndUpgradeCodeunitsDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0030");
public static readonly DiagnosticDescriptor Rule0031RecordInstanceIsolationLevel = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0031", (LocalizableString)new LocalizableResourceString("Rule0031RecordInstanceIsolationLevelTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0031RecordInstanceIsolationLevelFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0031RecordInstanceIsolationLevelDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0031");
public static readonly DiagnosticDescriptor Rule0032ClearCodeunitSingleInstance = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0032", (LocalizableString)new LocalizableResourceString("Rule0032ClearCodeunitSingleInstanceTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0032ClearCodeunitSingleInstanceFormat", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Warning, true, (LocalizableString)new LocalizableResourceString("Rule0032ClearCodeunitSingleInstanceDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0032");
public static readonly DiagnosticDescriptor Rule0033AppManifestRuntimeBehind = new DiagnosticDescriptor(LinterCopAnalyzers.AnalyzerPrefix + "0033", (LocalizableString)new LocalizableResourceString("Rule0033AppManifestRuntimeBehindTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), (LocalizableString)new LocalizableResourceString("Rule0033AppManifestRuntimeBehindTitle", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "Design", DiagnosticSeverity.Info, true, (LocalizableString)new LocalizableResourceString("Rule0033AppManifestRuntimeBehindTitleDescription", LinterCopAnalyzers.ResourceManager, typeof(LinterCopAnalyzers)), "https://github.com/StefanMaron/BusinessCentral.LinterCop/wiki/LC0033");
}
}
9 changes: 9 additions & 0 deletions LinterCopAnalyzers.resx
Original file line number Diff line number Diff line change
Expand Up @@ -393,4 +393,13 @@
<data name="Rule0032ClearCodeunitSingleInstanceDescription" xml:space="preserve">
<value>Clear(All) does not affect or change values for global variables in '{0}: Codeunit {1}'.</value>
</data>
<data name="Rule0033AppManifestRuntimeBehindTitle" xml:space="preserve">
<value>The specified runtime version in app.json is falling behind. The project targets {0} version {1}, but the current runtime is {2}. Update the runtime to {3} for compatibility with the latest runtime features.</value>
</data>
<data name="Rule0033AppManifestRuntimeBehindFormat" xml:space="preserve">
<value>The specified runtime version in app.json is falling behind. The project targets {0} version {1}, but the current runtime is {2}. Update the runtime to {3} for compatibility with the latest runtime features.</value>
</data>
<data name="Rule0033AppManifestRuntimeBehindDescription" xml:space="preserve">
<value>The specified runtime version in app.json is falling behind. The project targets {0} version {1}, but the current runtime is {2}. Update the runtime to {3} for compatibility with the latest runtime features.</value>
</data>
</root>

0 comments on commit 866670f

Please sign in to comment.