From 3aa79afe334a294aa5e4ebca3841d0968c8d07e6 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Mon, 18 Jul 2022 17:25:06 -0700 Subject: [PATCH 1/6] ObsoletedIn attribute support plus unsupported with message --- .../Core/AnalyzerReleases.Unshipped.md | 1 + .../PlatformCompatibilityAnalyzer.Data.cs | 7 +- .../PlatformCompatibilityAnalyzer.cs | 308 ++++++++++++++---- .../MicrosoftNetCoreAnalyzersResources.resx | 8 +- .../MicrosoftNetCoreAnalyzersResources.cs.xlf | 16 +- .../MicrosoftNetCoreAnalyzersResources.de.xlf | 16 +- .../MicrosoftNetCoreAnalyzersResources.es.xlf | 16 +- .../MicrosoftNetCoreAnalyzersResources.fr.xlf | 16 +- .../MicrosoftNetCoreAnalyzersResources.it.xlf | 16 +- .../MicrosoftNetCoreAnalyzersResources.ja.xlf | 16 +- .../MicrosoftNetCoreAnalyzersResources.ko.xlf | 16 +- .../MicrosoftNetCoreAnalyzersResources.pl.xlf | 16 +- ...crosoftNetCoreAnalyzersResources.pt-BR.xlf | 16 +- .../MicrosoftNetCoreAnalyzersResources.ru.xlf | 16 +- .../MicrosoftNetCoreAnalyzersResources.tr.xlf | 16 +- ...osoftNetCoreAnalyzersResources.zh-Hans.xlf | 16 +- ...osoftNetCoreAnalyzersResources.zh-Hant.xlf | 16 +- ...lityAnalyzer.ObsoletedInOSPlatformTests.cs | 246 ++++++++++++++ .../DiagnosticCategoryAndIdRanges.txt | 2 +- 19 files changed, 680 insertions(+), 100 deletions(-) create mode 100644 src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs diff --git a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md index d929849d5f..58e13eed62 100644 --- a/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md +++ b/src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md @@ -7,6 +7,7 @@ Rule ID | Category | Severity | Notes CA1311 | Globalization | Hidden | SpecifyCultureForToLowerAndToUpper, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1311) CA1420 | Interoperability | Warning | FeatureUnsupportedWhenRuntimeMarshallingDisabled, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1420) CA1421 | Interoperability | Info | MethodUsesRuntimeMarshallingEvenWhenMarshallingDisabled, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1421) +CA1422 | Interoperability | Warning | PlatformCompatibilityAnalyzer, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1422) CA1849 | Performance | Disabled | UseAsyncMethodInAsyncContext, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1849) CA1850 | Performance | Info | PreferHashDataOverComputeHashAnalyzer, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1850) CA1851 | Performance | Disabled | AvoidMultipleEnumerations, [Documentation](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1851) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.Data.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.Data.cs index 4059c6ad86..634f3e0de2 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.Data.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.Data.cs @@ -18,6 +18,7 @@ public sealed partial class PlatformCompatibilityAnalyzer /// So we only keep at most 2 versions of [UnsupportedOSPlatform] first one will be the lowest version found, second one will be second lowest if there is any /// /// Properties: + /// - ObsoletedIn - keeps lowest version of [ObsoletedInOSPlatform] attribute found /// - SupportedFirst - keeps lowest version of [SupportedOSPlatform] attribute found /// - SupportedSecond - keeps the highest version of [SupportedOSPlatform] attribute if there is any /// - UnsupportedFirst - keeps the lowest version of [UnsupportedOSPlatform] attribute found @@ -25,12 +26,16 @@ public sealed partial class PlatformCompatibilityAnalyzer /// private class Versions { + public Version? ObsoletedIn { get; set; } + public string? ObsoletedMessage { get; set; } + public string? ObsoletedUrl { get; set; } public Version? SupportedFirst { get; set; } public Version? SupportedSecond { get; set; } public Version? UnsupportedFirst { get; set; } + public string? UnsupportedMessage { get; set; } public Version? UnsupportedSecond { get; set; } public bool IsSet() => SupportedFirst != null || UnsupportedFirst != null || - SupportedSecond != null || UnsupportedSecond != null; + SupportedSecond != null || UnsupportedSecond != null || ObsoletedIn != null; } private sealed class PlatformAttributes diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs index fa324a6d1e..7de95c05bb 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs @@ -33,14 +33,16 @@ namespace Microsoft.NetCore.Analyzers.InteropServices [DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)] public sealed partial class PlatformCompatibilityAnalyzer : DiagnosticAnalyzer { - internal const string RuleId = "CA1416"; - private static readonly ImmutableArray s_osPlatformAttributes = ImmutableArray.Create(SupportedOSPlatformAttribute, UnsupportedOSPlatformAttribute); + internal const string SupportRuleId = "CA1416"; + internal const string ObsoletedRuleId = "CA1422"; + private static readonly ImmutableArray s_osPlatformAttributes = ImmutableArray.Create(SupportedOSPlatformAttribute, UnsupportedOSPlatformAttribute, ObsoletedInOSPlatformAttribute); private static readonly LocalizableString s_localizableTitle = CreateLocalizableResourceString(nameof(PlatformCompatibilityTitle)); private static readonly LocalizableString s_localizableDescription = CreateLocalizableResourceString(nameof(PlatformCompatibilityDescription)); // We are adding the new attributes into older versions of .Net 5.0, so there could be multiple referenced assemblies each with their own // version of internal attribute type which will cause ambiguity, to avoid that we are comparing the attributes by their name + private const string ObsoletedInOSPlatformAttribute = nameof(ObsoletedInOSPlatformAttribute); private const string SupportedOSPlatformAttribute = nameof(SupportedOSPlatformAttribute); private const string UnsupportedOSPlatformAttribute = nameof(UnsupportedOSPlatformAttribute); private const string UnsupportedOSPlatformGuardAttribute = nameof(UnsupportedOSPlatformGuardAttribute); @@ -57,7 +59,7 @@ public sealed partial class PlatformCompatibilityAnalyzer : DiagnosticAnalyzer private static readonly Version EmptyVersion = new(0, 0); internal static readonly DiagnosticDescriptor OnlySupportedCsReachable = DiagnosticDescriptorHelper.Create( - RuleId, + SupportRuleId, s_localizableTitle, CreateLocalizableResourceString(nameof(PlatformCompatibilityOnlySupportedCsReachableMessage)), DiagnosticCategory.Interoperability, @@ -67,7 +69,7 @@ public sealed partial class PlatformCompatibilityAnalyzer : DiagnosticAnalyzer isDataflowRule: false); internal static readonly DiagnosticDescriptor OnlySupportedCsUnreachable = DiagnosticDescriptorHelper.Create( - RuleId, + SupportRuleId, s_localizableTitle, CreateLocalizableResourceString(nameof(PlatformCompatibilityOnlySupportedCsUnreachableMessage)), DiagnosticCategory.Interoperability, @@ -77,7 +79,7 @@ public sealed partial class PlatformCompatibilityAnalyzer : DiagnosticAnalyzer isDataflowRule: false); internal static readonly DiagnosticDescriptor OnlySupportedCsAllPlatforms = DiagnosticDescriptorHelper.Create( - RuleId, + SupportRuleId, s_localizableTitle, CreateLocalizableResourceString(nameof(PlatformCompatibilityOnlySupportedCsAllPlatformMessage)), DiagnosticCategory.Interoperability, @@ -87,7 +89,7 @@ public sealed partial class PlatformCompatibilityAnalyzer : DiagnosticAnalyzer isDataflowRule: false); internal static readonly DiagnosticDescriptor SupportedCsAllPlatforms = DiagnosticDescriptorHelper.Create( - RuleId, + SupportRuleId, s_localizableTitle, CreateLocalizableResourceString(nameof(PlatformCompatibilitySupportedCsAllPlatformMessage)), DiagnosticCategory.Interoperability, @@ -97,7 +99,7 @@ public sealed partial class PlatformCompatibilityAnalyzer : DiagnosticAnalyzer isDataflowRule: false); internal static readonly DiagnosticDescriptor SupportedCsReachable = DiagnosticDescriptorHelper.Create( - RuleId, + SupportRuleId, s_localizableTitle, CreateLocalizableResourceString(nameof(PlatformCompatibilitySupportedCsReachableMessage)), DiagnosticCategory.Interoperability, @@ -107,7 +109,7 @@ public sealed partial class PlatformCompatibilityAnalyzer : DiagnosticAnalyzer isDataflowRule: false); internal static readonly DiagnosticDescriptor UnsupportedCsAllPlatforms = DiagnosticDescriptorHelper.Create( - RuleId, + SupportRuleId, s_localizableTitle, CreateLocalizableResourceString(nameof(PlatformCompatibilityUnsupportedCsAllPlatformMessage)), DiagnosticCategory.Interoperability, @@ -117,7 +119,7 @@ public sealed partial class PlatformCompatibilityAnalyzer : DiagnosticAnalyzer isDataflowRule: false); internal static readonly DiagnosticDescriptor UnsupportedCsReachable = DiagnosticDescriptorHelper.Create( - RuleId, + SupportRuleId, s_localizableTitle, CreateLocalizableResourceString(nameof(PlatformCompatibilityUnsupportedCsReachableMessage)), DiagnosticCategory.Interoperability, @@ -126,8 +128,28 @@ public sealed partial class PlatformCompatibilityAnalyzer : DiagnosticAnalyzer isPortedFxCopRule: false, isDataflowRule: false); + internal static readonly DiagnosticDescriptor ObsoletedCsAllPlatforms = DiagnosticDescriptorHelper.Create( + ObsoletedRuleId, + s_localizableTitle, + CreateLocalizableResourceString(nameof(PlatformCompatibilityObsoletedCsAllPlatformMessage)), + DiagnosticCategory.Interoperability, + RuleLevel.BuildWarning, + description: s_localizableDescription, + isPortedFxCopRule: false, + isDataflowRule: false); + + internal static readonly DiagnosticDescriptor ObsoletedCsReachable = DiagnosticDescriptorHelper.Create( + ObsoletedRuleId, + s_localizableTitle, + CreateLocalizableResourceString(nameof(PlatformCompatibilityObsoletedCsReachableMessage)), + DiagnosticCategory.Interoperability, + RuleLevel.BuildWarning, + description: s_localizableDescription, + isPortedFxCopRule: false, + isDataflowRule: false); + public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(OnlySupportedCsReachable, OnlySupportedCsUnreachable, - OnlySupportedCsAllPlatforms, SupportedCsAllPlatforms, SupportedCsReachable, UnsupportedCsAllPlatforms, UnsupportedCsReachable); + OnlySupportedCsAllPlatforms, SupportedCsAllPlatforms, SupportedCsReachable, UnsupportedCsAllPlatforms, UnsupportedCsReachable, ObsoletedCsAllPlatforms, ObsoletedCsReachable); public override void Initialize(AnalysisContext context) { @@ -767,9 +789,8 @@ private static void ReportDiagnostics(KeyValuePair operatio static void ReportSupportedDiagnostic(IOperation operation, OperationBlockAnalysisContext context, string operationName, SmallDictionary attributes, SmallDictionary? callsiteAttributes) { - var supportedRule = GetSupportedPlatforms(attributes, callsiteAttributes, out var platformNames); - var callSitePlatforms = GetCallsitePlatforms(attributes, callsiteAttributes, out var callsite, supported: supportedRule); - var csPlatformNames = JoinNames(callSitePlatforms); + var supportedRule = GetSupportedPlatforms(attributes, callsiteAttributes, out var platformNames, out var obsoletedPlatforms); + var csPlatformNames = JoinNames(GetCallsitePlatforms(attributes, callsiteAttributes, out var callsite, supported: supportedRule)); if (callsite == Callsite.Reachable && IsDenyList(callsiteAttributes)) { @@ -779,6 +800,11 @@ static void ReportSupportedDiagnostic(IOperation operation, OperationBlockAnalys var rule = supportedRule ? SwitchSupportedRule(callsite) : SwitchRule(callsite, true); context.ReportDiagnostic(operation.CreateDiagnostic(rule, operationName, JoinNames(platformNames), csPlatformNames)); + if (!obsoletedPlatforms.IsEmpty) + { + context.ReportDiagnostic(operation.CreateDiagnostic(SwitchObsoletedRule(callsite), operationName, JoinNames(obsoletedPlatforms), csPlatformNames)); + } + static DiagnosticDescriptor SwitchSupportedRule(Callsite callsite) => callsite switch { @@ -791,10 +817,12 @@ static DiagnosticDescriptor SwitchSupportedRule(Callsite callsite) static bool IsDenyList(SmallDictionary? callsiteAttributes) => callsiteAttributes != null && callsiteAttributes.Any(csa => DenyList(csa.Value)); - static bool GetSupportedPlatforms(SmallDictionary attributes, SmallDictionary? csAttributes, out List platformNames) + static bool GetSupportedPlatforms(SmallDictionary attributes, SmallDictionary? csAttributes, + out ImmutableArray platformNames, out ImmutableArray obsoletedPlatforms) { + using var obsoletedBuilder = ArrayBuilder.GetInstance(); bool? supportedRule = null; - platformNames = new List(); + var platformsBuilder = ArrayBuilder.GetInstance(); foreach (var (pName, pAttribute) in attributes) { if (pAttribute.SupportedFirst != null && supportedRule.GetValueOrDefault(true)) @@ -805,56 +833,72 @@ static bool GetSupportedPlatforms(SmallDictionary attributes, { if (IsEmptyVersion(supportedVersion)) { - platformNames.Add(GetFormattedString(PlatformCompatibilityVersionAndBefore, - pName, pAttribute.UnsupportedFirst)); + platformsBuilder.Add(AppendMessage(pAttribute, + GetFormattedString(PlatformCompatibilityVersionAndBefore, pName, pAttribute.UnsupportedFirst))); } else { - platformNames.Add(GetFormattedString(PlatformCompatibilityFromVersionToVersion, - pName, supportedVersion, pAttribute.UnsupportedFirst)); + platformsBuilder.Add(AppendMessage(pAttribute, + GetFormattedString(PlatformCompatibilityFromVersionToVersion, pName, supportedVersion, pAttribute.UnsupportedFirst))); } } else if (IsEmptyVersion(supportedVersion)) { if (csAttributes != null && HasSameVersionedPlatformSupport(csAttributes, pName, checkSupport: false)) { - platformNames.Add(GetFormattedString(PlatformCompatibilityAllVersions, pName)); + platformsBuilder.Add(GetFormattedString(PlatformCompatibilityAllVersions, pName)); continue; } - platformNames.Add(EncloseWithQuotes(pName)); + platformsBuilder.Add(EncloseWithQuotes(pName)); } else { - platformNames.Add(GetFormattedString(PlatformCompatibilityVersionAndLater, pName, supportedVersion)); + platformsBuilder.Add(GetFormattedString(PlatformCompatibilityVersionAndLater, pName, supportedVersion)); } } else if (pAttribute.UnsupportedFirst != null) { if (supportedRule.GetValueOrDefault()) { - platformNames.Clear(); + platformsBuilder.Clear(); } supportedRule = false; if (IsEmptyVersion(pAttribute.UnsupportedFirst)) { if (csAttributes != null && HasSameVersionedPlatformSupport(csAttributes, pName, checkSupport: true)) { - platformNames.Add(GetFormattedString(PlatformCompatibilityAllVersions, pName)); + platformsBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityAllVersions, pName))); continue; } - platformNames.Add(EncloseWithQuotes(pName)); + platformsBuilder.Add(AppendMessage(pAttribute, EncloseWithQuotes(pName))); } else { - platformNames.Add(GetFormattedString(PlatformCompatibilityVersionAndLater, - pName, pAttribute.UnsupportedFirst)); + platformsBuilder.Add(AppendMessage(pAttribute, + GetFormattedString(PlatformCompatibilityVersionAndLater, pName, pAttribute.UnsupportedFirst))); } } + + if (pAttribute.ObsoletedIn != null) + { + obsoletedBuilder.Add(AppendMessageAndUrl(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndLater, pName, pAttribute.ObsoletedIn))); + } } + obsoletedPlatforms = obsoletedBuilder.ToImmutable(); + platformNames = platformsBuilder.ToImmutable(); return supportedRule.GetValueOrDefault(true); } } + static DiagnosticDescriptor SwitchObsoletedRule(Callsite callsite) + { + return callsite switch + { + Callsite.AllPlatforms => ObsoletedCsAllPlatforms, + Callsite.Reachable => ObsoletedCsReachable, + _ => throw new NotImplementedException() + }; + } static DiagnosticDescriptor SwitchRule(Callsite callsite, bool unsupported) { @@ -878,16 +922,52 @@ static DiagnosticDescriptor SwitchRule(Callsite callsite, bool unsupported) } } + static string AppendMessage(Versions attribute, string message) + { + if (attribute.UnsupportedMessage is not null) + { + message += $", {attribute.UnsupportedMessage}"; + } + + return message; + } + + static string AppendMessageAndUrl(Versions attribute, string message) + { + if (attribute.ObsoletedMessage is not null) + { + message += $", {attribute.ObsoletedMessage}"; + } + + if (attribute.ObsoletedUrl is not null) + { + message += $", {attribute.ObsoletedUrl}"; + } + + return message; + } + static void ReportUnsupportedDiagnostic(IOperation operation, OperationBlockAnalysisContext context, string operationName, SmallDictionary attributes, SmallDictionary? callsiteAttributes) { - var unsupportedRule = GetPlatformNames(attributes, callsiteAttributes, out var platformNames); + var unsupportedRule = GetPlatformNames(attributes, callsiteAttributes, out var platformNames, out var obsoletedPlatforms); var csPlatformNames = JoinNames(GetCallsitePlatforms(attributes, callsiteAttributes, out var callsite, supported: !unsupportedRule)); - context.ReportDiagnostic(operation.CreateDiagnostic(SwitchRule(callsite, unsupportedRule), operationName, JoinNames(platformNames), csPlatformNames)); - static bool GetPlatformNames(SmallDictionary attributes, SmallDictionary? csAttributes, out List platformNames) + if (!platformNames.IsEmpty) { - platformNames = new List(); + context.ReportDiagnostic(operation.CreateDiagnostic(SwitchRule(callsite, unsupportedRule), operationName, JoinNames(platformNames), csPlatformNames)); + } + + if (!obsoletedPlatforms.IsEmpty) + { + context.ReportDiagnostic(operation.CreateDiagnostic(SwitchObsoletedRule(callsite), operationName, JoinNames(obsoletedPlatforms), csPlatformNames)); + } + + static bool GetPlatformNames(SmallDictionary attributes, SmallDictionary? csAttributes, + out ImmutableArray platformNames, out ImmutableArray obsoletedPlatforms) + { + using var obsoletedBuilder = ArrayBuilder.GetInstance(); + using var platformsBuilder = ArrayBuilder.GetInstance(); var unsupportedRule = true; foreach (var (pName, pAttribute) in attributes) { @@ -908,20 +988,21 @@ static bool GetPlatformNames(SmallDictionary attributes, Small unsupportedRule = true; if (IsEmptyVersion(pAttribute.UnsupportedFirst!)) { - platformNames.Add(GetFormattedString(PlatformCompatibilityVersionAndBefore, pName, supportedVersion)); + platformsBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndBefore, pName, supportedVersion))); } else { - platformNames.Add(GetFormattedString(PlatformCompatibilityFromVersionToVersion, pName, unsupportedVersion, supportedVersion)); + platformsBuilder.Add(AppendMessage(pAttribute, + GetFormattedString(PlatformCompatibilityFromVersionToVersion, pName, unsupportedVersion, supportedVersion))); } continue; } - platformNames.Add(GetFormattedString(PlatformCompatibilityVersionAndLater, pName, supportedVersion)); + platformsBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndLater, pName, supportedVersion))); } else { - platformNames.Add(GetFormattedString(PlatformCompatibilityFromVersionToVersion, - pName, supportedVersion, unsupportedVersion)); + platformsBuilder.Add(AppendMessage(pAttribute, + GetFormattedString(PlatformCompatibilityFromVersionToVersion, pName, supportedVersion, unsupportedVersion))); } } else @@ -930,14 +1011,14 @@ static bool GetPlatformNames(SmallDictionary attributes, Small { if (csAttributes != null && HasSameVersionedPlatformSupport(csAttributes, pName, checkSupport: true)) { - platformNames.Add(GetFormattedString(PlatformCompatibilityAllVersions, pName)); + platformsBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityAllVersions, pName))); continue; } - platformNames.Add(EncloseWithQuotes(pName)); + platformsBuilder.Add(AppendMessage(pAttribute, EncloseWithQuotes(pName))); } else { - platformNames.Add(GetFormattedString(PlatformCompatibilityVersionAndLater, pName, unsupportedVersion)); + platformsBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndLater, pName, unsupportedVersion))); } } } @@ -946,23 +1027,31 @@ static bool GetPlatformNames(SmallDictionary attributes, Small unsupportedRule = false; if (IsEmptyVersion(supportedVersion)) { - platformNames.Add(EncloseWithQuotes(pName)); + platformsBuilder.Add(EncloseWithQuotes(pName)); } else { - platformNames.Add(GetFormattedString(PlatformCompatibilityVersionAndLater, pName, supportedVersion)); + platformsBuilder.Add(GetFormattedString(PlatformCompatibilityVersionAndLater, pName, supportedVersion)); } } + + if (pAttribute.ObsoletedIn != null) + { + obsoletedBuilder.Add(AppendMessageAndUrl(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndLater, pName, pAttribute.ObsoletedIn))); + } } + + obsoletedPlatforms = obsoletedBuilder.ToImmutable(); + platformNames = platformsBuilder.ToImmutable(); return unsupportedRule; } } - static List GetCallsitePlatforms(SmallDictionary attributes, + static ImmutableArray GetCallsitePlatforms(SmallDictionary attributes, SmallDictionary? callsiteAttributes, out Callsite callsite, bool supported) { callsite = Callsite.AllPlatforms; - var platformNames = new List(); + using var platformNames = ArrayBuilder.GetInstance(); if (callsiteAttributes != null) { foreach (var (pName, csAttribute) in callsiteAttributes) @@ -1045,7 +1134,7 @@ static List GetCallsitePlatforms(SmallDictionary attri } } } - return platformNames; + return platformNames.ToImmutable(); } static string GetFormattedString(string resource, string platformName, object? arg1 = null, object? arg2 = null) => @@ -1056,9 +1145,9 @@ static string AddOsxIfMacOS(string platformName) => static string EncloseWithQuotes(string pName) => $"'{AddOsxIfMacOS(pName)}'"; - static string JoinNames(List platformNames) + static string JoinNames(ImmutableArray platformNames) { - platformNames.Sort(StringComparer.OrdinalIgnoreCase); + platformNames = platformNames.Sort(StringComparer.OrdinalIgnoreCase); return string.Join(CommaSeparator, platformNames); } @@ -1156,8 +1245,8 @@ private static ISymbol GetEventAccessor(IEventSymbol iEvent, IOperation operatio private static void AnalyzeOperation(IOperation operation, OperationAnalysisContext context, PooledConcurrentDictionary, (SmallDictionary attributes, SmallDictionary? csAttributes)> platformSpecificOperations, - ConcurrentDictionary platformSpecificMembers, ImmutableArray msBuildPlatforms, - ITypeSymbol? notSupportedExceptionType, bool crossPlatform, SmallDictionary relatedPlatforms) + ConcurrentDictionary platformSpecificMembers, ImmutableArray msBuildPlatforms, + ITypeSymbol? notSupportedExceptionType, bool crossPlatform, SmallDictionary relatedPlatforms) { if (operation.Parent is IArgumentOperation argumentOperation && UsedInCreatingNotSupportedException(argumentOperation, notSupportedExceptionType)) { @@ -1362,6 +1451,7 @@ private static bool IsNotSuppressedByCallSite(SmallDictionary SuppressedByCallSiteUnsupported(callSiteAttribute, attribute.UnsupportedFirst)))) { diagnosticAttribute.UnsupportedFirst = (Version)attribute.UnsupportedFirst.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; } } } @@ -1379,12 +1469,14 @@ private static bool IsNotSuppressedByCallSite(SmallDictionary if (!UnsupportedFirstSuppressed(attribute, callSiteAttribute)) { diagnosticAttribute.UnsupportedFirst = (Version)attribute.UnsupportedFirst.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; } if (attribute.UnsupportedSecond != null && !UnsupportedSecondSuppressed(attribute, callSiteAttribute)) { diagnosticAttribute.UnsupportedSecond = (Version)attribute.UnsupportedSecond.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; } } else if (msBuildPlatforms.Contains(platformName, StringComparer.OrdinalIgnoreCase)) @@ -1393,12 +1485,14 @@ private static bool IsNotSuppressedByCallSite(SmallDictionary { diagnosticAttribute.SupportedFirst = (Version)attribute.SupportedFirst.Clone(); diagnosticAttribute.UnsupportedFirst = (Version)attribute.UnsupportedFirst.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; } if (attribute.UnsupportedSecond != null && !SuppressedByCallSiteUnsupported(callSiteAttribute, attribute.UnsupportedSecond)) { diagnosticAttribute.SupportedFirst = (Version)attribute.SupportedFirst.Clone(); diagnosticAttribute.UnsupportedSecond = (Version)attribute.UnsupportedSecond.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; } } } @@ -1422,21 +1516,25 @@ private static bool IsNotSuppressedByCallSite(SmallDictionary if (!SuppressedByCallSiteUnsupported(callSiteAttribute, attribute.UnsupportedFirst)) { diagnosticAttribute.UnsupportedFirst = (Version)attribute.UnsupportedFirst.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; } else if (DenyList(callSiteAttribute)) { diagnosticAttribute.UnsupportedFirst = (Version)attribute.UnsupportedFirst.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; } } else { diagnosticAttribute.UnsupportedFirst = (Version)attribute.UnsupportedFirst.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; } } else if (msBuildPlatforms.Contains(platformName, StringComparer.OrdinalIgnoreCase) && !SuppressedByCallSiteUnsupported(callSiteAttribute, attribute.UnsupportedFirst)) { diagnosticAttribute.UnsupportedFirst = (Version)attribute.UnsupportedFirst.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; } } else if (msBuildPlatforms.Contains(platformName, StringComparer.OrdinalIgnoreCase) && @@ -1444,6 +1542,39 @@ private static bool IsNotSuppressedByCallSite(SmallDictionary { // if MsBuild list contain the platform and call site has no any other supported attribute it means global, so need to warn diagnosticAttribute.UnsupportedFirst = (Version)attribute.UnsupportedFirst.Clone(); + diagnosticAttribute.UnsupportedMessage = attribute.UnsupportedMessage; + } + } + + // Check if obsoleted attribute suppressed + if (attribute.ObsoletedIn != null) + { + if (callSiteAttributes.TryGetValue(platformName, out var callSiteAttribute)) + { + if (callSiteAttribute.SupportedFirst != null) + { + if ((callSiteAttribute.ObsoletedIn == null || callSiteAttribute.ObsoletedIn > attribute.ObsoletedIn) && + (callSiteAttribute.UnsupportedFirst == null || callSiteAttribute.UnsupportedFirst > attribute.ObsoletedIn)) + { + diagnosticAttribute.ObsoletedIn = (Version)attribute.ObsoletedIn.Clone(); + diagnosticAttribute.ObsoletedMessage = attribute.ObsoletedMessage; + diagnosticAttribute.ObsoletedUrl = attribute.ObsoletedUrl; + } + } + else if (msBuildPlatforms.Contains(platformName, StringComparer.OrdinalIgnoreCase) && + callSiteAttribute.UnsupportedFirst != null && callSiteAttribute.UnsupportedFirst > attribute.ObsoletedIn) + { + diagnosticAttribute.ObsoletedIn = (Version)attribute.ObsoletedIn.Clone(); + diagnosticAttribute.ObsoletedMessage = attribute.ObsoletedMessage; + diagnosticAttribute.ObsoletedUrl = attribute.ObsoletedUrl; + } + } + else if (msBuildPlatforms.Contains(platformName, StringComparer.OrdinalIgnoreCase) && + !callSiteAttributes.Values.Any(AllowList)) + { + diagnosticAttribute.ObsoletedIn = (Version)attribute.ObsoletedIn.Clone(); + diagnosticAttribute.ObsoletedMessage = attribute.ObsoletedMessage; + diagnosticAttribute.ObsoletedUrl = attribute.ObsoletedUrl; } } @@ -1534,6 +1665,10 @@ private static Versions CopyAllAttributes(Versions copyTo, Versions copyFrom) copyTo.SupportedSecond = (Version?)copyFrom.SupportedSecond?.Clone(); copyTo.UnsupportedFirst = (Version?)copyFrom.UnsupportedFirst?.Clone(); copyTo.UnsupportedSecond = (Version?)copyFrom.UnsupportedSecond?.Clone(); + copyTo.UnsupportedMessage = copyFrom.UnsupportedMessage; + copyTo.ObsoletedIn = (Version?)copyFrom.ObsoletedIn?.Clone(); + copyTo.ObsoletedMessage = copyFrom.ObsoletedMessage; + copyTo.ObsoletedUrl = copyFrom.ObsoletedUrl; return copyTo; } @@ -1694,6 +1829,13 @@ static void MergePlatformAttributes(ImmutableArray immediateAttri notFoundPlatforms.Add(platform); } } + // Check for Obsoleted attributes, only lower version could overwrite + if (attributes.ObsoletedIn != null && + childAttributes.TryGetValue(platform, out var childAttr) && + childAttr.ObsoletedIn != null && childAttr.ObsoletedIn < attributes.ObsoletedIn) + { + attributes.ObsoletedIn = childAttr.ObsoletedIn; + } } CheckAttributesConsistency(pAttributes); @@ -1751,9 +1893,8 @@ static void CheckAttributesConsistency(SmallDictionary childAt { allowList = true; } - else + else if (DenyList(attributes)) { - Debug.Assert(DenyList(attributes)); unsupportedList.Add(platform); } } @@ -1801,7 +1942,7 @@ private static bool TryAddValidAttribute([NotNullWhen(true)] ref SmallDictionary attributes[platformName] = new Versions(); } - if (!AddAttribute(attribute.AttributeClass.Name, version, attributes[platformName])) + if (!AddAttribute(attribute, version, attributes[platformName])) { attributes.Remove(platformName); } @@ -1812,7 +1953,7 @@ private static bool TryAddValidAttribute([NotNullWhen(true)] ref SmallDictionary attributes[relation.relatedPlatform] = new Versions(); } - AddAttribute(attribute.AttributeClass.Name, version, attributes[relation.relatedPlatform]); + AddAttribute(attribute, version, attributes[relation.relatedPlatform]); } return true; @@ -1876,8 +2017,9 @@ private static bool TryParsePlatformNameAndVersion(string osString, out string o private static string GetNameAsMacOsWhenOSX(string platformName) => platformName.Equals(OSX, StringComparison.OrdinalIgnoreCase) ? macOS : platformName; - private static bool AddAttribute(string name, Version version, Versions attributes) + private static bool AddAttribute(AttributeData attribute, Version version, Versions attributes) { + string name = attribute.AttributeClass.Name; if (name == SupportedOSPlatformAttribute) { if (attributes.UnsupportedFirst != null && attributes.UnsupportedFirst == version) @@ -1890,38 +2032,68 @@ private static bool AddAttribute(string name, Version version, Versions attribut AddOrUpdateSupportedAttribute(attributes, version); } } - else + else if (name == UnsupportedOSPlatformAttribute) { - Debug.Assert(name == UnsupportedOSPlatformAttribute); - if (attributes.SupportedFirst != null && attributes.SupportedFirst == version) { attributes.SupportedFirst = null; } - AddOrUpdateUnsupportedAttribute(attributes, version); + AddOrUpdateUnsupportedAttribute(attribute, attributes, version); + } + else + { + Debug.Assert(name == ObsoletedInOSPlatformAttribute); + AddOrUpdateObsoletedAttribute(attribute, attributes, version); } return true; - static void AddOrUpdateUnsupportedAttribute(Versions attributes, Version version) + static void AddOrUpdateObsoletedAttribute(AttributeData attribute, Versions attributes, Version version) { + var message = PopulateMessage(attribute); + var url = PopulateUrl(attribute); + + if (attributes.ObsoletedIn != null) + { + // only keep lowest version, ignore other versions + if (attributes.ObsoletedIn > version) + { + attributes.ObsoletedIn = version; + attributes.ObsoletedMessage = message; + attributes.ObsoletedUrl = url; + } + } + else + { + attributes.ObsoletedIn = version; + attributes.ObsoletedMessage = message; + attributes.ObsoletedUrl = url; + } + } + + static void AddOrUpdateUnsupportedAttribute(AttributeData attribute, Versions attributes, Version version) + { + var message = PopulateMessage(attribute); if (attributes.UnsupportedFirst != null) { if (attributes.UnsupportedFirst > version) { attributes.UnsupportedSecond = attributes.UnsupportedFirst; attributes.UnsupportedFirst = version; + attributes.UnsupportedMessage = message; } else if (attributes.UnsupportedSecond == null || attributes.UnsupportedSecond > version) { attributes.UnsupportedSecond = version; + attributes.UnsupportedMessage = message; } } else { attributes.UnsupportedFirst = version; + attributes.UnsupportedMessage = message; } } @@ -1942,6 +2114,26 @@ static void AddOrUpdateSupportedAttribute(Versions attributes, Version version) } } + private static string? PopulateMessage(AttributeData attribute) + { + if (attribute.ConstructorArguments.Length == 2) + { + return attribute.ConstructorArguments[1].Value?.ToString(); + } + + return null; + } + + private static string? PopulateUrl(AttributeData attribute) + { + if (attribute.NamedArguments.Length == 1 && attribute.NamedArguments[0].Key is "Url") + { + return attribute.NamedArguments[0].Value.Value.ToString(); + } + + return null; + } + /// /// Determines if the attributes supported only for the platform (allow list) /// diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index 1afda5dd95..c2d117b527 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -1485,7 +1485,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. String parameters passed by value with the 'OutAttribute' can destabilize the runtime if the string is an interned string. @@ -1948,4 +1948,10 @@ The behavior of '{0}' could vary based on the current user's locale settings. Provide a value for the 'IFormatProvider' argument. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf index a8ae91171d..f4ac63acb1 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf @@ -1852,6 +1852,16 @@ {0} od verze {1} do {2} 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. Toto místo volání je k dispozici na všech platformách. {0} se podporuje jen na {1}. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - Toto místo volání je k dispozici na všech platformách. {0} se nepodporuje na {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - Toto místo volání je k dispozici na {2}. {0} se nepodporuje na {1}. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf index 1a686fe537..3525928809 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf @@ -1852,6 +1852,16 @@ {0}, Version {1} bis {2} 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. Diese Aufrufsite ist auf allen Plattformen erreichbar. "{0}" nur unterstützt für: {1}. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - Diese Aufrufsite ist auf allen Plattformen erreichbar. "{0}" nicht unterstützt für: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - Diese Aufrufsite ist erreichbar für: {2}. "{0}" nicht unterstützt für: {1}. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf index 6a75f6fa38..bd1ec023a4 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf @@ -1852,6 +1852,16 @@ "{0}" de la versión {1} a la {2} 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. Se puede acceder a este sitio de llamada en todas las plataformas. "{0}" solo se admite en {1}. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - Se puede acceder a este sitio de llamada en todas las plataformas. "{0}" no se admite en {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - Se puede acceder a este sitio de llamada en {2}. "{0}" no se admite en {1}. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf index 93ff5d5afd..d3df8e0356 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf @@ -1852,6 +1852,16 @@ '{0}' de la version {1} à {2} 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. Ce site d'appel est accessible sur toutes les plateformes. '{0}' est uniquement pris en charge sur {1}. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - Ce site d'appel est accessible sur toutes les plateformes. '{0}' n'est pas pris en charge sur {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - Ce site d'appel est accessible sur {2}. '{0}' n'est pas pris en charge sur {1}. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf index 7e4006d87f..28865bc998 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf @@ -1852,6 +1852,16 @@ '{0}' dalla versione {1} alla versione {2} 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. Questo sito di chiamata è raggiungibile da tutte le piattaforme. '{0}' è supportato solo in {1}. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - Questo sito di chiamata è raggiungibile da tutte le piattaforme. '{0}' non è supportato in {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - Questo sito di chiamata è raggiungibile da {2}. '{0}' non è supportato in {1}. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf index 5a11f87e84..4bddbaac05 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf @@ -1852,6 +1852,16 @@ バージョン {1} から {2} の '{0}' 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. この呼び出しサイトはすべてのプラットフォームで到達可能です。'{0}' は {1} でのみサポートされています。 @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - この呼び出しサイトはすべてのプラットフォームで到達可能です。'{0}' は {1} でサポートされていません。 - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - この呼び出しサイトは {2} で到達可能です。'{0}' は {1} でサポートされていません。 + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf index 66b05763d3..57e2547320 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf @@ -1852,6 +1852,16 @@ '{0}' 버전 {1}~{2} 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. 이 호출 사이트에는 모든 플랫폼에서 연결할 수 있습니다. '{0}'은(는) {1}에서만 지원됩니다. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - 이 호출 사이트에는 모든 플랫폼에서 연결할 수 있습니다. '{0}'은(는) {1}에서 지원되지 않습니다. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - 이 호출 사이트에는 {2}에서 연결할 수 있습니다. '{0}'은(는) {1}에서 지원되지 않습니다. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf index 1b07cfdfff..251ffd1551 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf @@ -1852,6 +1852,16 @@ system „{0}” w wersji od {1} do {2} 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. To miejsce wywołania jest osiągalne na wszystkich platformach. Metoda „{0}” jest obsługiwana tylko na następujących platformach: {1}. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - To miejsce wywołania jest osiągalne na wszystkich platformach. Metoda „{0}” nie jest obsługiwana na następujących platformach: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - To miejsce wywołania jest osiągalne na platformie: {2}. Metoda „{0}” nie jest obsługiwana na następujących platformach: {1}. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf index 15412da949..adc382392f 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf @@ -1852,6 +1852,16 @@ '{0}' da versão {1} à {2} 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. Este site de chamada pode ser acessado em todas as plataformas. Só há suporte para '{0}' em: {1}. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - Este site de chamada pode ser acessado em todas as plataformas. Não há suporte para '{0}' em: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - Este site de chamada pode ser acessado em: {2}. Não há suporte para '{0}' em: {1}. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf index 25134844e9..4fed9068f2 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf @@ -1852,6 +1852,16 @@ "{0}" с версии {1} до {2} 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. Этот сайт вызова доступен на всех платформах. "{0}" поддерживается только в {1}. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - Этот сайт вызова доступен на всех платформах. "{0}" не поддерживается в {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - Этот сайт вызова доступен в {2}. "{0}" не поддерживается в {1}. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf index 136d1fda74..ab6e299fd9 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf @@ -1852,6 +1852,16 @@ '{0}' {1} sürümünden {2} sürümüne kadar 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. Bu çağrı sitesine tüm platformlarda ulaşılabilir. '{0}' yalnızca şurada desteklenir: {1}. @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - Bu çağrı sitesine tüm platformlarda ulaşılabilir. '{0}' şurada desteklenmez: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - Bu çağrı sitesine şurada ulaşılabilir: {2}. '{0}' şurada desteklenmez: {1}. + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf index d6fe644987..efebae4af1 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf @@ -1852,6 +1852,16 @@ "{0}" 版本 {1} 到 {2}。 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. 可在所有平台上访问此调用站点。"{0}" 仅在 {1} 上受支持。 @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - 可在所有平台上访问此调用站点。"{0}" 在 {1} 上不受支持。 - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - 可在 {2} 上访问此调用站点。"{0}" 在 {1} 上不受支持。 + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf index 0b61f2cda2..0a4f43d653 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf @@ -1852,6 +1852,16 @@ '{0}' 從 {1} 至 {2} 的版本 'SupportedOnWindows1903UnsupportedOn2004()' is supported on: 'windows' from version 10.0.1903 to 10.0.2004. + + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + + + + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + + This call site is reachable on all platforms. '{0}' is only supported on: {1}. 可在所有平台上連線到此呼叫網站。只有 {1} 支援 '{0}'。 @@ -1884,12 +1894,12 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - 可在所有平台上連線到此呼叫網站。{1} 不支援 '{0}'。 - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' + This call site is reachable on all platforms. '{0}' is unsupported on: {1}. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. This call site is reachable on: {2}. '{0}' is unsupported on: {1}. - 可在 {2} 上連線到此呼叫網站。{1} 不支援 '{0}'。 + This call site is reachable on: {2}. '{0}' is unsupported on: {1}. This call site is reachable on: 'windows', 'browser'. 'UnsupportedOnBrowser()' is unsupported on: 'browser'. diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs new file mode 100644 index 0000000000..094782dc0e --- /dev/null +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs @@ -0,0 +1,246 @@ +// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. + +using System.Threading.Tasks; +using Xunit; +using VerifyCS = Test.Utilities.CSharpCodeFixVerifier< + Microsoft.NetCore.Analyzers.InteropServices.PlatformCompatibilityAnalyzer, + Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; +using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier< + Microsoft.NetCore.Analyzers.InteropServices.PlatformCompatibilityAnalyzer, + Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>; + +namespace Microsoft.NetCore.Analyzers.InteropServices.UnitTests +{ + public partial class PlatformCompatabilityAnalyzerTests + { + [Fact] + public async Task ObsoletedMethodsCalledWarnsAsync() + { + var csSource = @" +using System; +using System.Runtime.Versioning; +using Mock; + +public class Test +{ + [SupportedOSPlatform(""Linux"")] + public void M1() + { + ObsoletedOnWindows10(); // Shold not warn as only accessible on Linux + {|#0:ObsoletedOnLinux4()|}; // This call site is reachable on: 'Linux'. 'Test.ObsoletedOnLinux()' is obsoleted on: 'Linux' 4.1 and later. + {|CA1422:ObsoletedOnLinux4AndWindows10()|}; // This call site is reachable on: 'Linux'. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Linux' 4.1 and later. + } + + [ObsoletedInOSPlatform(""Linux4.1"")] + public void ObsoletedOnLinux4() { } + + [ObsoletedInOSPlatform(""Windows10.1.1.1"")] + public void ObsoletedOnWindows10() { } + + [ObsoletedInOSPlatform(""Linux4.1"", ""Use Linux4Supported"")] + [ObsoletedInOSPlatform(""Windows10.1.1.1"",""Use Windows10Supported"")] + public void ObsoletedOnLinux4AndWindows10() { } +}" + MockObsoletedAttributeCS; + await VerifyAnalyzerCSAsync(csSource, VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsReachable).WithLocation(0) + .WithArguments("Test.ObsoletedOnLinux4()", "'Linux' 4.1 and later", "'Linux'")); + + + var vbSource = @" +Imports System +Imports System.Runtime.Versioning +Imports Mock +Public Class Test + + Public Sub M1() + ObsoletedOnWindows10() + {|#0:ObsoletedOnLinux()|} ' This call site is reachable on: 'Linux'. 'Public Sub ObsoletedOnLinux()' is obsoleted on: 'Linux' 4.1 and later. + End Sub + + + Public Sub ObsoletedOnWindows10() + End Sub + + + Public Sub ObsoletedOnLinux() + End Sub +End Class +" + MockObsoletedAttributeVB; + await VerifyAnalyzerVBAsync(vbSource, VerifyVB.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsReachable).WithLocation(0) + .WithArguments("Public Sub ObsoletedOnLinux()", "'Linux' 4.1 and later", "'Linux'")); + } + + [Fact] + public async Task ObsoletedWithMessageUrlCalledWarnsAsync() + { + var csSource = @" +using System; +using System.Runtime.Versioning; +using Mock; + +public class Test +{ + public void CrossPlatform() + { + {|#0:ObsoletedWithMessageAndUrl()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessageAndUrl()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead, http://www/look.for.more.info. + {|#1:ObsoletedWithMessage()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead. + ObsoletedOnAndroid(); // Cross platform and android not int he MSBuild list so not warn + } + + [SupportedOSPlatform(""Android"")] + public void ReachableOnAndroidAndWindows() + { + ObsoletedWithMessageAndUrl(); // Unreachable on windows, not warn + ObsoletedWithMessage(); + {|CA1422:ObsoletedOnAndroid()|}; // This call site is reachable on: 'Android', 'Windows'. 'Test.ObsoletedOnAndroid()' is obsoleted on: 'android' 21.0 and later. + } + + [Mock.UnsupportedOSPlatform(""Android31.0"")] + [System.Runtime.Versioning.UnsupportedOSPlatform(""Windows10.1.0"")] + public void UnreachableOnAndroidAndWindows() + { + ObsoletedWithMessageAndUrl(); // Not supported on windows, not warn + ObsoletedWithMessage(); + ObsoletedOnAndroid(); // Obsoleted before unuspport, so warns + } + + [ObsoletedInOSPlatform(""android21.0"")] + public void ObsoletedOnAndroid() { } + + [ObsoletedInOSPlatform(""Windows10.1.1.1"", ""Use other method instead"", Url = ""http://www/look.for.more.info"")] + public void ObsoletedWithMessageAndUrl() { } + [ObsoletedInOSPlatform(""Windows10.1.1.1"", ""Use other method instead"")] + public void ObsoletedWithMessage() { } +}" + MockObsoletedAttributeCS; + await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms, VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsAllPlatforms).WithLocation(0). + WithArguments("Test.ObsoletedWithMessageAndUrl()", "'Windows' 10.1.1.1 and later, Use other method instead, http://www/look.for.more.info"), + VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsAllPlatforms).WithLocation(1). + WithArguments("Test.ObsoletedWithMessage()", "'Windows' 10.1.1.1 and later, Use other method instead")); + } + + [Fact] + public async Task UnsuportedWithMessageCalledWarnsAsync() + { + var csSource = @" +using System; +using System.Runtime.Versioning; +using Mock; + +public class Test +{ + public void CrossPlatform() + { + [|UnsupportedIosBrowserWatchOS()|]; // This call site is reachable on all platforms. 'Test.UnsupportedIosBrowserWatchOS()' is unsupported on: 'Browser'. Use BrowserSupported() method instead, + // 'ios' 13.0 and later. Use Test.IOsSupported() method instead, 'maccatalyst' 13.0 and later. Use Test.IOsSupported() method instead. + UnsupportedAndroid(); // Cross platform and android not int he MSBuild list so not warn + } + + [SupportedOSPlatform(""Android"")] + [SupportedOSPlatform(""browser"")] + public void ReachableOnAndroidAndBrowser() + { + [|UnsupportedIosBrowserWatchOS()|]; // This call site is reachable on: 'Android', 'browser'. 'Test.UnsupportedIosBrowserWatchOS()' is unsupported on: 'Browser', Use BrowserSupported() method instead. + [|UnsupportedAndroid()|]; // This call site is reachable on: 'Android' all versions, 'browser'. 'Test.UnsupportedAndroid()' is unsupported on: 'Android' 21.0 and later, Use other method instead. + } + + [Mock.UnsupportedOSPlatform(""Android21.0"", ""Use other method instead"")] + public void UnsupportedAndroid() { } + + [Mock.UnsupportedOSPlatform(""ios13.0"", ""Use Test.IOsSupported() method instead"")] + [Mock.UnsupportedOSPlatform(""Browser"", ""Use BrowserSupported() method instead"")] + [Mock.UnsupportedOSPlatform(""Watchos"", ""Use WitchSupported() method instead"")] + public void UnsupportedIosBrowserWatchOS() { } +}" + MockObsoletedAttributeCS; + await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms); + } + + private readonly string MockObsoletedAttributeCS = @" +namespace Mock +{ + public abstract class OSPlatformAttribute : Attribute + { + private protected OSPlatformAttribute(string platformName) + { + PlatformName = platformName; + } + public string PlatformName { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | + AttributeTargets.Class | + AttributeTargets.Constructor | + AttributeTargets.Enum | + AttributeTargets.Event | + AttributeTargets.Field | + AttributeTargets.Interface | + AttributeTargets.Method | + AttributeTargets.Module | + AttributeTargets.Property | + AttributeTargets.Struct, + AllowMultiple = true, Inherited = false)] + public sealed class UnsupportedOSPlatformAttribute : OSPlatformAttribute + { + public UnsupportedOSPlatformAttribute(string platformName) : base(platformName) + { + } + public UnsupportedOSPlatformAttribute(string platformName, string message) : base(platformName) + { + Message = message; + } + public string Message { get; } + } + + [AttributeUsage(AttributeTargets.Assembly | + AttributeTargets.Class | + AttributeTargets.Constructor | + AttributeTargets.Enum | + AttributeTargets.Event | + AttributeTargets.Field | + AttributeTargets.Interface | + AttributeTargets.Method | + AttributeTargets.Module | + AttributeTargets.Property | + AttributeTargets.Struct, + AllowMultiple = true, Inherited = false)] + public sealed class ObsoletedInOSPlatformAttribute : OSPlatformAttribute + { + public ObsoletedInOSPlatformAttribute(string platformName) : base(platformName) + { + } + public ObsoletedInOSPlatformAttribute(string platformName, string message) : base(platformName) + { + Message = message; + } + public string Message { get; } + public string Url { get; set; } + } +}"; + + private readonly string MockObsoletedAttributeVB = @" +Namespace Mock + + Public NotInheritable Class ObsoletedInOSPlatformAttribute + Inherits Attribute + + Public Sub New(ByVal platformName As String) + PlatformName = platformName + End Sub + + Public Sub New(ByVal platformName As String, ByVal message As String) + PlatformName = platformName + Message = message + End Sub + + Public ReadOnly Property PlatformName As String + Public ReadOnly Property Message As String + Public Property Url As String + End Class +End Namespace"; + } +} diff --git a/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt b/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt index 428f549aad..cc1d32e615 100644 --- a/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt +++ b/src/Utilities/Compiler/DiagnosticCategoryAndIdRanges.txt @@ -16,7 +16,7 @@ Performance: HA, CA1800-CA1854 Security: CA2100-CA2153, CA2300-CA2330, CA3000-CA3147, CA5300-CA5405 Usage: CA1801, CA1806, CA1816, CA2200-CA2209, CA2211-CA2259 Naming: CA1700-CA1727 -Interoperability: CA1400-CA1421 +Interoperability: CA1400-CA1422 Maintainability: CA1500-CA1509 Reliability: CA9998-CA9999, CA2000-CA2019 Documentation: CA1200-CA1200 From f8941d283b894aaeff4fc25d48d8cbc8c45139ef Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Fri, 22 Jul 2022 13:45:41 -0700 Subject: [PATCH 2/6] Obsoleted warnings can be guarded with negated OperatingSystemIsOSPlatform APIs --- .../PlatformCompatibilityAnalyzer.cs | 93 ++++++--- .../MicrosoftNetCoreAnalyzersResources.resx | 2 + .../MicrosoftNetCoreAnalyzersResources.cs.xlf | 4 +- .../MicrosoftNetCoreAnalyzersResources.de.xlf | 4 +- .../MicrosoftNetCoreAnalyzersResources.es.xlf | 4 +- .../MicrosoftNetCoreAnalyzersResources.fr.xlf | 4 +- .../MicrosoftNetCoreAnalyzersResources.it.xlf | 4 +- .../MicrosoftNetCoreAnalyzersResources.ja.xlf | 4 +- .../MicrosoftNetCoreAnalyzersResources.ko.xlf | 4 +- .../MicrosoftNetCoreAnalyzersResources.pl.xlf | 4 +- ...crosoftNetCoreAnalyzersResources.pt-BR.xlf | 4 +- .../MicrosoftNetCoreAnalyzersResources.ru.xlf | 4 +- .../MicrosoftNetCoreAnalyzersResources.tr.xlf | 4 +- ...osoftNetCoreAnalyzersResources.zh-Hans.xlf | 4 +- ...osoftNetCoreAnalyzersResources.zh-Hant.xlf | 4 +- ...lityAnalyzer.ObsoletedInOSPlatformTests.cs | 190 ++++++++++++++++-- 16 files changed, 263 insertions(+), 74 deletions(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs index 7de95c05bb..8ab1a4a632 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs @@ -526,6 +526,12 @@ static bool IsKnownValueGuarded( attribute.UnsupportedSecond = null; } + if (attribute.ObsoletedIn != null && + attribute.ObsoletedIn.IsGreaterThanOrEqualTo(info.Version)) + { + attribute.ObsoletedIn = null; + } + if (!IsEmptyVersion(info.Version)) { capturedVersions[info.PlatformName] = info.Version; @@ -730,13 +736,16 @@ static void RemoveUnsupportsOnDifferentPlatforms(SmallDictionary attributes, } } - if (pAttribute.ObsoletedIn != null) - { - obsoletedBuilder.Add(AppendMessageAndUrl(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndLater, pName, pAttribute.ObsoletedIn))); - } + AddObsoletedIn(csAttributes, obsoletedBuilder, pName, pAttribute); } obsoletedPlatforms = obsoletedBuilder.ToImmutable(); @@ -926,7 +932,7 @@ static string AppendMessage(Versions attribute, string message) { if (attribute.UnsupportedMessage is not null) { - message += $", {attribute.UnsupportedMessage}"; + message += $"{CommaSeparator}{attribute.UnsupportedMessage}"; } return message; @@ -936,12 +942,12 @@ static string AppendMessageAndUrl(Versions attribute, string message) { if (attribute.ObsoletedMessage is not null) { - message += $", {attribute.ObsoletedMessage}"; + message += $"{CommaSeparator}{attribute.ObsoletedMessage}"; } if (attribute.ObsoletedUrl is not null) { - message += $", {attribute.ObsoletedUrl}"; + message += $" {attribute.ObsoletedUrl}"; } return message; @@ -1035,10 +1041,7 @@ static bool GetPlatformNames(SmallDictionary attributes, Small } } - if (pAttribute.ObsoletedIn != null) - { - obsoletedBuilder.Add(AppendMessageAndUrl(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndLater, pName, pAttribute.ObsoletedIn))); - } + AddObsoletedIn(csAttributes, obsoletedBuilder, pName, pAttribute); } obsoletedPlatforms = obsoletedBuilder.ToImmutable(); @@ -1047,6 +1050,28 @@ static bool GetPlatformNames(SmallDictionary attributes, Small } } + static void AddObsoletedIn(SmallDictionary? csAttributes, ArrayBuilder obsoletedBuilder, string pName, Versions pAttribute) + { + if (pAttribute.ObsoletedIn != null) + { + if (IsEmptyVersion(pAttribute.ObsoletedIn)) // Do not need to add the version part if it is 0.0 + { + if (csAttributes != null && HasVersionedCallsite(csAttributes, pName)) + { + obsoletedBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityAllVersions, pName))); + } + else + { + obsoletedBuilder.Add(AppendMessage(pAttribute, EncloseWithQuotes(pName))); + } + } + else + { + obsoletedBuilder.Add(AppendMessageAndUrl(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndLater, pName, pAttribute.ObsoletedIn))); + } + } + } + static ImmutableArray GetCallsitePlatforms(SmallDictionary attributes, SmallDictionary? callsiteAttributes, out Callsite callsite, bool supported) { @@ -1166,18 +1191,6 @@ static bool HasSameVersionedPlatformSupport(SmallDictionary at { version = supportedVersion.IsGreaterThanOrEqualTo(version) ? supportedVersion : version; } - else - { - var unsupportedVersion = attribute.UnsupportedSecond ?? attribute.UnsupportedFirst; - if (unsupportedVersion != null) - { - version = unsupportedVersion.IsGreaterThanOrEqualTo(version) ? unsupportedVersion : version; - } - else - { - version = supportedVersion; - } - } } if (version != null && !IsEmptyVersion(version)) { @@ -1186,6 +1199,25 @@ static bool HasSameVersionedPlatformSupport(SmallDictionary at } return false; } + + static bool HasVersionedCallsite(SmallDictionary csAttributes, string pName) + { + if (csAttributes.TryGetValue(pName, out var attribute)) + { + var version = attribute.ObsoletedIn; + var supportedVersion = attribute.SupportedSecond ?? attribute.SupportedFirst; + if (supportedVersion != null) + { + version = supportedVersion.IsGreaterThanOrEqualTo(version) ? supportedVersion : version; + } + + if (version != null && !IsEmptyVersion(version)) + { + return true; + } + } + return false; + } } private enum Callsite @@ -1562,7 +1594,8 @@ private static bool IsNotSuppressedByCallSite(SmallDictionary } } else if (msBuildPlatforms.Contains(platformName, StringComparer.OrdinalIgnoreCase) && - callSiteAttribute.UnsupportedFirst != null && callSiteAttribute.UnsupportedFirst > attribute.ObsoletedIn) + (callSiteAttribute.UnsupportedFirst != null && callSiteAttribute.UnsupportedFirst > attribute.ObsoletedIn || + callSiteAttribute.ObsoletedIn != null && callSiteAttribute.ObsoletedIn > attribute.ObsoletedIn)) { diagnosticAttribute.ObsoletedIn = (Version)attribute.ObsoletedIn.Clone(); diagnosticAttribute.ObsoletedMessage = attribute.ObsoletedMessage; diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index c2d117b527..24ecae5c6c 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -1950,8 +1950,10 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf index f4ac63acb1..a2b7439420 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf index 3525928809..72ef6007df 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf index bd1ec023a4..9e88c7fd18 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf index d3df8e0356..5cdae3e22c 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf index 28865bc998..4515fa9d87 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf index 4bddbaac05..9277e9cd63 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf index 57e2547320..3559dc8a84 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf index 251ffd1551..bd52a34689 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf index adc382392f..8f0977c64b 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf index 4fed9068f2..edffc19200 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf index ab6e299fd9..3f209d1967 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf index efebae4af1..196b6bf3d7 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf index 0a4f43d653..5af6dbe440 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf @@ -1855,12 +1855,12 @@ This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. This call site is reachable on all platforms. '{0}' is obsoleted on: {1}. - + This call site is reachable on all platforms. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. - + This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. This call site is reachable on all platforms. '{0}' is only supported on: {1}. diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs index 094782dc0e..72027a1b5a 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs @@ -14,7 +14,7 @@ namespace Microsoft.NetCore.Analyzers.InteropServices.UnitTests public partial class PlatformCompatabilityAnalyzerTests { [Fact] - public async Task ObsoletedMethodsCalledWarnsAsync() + public async Task ObsoletedMethodsCalledWarns() { var csSource = @" using System; @@ -70,7 +70,7 @@ await VerifyAnalyzerVBAsync(vbSource, VerifyVB.Diagnostic(PlatformCompatibilityA } [Fact] - public async Task ObsoletedWithMessageUrlCalledWarnsAsync() + public async Task ObsoletedWithMessageUrlCalledWarns() { var csSource = @" using System; @@ -85,36 +85,84 @@ public void CrossPlatform() {|#1:ObsoletedWithMessage()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead. ObsoletedOnAndroid(); // Cross platform and android not int he MSBuild list so not warn } + + [ObsoletedInOSPlatform(""android21.0"")] + public void ObsoletedOnAndroid() { } - [SupportedOSPlatform(""Android"")] - public void ReachableOnAndroidAndWindows() + [ObsoletedInOSPlatform(""Windows10.1.1.1"", ""Use other method instead"", Url = ""http://www/look.for.more.info"")] + public void ObsoletedWithMessageAndUrl() { } + [ObsoletedInOSPlatform(""Windows10.1.1.1"", ""Use other method instead"")] + public void ObsoletedWithMessage() { } +}" + MockObsoletedAttributeCS; + await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms, VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsAllPlatforms).WithLocation(0). + WithArguments("Test.ObsoletedWithMessageAndUrl()", "'Windows' 10.1.1.1 and later, Use other method instead http://www/look.for.more.info"), + VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsAllPlatforms).WithLocation(1). + WithArguments("Test.ObsoletedWithMessage()", "'Windows' 10.1.1.1 and later, Use other method instead")); + } + + [Fact] + public async Task ObsoletedWithinDifferentCallsite() + { + var csSource = @" +using System; +using System.Runtime.Versioning; +using Mock; + +public class Test +{ + [SupportedOSPlatform(""IOS"")] + public void CallsiteReachableOnIOS() { - ObsoletedWithMessageAndUrl(); // Unreachable on windows, not warn + ObsoletedOnWindows(); // Unreachable on windows, not warn ObsoletedWithMessage(); - {|CA1422:ObsoletedOnAndroid()|}; // This call site is reachable on: 'Android', 'Windows'. 'Test.ObsoletedOnAndroid()' is obsoleted on: 'android' 21.0 and later. + {|CA1422:ObsoletedOnIOS14()|}; // This call site is reachable on: 'IOS', 'maccatalyst'. 'Test.ObsoletedOnIOS14()' is obsoleted on: 'ios' 14.0 and later, 'maccatalyst' 14.0 and later. } - [Mock.UnsupportedOSPlatform(""Android31.0"")] + [Mock.UnsupportedOSPlatform(""ios13.0"")] [System.Runtime.Versioning.UnsupportedOSPlatform(""Windows10.1.0"")] - public void UnreachableOnAndroidAndWindows() + public void SuppressedByCallsiteUnsupported() + { + ObsoletedOnWindows(); // Not supported on windows with matching version, not warn + ObsoletedWithMessage(); // Same as above + ObsoletedOnIOS14(); + } + + [Mock.UnsupportedOSPlatform(""ios15.0"")] + [System.Runtime.Versioning.UnsupportedOSPlatform(""Windows11.1.0"")] + public void NotSuppressedByCallsiteUnsupported() // obsoleted before unsupported version { - ObsoletedWithMessageAndUrl(); // Not supported on windows, not warn + {|CA1422:ObsoletedOnWindows()|}; // This call site is reachable on: 'Windows' 11.1.0 and before. 'Test.ObsoletedOnWindows()' is obsoleted on: 'Windows' 10.1.1.1 and later. + {|CA1422:ObsoletedWithMessage()|}; // This call site is reachable on: 'Windows' 11.1.0 and before. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead. + {|CA1422:ObsoletedOnIOS14()|}; // This call site is reachable on: 'ios' 15.0 and before, 'maccatalyst' 15.0 and before. 'Test.ObsoletedOnIOS14()' is obsoleted on: 'ios' 14.0 and later, 'maccatalyst' 14.0 and later. + } + + [ObsoletedInOSPlatform(""ios13.0"")] + [ObsoletedInOSPlatform(""Windows10.1.0"")] + public void SuppressedByCallsiteObsoleted() + { + ObsoletedOnWindows(); // All calls Obsoleted within version range, not warn ObsoletedWithMessage(); - ObsoletedOnAndroid(); // Obsoleted before unuspport, so warns + ObsoletedOnIOS14(); + } + + [ObsoletedInOSPlatform(""ios16.0"")] + [ObsoletedInOSPlatform(""Windows11.1.0"")] + public void NotSuppressedByCallsiteObsoleted() + { + {|CA1422:ObsoletedOnWindows()|}; //This call site is reachable on all platforms. 'Test.ObsoletedOnWindows()' is obsoleted on: 'Windows' 10.1.1.1 and later. + {|CA1422:ObsoletedWithMessage()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead. + {|CA1422:ObsoletedOnIOS14()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnIOS14()' is obsoleted on: 'ios' 14.0 and later, 'maccatalyst' 14.0 and later. } - [ObsoletedInOSPlatform(""android21.0"")] - public void ObsoletedOnAndroid() { } + [ObsoletedInOSPlatform(""ios14.0"")] + public void ObsoletedOnIOS14() { } - [ObsoletedInOSPlatform(""Windows10.1.1.1"", ""Use other method instead"", Url = ""http://www/look.for.more.info"")] - public void ObsoletedWithMessageAndUrl() { } + [ObsoletedInOSPlatform(""Windows10.1.1.1"")] + public void ObsoletedOnWindows() { } [ObsoletedInOSPlatform(""Windows10.1.1.1"", ""Use other method instead"")] public void ObsoletedWithMessage() { } }" + MockObsoletedAttributeCS; - await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms, VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsAllPlatforms).WithLocation(0). - WithArguments("Test.ObsoletedWithMessageAndUrl()", "'Windows' 10.1.1.1 and later, Use other method instead, http://www/look.for.more.info"), - VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsAllPlatforms).WithLocation(1). - WithArguments("Test.ObsoletedWithMessage()", "'Windows' 10.1.1.1 and later, Use other method instead")); + await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms); } [Fact] @@ -153,6 +201,112 @@ public void UnsupportedIosBrowserWatchOS() { } await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms); } + [Fact] + public async Task ObsoletedWarningsGuardedWithOperatingSystemAPIs() + { + var csSource = @" +using System; +using System.Runtime.Versioning; +using Mock; + +public class Test +{ + public void CrossPlatform() + { + if (OperatingSystem.IsMacOS()) + { + {|CA1422:ObsoletedOnMacOS()|}; // This call site is reachable on: 'macOS/OSX'. 'Test.ObsoletedOnMacOS()' is obsoleted on: 'macOS/OSX'. + ObsoletedOnAndroid21(); // Call site only reachable on MacOS, no warning + ObsoletedOnLinux4AndWindows10(); // Same, no warning + } + else + { + ObsoletedOnMacOS(); + ObsoletedOnAndroid21(); // Android is not in MSBuild support list, no warning + {|CA1422:ObsoletedOnLinux4AndWindows10()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Linux' 4.1 and later, Use Linux4Supported, 'Windows' 10.1.1.1 and later, Use Windows10Supported. + } + + if (OperatingSystem.IsMacOSVersionAtLeast(11)) + { + {|CA1422:ObsoletedOnMacOS()|}; // This call site is reachable on: 'macOS/OSX' 11.0 and later. 'Test.ObsoletedOnMacOS()' is obsoleted on: 'macOS/OSX' all versions. + } + else + { + {|CA1422:ObsoletedOnMacOS()|}; // It could be macos with less version, so warns: This call site is reachable on all platforms. 'Test.ObsoletedOnMacOS()' is obsoleted on: 'macOS/OSX'. + } + } + + [ObsoletedInOSPlatform(""Android21.0"")] + public void ObsoletedOnAndroid21() { } + + [ObsoletedInOSPlatform(""MacOS"")] + public void ObsoletedOnMacOS() { } + + [ObsoletedInOSPlatform(""Linux4.1"", ""Use Linux4Supported"")] + [ObsoletedInOSPlatform(""Windows10.1.1.1"",""Use Windows10Supported"")] + public void ObsoletedOnLinux4AndWindows10() { } +}" + MockObsoletedAttributeCS; + await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms); + } + + [Fact] + public async Task ObsoletedWarningsGuardedWithOperatingSystemAPIsDifferentCallsite() + { + var csSource = @" +using System; +using System.Runtime.Versioning; +using Mock; + +public class Test +{ + [SupportedOSPlatform(""Android"")] + public void AndroidOnly() + { + if (OperatingSystem.IsMacOS()) + { + ObsoletedOnMacOS(); // The method is not reachable on MacOS, so no warning + ObsoletedOnAndroid21(); // Conditional only reachable on MacOS, no warning + ObsoletedOnLinux4AndWindows10(); + } + else + { + ObsoletedOnMacOS(); // Method only for android, no warning + {|CA1422:ObsoletedOnAndroid21()|}; // This call site is reachable on: 'Android'. 'Test.ObsoletedOnAndroid21()' is obsoleted on: 'Android' 21.0 and later. + ObsoletedOnLinux4AndWindows10(); // Method only for android + } + } + + [SupportedOSPlatform(""Android"")] + [SupportedOSPlatform(""MacOS"")] + public void AndroidMacOSOnly() + { + if (OperatingSystem.IsMacOS()) + { + {|CA1422:ObsoletedOnMacOS()|}; // This call site is reachable on: 'Android', 'macOS/OSX'. 'Test.ObsoletedOnMacOS()' is obsoleted on: 'macOS/OSX'. + ObsoletedOnAndroid21(); + ObsoletedOnLinux4AndWindows10(); + } + else + { + ObsoletedOnMacOS(); + {|CA1422:ObsoletedOnAndroid21()|}; // This call site is reachable on: 'Android', 'macOS/OSX'. 'Test.ObsoletedOnAndroid21()' is obsoleted on: 'Android' 21.0 and later. + ObsoletedOnLinux4AndWindows10(); + } + } + + [ObsoletedInOSPlatform(""Android21.0"")] + public void ObsoletedOnAndroid21() { } + + [ObsoletedInOSPlatform(""MacOS"")] + public void ObsoletedOnMacOS() { } + + [ObsoletedInOSPlatform(""Linux4.1"", ""Use Linux4Supported"")] + [ObsoletedInOSPlatform(""Windows10.1.1.1"",""Use Windows10Supported"")] + public void ObsoletedOnLinux4AndWindows10() { } +}" + MockObsoletedAttributeCS; + await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms); + } + private readonly string MockObsoletedAttributeCS = @" namespace Mock { From fb6a86d9086674284bf433c3582603022f194f9c Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Fri, 22 Jul 2022 14:59:23 -0700 Subject: [PATCH 3/6] Add guard attribute test --- .../PlatformCompatibilityAnalyzer.cs | 2 +- .../MicrosoftNetCoreAnalyzersResources.resx | 2 +- .../MicrosoftNetCoreAnalyzersResources.cs.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.de.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.es.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.fr.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.it.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.ja.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.ko.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.pl.xlf | 2 +- ...crosoftNetCoreAnalyzersResources.pt-BR.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.ru.xlf | 2 +- .../MicrosoftNetCoreAnalyzersResources.tr.xlf | 2 +- ...osoftNetCoreAnalyzersResources.zh-Hans.xlf | 2 +- ...osoftNetCoreAnalyzersResources.zh-Hant.xlf | 2 +- ...lityAnalyzer.ObsoletedInOSPlatformTests.cs | 65 +++++++++++++++++-- 16 files changed, 76 insertions(+), 19 deletions(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs index 8ab1a4a632..b51058b9dd 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs @@ -831,7 +831,7 @@ static bool GetSupportedPlatforms(SmallDictionary attributes, { using var obsoletedBuilder = ArrayBuilder.GetInstance(); bool? supportedRule = null; - var platformsBuilder = ArrayBuilder.GetInstance(); + using var platformsBuilder = ArrayBuilder.GetInstance(); foreach (var (pName, pAttribute) in attributes) { if (pAttribute.SupportedFirst != null && supportedRule.GetValueOrDefault(true)) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index 24ecae5c6c..0f91466afe 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -1485,7 +1485,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' String parameters passed by value with the 'OutAttribute' can destabilize the runtime if the string is an interned string. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf index a2b7439420..34b3242234 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf index 72ef6007df..cfce8ad0bb 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf index 9e88c7fd18..3b88decb13 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf index 5cdae3e22c..74f7bbd7f9 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf index 4515fa9d87..fbb23bcf1f 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf index 9277e9cd63..151937e37a 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf index 3559dc8a84..fc29c19491 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf index bd52a34689..36d2d31f4a 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf index 8f0977c64b..37336f3e62 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf index edffc19200..78796d070d 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf index 3f209d1967..5df359f2f9 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf index 196b6bf3d7..10d8277e28 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf index 5af6dbe440..144e708b25 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf @@ -1895,7 +1895,7 @@ This call site is reachable on all platforms. '{0}' is unsupported on: {1}. This call site is reachable on all platforms. '{0}' is unsupported on: {1}. - This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows'. + This call site is reachable on all platforms. 'UnsupportedOnWindows()' is unsupported on: 'windows' This call site is reachable on: {2}. '{0}' is unsupported on: {1}. diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs index 72027a1b5a..01f3fe9164 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs @@ -83,7 +83,7 @@ public void CrossPlatform() { {|#0:ObsoletedWithMessageAndUrl()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessageAndUrl()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead, http://www/look.for.more.info. {|#1:ObsoletedWithMessage()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead. - ObsoletedOnAndroid(); // Cross platform and android not int he MSBuild list so not warn + ObsoletedOnAndroid(); // Cross platform and android not in the MSBuild list so not warn } [ObsoletedInOSPlatform(""android21.0"")] @@ -101,7 +101,7 @@ await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms, VerifyCS.Diagnostic(Pl } [Fact] - public async Task ObsoletedWithinDifferentCallsite() + public async Task ObsoletedAPIsCAlledFromDifferentCallsite() { var csSource = @" using System; @@ -179,7 +179,7 @@ public void CrossPlatform() { [|UnsupportedIosBrowserWatchOS()|]; // This call site is reachable on all platforms. 'Test.UnsupportedIosBrowserWatchOS()' is unsupported on: 'Browser'. Use BrowserSupported() method instead, // 'ios' 13.0 and later. Use Test.IOsSupported() method instead, 'maccatalyst' 13.0 and later. Use Test.IOsSupported() method instead. - UnsupportedAndroid(); // Cross platform and android not int he MSBuild list so not warn + UnsupportedAndroid(); // Cross platform and android not in the MSBuild list so not warn } [SupportedOSPlatform(""Android"")] @@ -250,7 +250,7 @@ public void ObsoletedOnLinux4AndWindows10() { } } [Fact] - public async Task ObsoletedWarningsGuardedWithOperatingSystemAPIsDifferentCallsite() + public async Task ObsoletedWarningsGuardedWithOperatingSystemAPIsFromDifferentCallsite() { var csSource = @" using System; @@ -307,6 +307,63 @@ public void ObsoletedOnLinux4AndWindows10() { } await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms); } + [Fact] + public async Task ObsoletedWarningsGuardedWithUnsupportedOSPlatformGuardAttribute() + { + var csSource = @" +using System; +using System.Runtime.Versioning; +using Mock; + +public class Test +{ + [UnsupportedOSPlatformGuard(""MacOS"")] + private readonly bool _macOSNotSupported; + + [SupportedOSPlatformGuard(""Windows11.0"")] + public bool IsWindows11Supported { get; } + + [UnsupportedOSPlatformGuard(""linux"")] + [UnsupportedOSPlatformGuard(""Windows10.0"")] + private bool IsLinuxWindows10NotSupported() => true; + + public void CrossPlatform() + { + if (_macOSNotSupported) + { + ObsoletedOnMacOS(); // Guarded with the attributed field + ObsoletedOnMacOS15(); + {|CA1422:ObsoletedOnLinuxAndWindows10()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Linux', 'Windows' 10.1.1.1 and later, Use Windows10Supported. + } + + if (IsWindows11Supported) + { + ObsoletedOnMacOS(); // reachable on 'Windows' 11.0 and later only + ObsoletedOnMacOS15(); + {|CA1422:ObsoletedOnLinuxAndWindows10()|}; // This call site is reachable on: 'Windows' 11.0 and later. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use Windows10Supported. + } + + if (IsLinuxWindows10NotSupported()) + { + {|CA1422:ObsoletedOnMacOS()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnMacOS()' is obsoleted on: 'macOS/OSX'. + {|CA1422:ObsoletedOnMacOS15()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnMacOS15()' is obsoleted on: 'macOS/OSX' 15.0 and later. + ObsoletedOnLinuxAndWindows10(); // Guarded with the attirubted API + } + } + + [ObsoletedInOSPlatform(""MacOS15.0"")] + public void ObsoletedOnMacOS15() { } + + [ObsoletedInOSPlatform(""MacOS"")] + public void ObsoletedOnMacOS() { } + + [ObsoletedInOSPlatform(""Linux"", ""Use LinuxSupported"")] + [ObsoletedInOSPlatform(""Windows10.1.1.1"",""Use Windows10Supported"")] + public void ObsoletedOnLinuxAndWindows10() { } +}" + MockObsoletedAttributeCS; + await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms); + } + private readonly string MockObsoletedAttributeCS = @" namespace Mock { From 18f5a444bac98eec105e90d0376e8cacb0297756 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Fri, 22 Jul 2022 16:49:09 -0700 Subject: [PATCH 4/6] Add generated files --- .../Microsoft.CodeAnalysis.NetAnalyzers.md | 12 +++++++++++ .../Microsoft.CodeAnalysis.NetAnalyzers.sarif | 20 +++++++++++++++++++ src/NetAnalyzers/RulesMissingDocumentation.md | 1 + 3 files changed, 33 insertions(+) diff --git a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md index 308d72dcec..76c3b85978 100644 --- a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md +++ b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.md @@ -768,6 +768,18 @@ This method uses runtime marshalling even when runtime marshalling is disabled, |CodeFix|True| --- +## [CA1422](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1422): Validate platform compatibility + +Using platform dependent API on a component makes the code no longer work across all platforms. + +|Item|Value| +|-|-| +|Category|Interoperability| +|Enabled|True| +|Severity|Warning| +|CodeFix|False| +--- + ## [CA1501](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1501): Avoid excessive inheritance Deeply nested type hierarchies can be difficult to follow, understand, and maintain. This rule limits analysis to hierarchies in the same module. To fix a violation of this rule, derive the type from a base type that is less deep in the inheritance hierarchy or eliminate some of the intermediate base types. diff --git a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif index cec4eac782..e66380c020 100644 --- a/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif +++ b/src/NetAnalyzers/Microsoft.CodeAnalysis.NetAnalyzers.sarif @@ -1710,6 +1710,26 @@ ] } }, + "CA1422": { + "id": "CA1422", + "shortDescription": "Validate platform compatibility", + "fullDescription": "Using platform dependent API on a component makes the code no longer work across all platforms.", + "defaultLevel": "warning", + "helpUri": "https://docs.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1422", + "properties": { + "category": "Interoperability", + "isEnabledByDefault": true, + "typeName": "PlatformCompatibilityAnalyzer", + "languages": [ + "C#", + "Visual Basic" + ], + "tags": [ + "Telemetry", + "EnabledRuleInAggressiveMode" + ] + } + }, "CA1501": { "id": "CA1501", "shortDescription": "Avoid excessive inheritance", diff --git a/src/NetAnalyzers/RulesMissingDocumentation.md b/src/NetAnalyzers/RulesMissingDocumentation.md index c882b1714b..1096512739 100644 --- a/src/NetAnalyzers/RulesMissingDocumentation.md +++ b/src/NetAnalyzers/RulesMissingDocumentation.md @@ -5,6 +5,7 @@ Rule ID | Missing Help Link | Title | CA1311 | | Specify a culture or use an invariant version | CA1420 | | Property, type, or attribute requires runtime marshalling | CA1421 | | This method uses runtime marshalling even when the 'DisableRuntimeMarshallingAttribute' is applied | +CA1422 | | Validate platform compatibility | CA1852 | | Seal internal types | CA1853 | | Unnecessary call to 'Dictionary.ContainsKey(key)' | CA2019 | | Improper 'ThreadStatic' field initialization | From 45fe345150516186c9d35d6de9a656bcbe04ad5a Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Mon, 1 Aug 2022 08:58:14 -0700 Subject: [PATCH 5/6] Apply feedback --- .../PlatformCompatibilityAnalyzer.cs | 60 +++++++-- .../MicrosoftNetCoreAnalyzersResources.resx | 3 + .../MicrosoftNetCoreAnalyzersResources.cs.xlf | 5 + .../MicrosoftNetCoreAnalyzersResources.de.xlf | 5 + .../MicrosoftNetCoreAnalyzersResources.es.xlf | 5 + .../MicrosoftNetCoreAnalyzersResources.fr.xlf | 5 + .../MicrosoftNetCoreAnalyzersResources.it.xlf | 5 + .../MicrosoftNetCoreAnalyzersResources.ja.xlf | 5 + .../MicrosoftNetCoreAnalyzersResources.ko.xlf | 5 + .../MicrosoftNetCoreAnalyzersResources.pl.xlf | 5 + ...crosoftNetCoreAnalyzersResources.pt-BR.xlf | 5 + .../MicrosoftNetCoreAnalyzersResources.ru.xlf | 5 + .../MicrosoftNetCoreAnalyzersResources.tr.xlf | 5 + ...osoftNetCoreAnalyzersResources.zh-Hans.xlf | 5 + ...osoftNetCoreAnalyzersResources.zh-Hant.xlf | 5 + ...lityAnalyzer.ObsoletedInOSPlatformTests.cs | 118 +++++++++++++++--- 16 files changed, 219 insertions(+), 27 deletions(-) diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs index b51058b9dd..0f35ce425d 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.cs @@ -502,6 +502,7 @@ static bool IsKnownValueGuarded( attribute.UnsupportedSecond = null; } attribute.UnsupportedFirst = null; + attribute.UnsupportedMessage = null; } else { @@ -513,6 +514,7 @@ static bool IsKnownValueGuarded( attribute.SupportedSecond = null; attribute.UnsupportedSecond = null; attribute.UnsupportedFirst = null; + attribute.UnsupportedMessage = null; } else if (value.AnalysisValues.Contains(new PlatformMethodValue(info.PlatformName, EmptyVersion, false))) { @@ -530,6 +532,8 @@ static bool IsKnownValueGuarded( attribute.ObsoletedIn.IsGreaterThanOrEqualTo(info.Version)) { attribute.ObsoletedIn = null; + attribute.ObsoletedMessage = null; + attribute.ObsoletedUrl = null; } if (!IsEmptyVersion(info.Version)) @@ -546,6 +550,7 @@ static bool IsKnownValueGuarded( attribute.UnsupportedFirst.IsGreaterThanOrEqualTo(version)) { attribute.UnsupportedFirst = null; + attribute.UnsupportedMessage = null; } if (attribute.UnsupportedSecond != null && @@ -553,6 +558,7 @@ static bool IsKnownValueGuarded( version.IsGreaterThanOrEqualTo(attribute.UnsupportedSecond)) { attribute.UnsupportedSecond = null; + attribute.UnsupportedMessage = null; } } @@ -744,8 +750,11 @@ static void RemoveUnsupportsOnDifferentPlatforms(SmallDictionary attributes, Small platformsBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityFromVersionToVersion, pName, unsupportedVersion, supportedVersion))); } - continue; } - platformsBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndLater, pName, supportedVersion))); + else + { + platformsBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityVersionAndLater, pName, supportedVersion))); + } } else { @@ -1018,9 +1033,11 @@ static bool GetPlatformNames(SmallDictionary attributes, Small if (csAttributes != null && HasSameVersionedPlatformSupport(csAttributes, pName, checkSupport: true)) { platformsBuilder.Add(AppendMessage(pAttribute, GetFormattedString(PlatformCompatibilityAllVersions, pName))); - continue; } - platformsBuilder.Add(AppendMessage(pAttribute, EncloseWithQuotes(pName))); + else + { + platformsBuilder.Add(AppendMessage(pAttribute, EncloseWithQuotes(pName))); + } } else { @@ -1578,7 +1595,7 @@ private static bool IsNotSuppressedByCallSite(SmallDictionary } } - // Check if obsoleted attribute suppressed + // Check if obsoleted attribute guarded by callsite attributes if (attribute.ObsoletedIn != null) { if (callSiteAttributes.TryGetValue(platformName, out var callSiteAttribute)) @@ -1811,6 +1828,17 @@ static void MergePlatformAttributes(ImmutableArray immediateAttri existing.SupportedFirst = childAttribute.SupportedFirst; } } + + if (childAttribute.ObsoletedIn != null && + (childAttribute.ObsoletedIn < existing.UnsupportedFirst || + existing.SupportedFirst != null && + (existing.UnsupportedSecond == null || existing.UnsupportedSecond > childAttribute.ObsoletedIn)) && + (existing.ObsoletedIn == null || childAttribute.ObsoletedIn < existing.ObsoletedIn)) + { + existing.ObsoletedIn = childAttribute.ObsoletedIn; + existing.ObsoletedMessage = childAttribute.ObsoletedMessage; + existing.ObsoletedUrl = childAttribute.ObsoletedMessage; + } } else { @@ -1840,10 +1868,12 @@ static void MergePlatformAttributes(ImmutableArray immediateAttri parentAttributes.Callsite = Callsite.Empty; attributes.SupportedFirst = childAttribute.SupportedFirst > attributes.SupportedFirst ? childAttribute.SupportedFirst : null; attributes.UnsupportedFirst = childAttribute.UnsupportedFirst; + attributes.UnsupportedMessage = childAttribute.UnsupportedMessage; } else if (attributes.UnsupportedFirst == null || attributes.UnsupportedFirst > childAttribute.UnsupportedFirst) { attributes.UnsupportedFirst = childAttribute.UnsupportedFirst; + attributes.UnsupportedMessage = childAttribute.UnsupportedMessage; } if (attributes.SupportedSecond.IsGreaterThanOrEqualTo(childAttribute.UnsupportedFirst)) @@ -1853,6 +1883,7 @@ static void MergePlatformAttributes(ImmutableArray immediateAttri if (childAttribute.UnsupportedSecond != null && childAttribute.UnsupportedSecond > attributes.UnsupportedFirst) { attributes.UnsupportedFirst = childAttribute.UnsupportedSecond; + attributes.UnsupportedMessage = childAttribute.UnsupportedMessage; } } } @@ -1862,12 +1893,15 @@ static void MergePlatformAttributes(ImmutableArray immediateAttri notFoundPlatforms.Add(platform); } } + // Check for Obsoleted attributes, only lower version could overwrite - if (attributes.ObsoletedIn != null && - childAttributes.TryGetValue(platform, out var childAttr) && - childAttr.ObsoletedIn != null && childAttr.ObsoletedIn < attributes.ObsoletedIn) + if (childAttributes.TryGetValue(platform, out var childAttr) && + childAttr.ObsoletedIn != null && + (attributes.ObsoletedIn == null || childAttr.ObsoletedIn < attributes.ObsoletedIn)) { attributes.ObsoletedIn = childAttr.ObsoletedIn; + attributes.ObsoletedMessage = childAttr.ObsoletedMessage; + attributes.ObsoletedUrl = childAttr.ObsoletedUrl; } } diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx index 0f91466afe..9fd249e48a 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx @@ -1956,4 +1956,7 @@ This call site is reachable on: {2}. '{0}' is obsoleted on: {1}. This call site is reachable on 'macos', 'linux'. 'OboletedOnMacOS()' is obsoleted on: 'macos'. + + ({0}) + \ No newline at end of file diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf index 34b3242234..041cd83a1a 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.cs.xlf @@ -1832,6 +1832,11 @@ Metody P/Invoke nemají být viditelné + + ({0}) + ({0}) + + and all other platforms a všechny ostatní platformy diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf index cfce8ad0bb..69ed32acd8 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.de.xlf @@ -1832,6 +1832,11 @@ P/Invokes dürfen nicht sichtbar sein + + ({0}) + ({0}) + + and all other platforms und alle anderen Plattformen diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf index 3b88decb13..d087e2a755 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.es.xlf @@ -1832,6 +1832,11 @@ Los elementos P/Invoke no deben estar visibles + + ({0}) + ({0}) + + and all other platforms y el resto de plataformas diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf index 74f7bbd7f9..3a20f66f0c 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.fr.xlf @@ -1832,6 +1832,11 @@ Les P/Invoke ne doivent pas être visibles + + ({0}) + ({0}) + + and all other platforms et toutes les autres plateformes diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf index fbb23bcf1f..0283857596 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.it.xlf @@ -1832,6 +1832,11 @@ I metodi P/Invoke non devono essere visibili + + ({0}) + ({0}) + + and all other platforms e tutte le altre piattaforme diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf index 151937e37a..5270c1f896 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ja.xlf @@ -1832,6 +1832,11 @@ P/Invokes は参照可能にすることはできません + + ({0}) + ({0}) + + and all other platforms およびその他すべてのプラットフォーム diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf index fc29c19491..45035073ea 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ko.xlf @@ -1832,6 +1832,11 @@ P/Invokes를 표시하지 않아야 합니다. + + ({0}) + ({0}) + + and all other platforms 및 다른 모든 플랫폼 diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf index 36d2d31f4a..b74a8655d8 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pl.xlf @@ -1832,6 +1832,11 @@ Elementy P/Invoke nie powinny być widoczne + + ({0}) + ({0}) + + and all other platforms i wszystkie inne platformy diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf index 37336f3e62..c799b15293 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.pt-BR.xlf @@ -1832,6 +1832,11 @@ P/Invokes não deve ser visível + + ({0}) + ({0}) + + and all other platforms e todas as outras plataformas diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf index 78796d070d..9bd1ca7323 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.ru.xlf @@ -1832,6 +1832,11 @@ Методы P/Invoke не должны быть видимыми + + ({0}) + ({0}) + + and all other platforms и на всех остальных платформах diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf index 5df359f2f9..b9ce1103d6 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.tr.xlf @@ -1832,6 +1832,11 @@ P/Invokes görünür olmamalıdır + + ({0}) + ({0}) + + and all other platforms ve diğer tüm platformlar diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf index 10d8277e28..287002ea92 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hans.xlf @@ -1832,6 +1832,11 @@ P/Invokes 应该是不可见的 + + ({0}) + ({0}) + + and all other platforms 和其他所有平台 diff --git a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf index 144e708b25..f9f174d063 100644 --- a/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf +++ b/src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/xlf/MicrosoftNetCoreAnalyzersResources.zh-Hant.xlf @@ -1832,6 +1832,11 @@ 不應看得見 P/Invoke + + ({0}) + ({0}) + + and all other platforms 及所有其他平台 diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs index 01f3fe9164..3524147989 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs @@ -26,7 +26,7 @@ public class Test [SupportedOSPlatform(""Linux"")] public void M1() { - ObsoletedOnWindows10(); // Shold not warn as only accessible on Linux + ObsoletedOnWindows10(); // Should not warn as only accessible on Linux {|#0:ObsoletedOnLinux4()|}; // This call site is reachable on: 'Linux'. 'Test.ObsoletedOnLinux()' is obsoleted on: 'Linux' 4.1 and later. {|CA1422:ObsoletedOnLinux4AndWindows10()|}; // This call site is reachable on: 'Linux'. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Linux' 4.1 and later. } @@ -70,7 +70,7 @@ await VerifyAnalyzerVBAsync(vbSource, VerifyVB.Diagnostic(PlatformCompatibilityA } [Fact] - public async Task ObsoletedWithMessageUrlCalledWarns() + public async Task ObsoletedAndSupportedMixedDiagnostics() { var csSource = @" using System; @@ -81,23 +81,113 @@ public class Test { public void CrossPlatform() { - {|#0:ObsoletedWithMessageAndUrl()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessageAndUrl()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead, http://www/look.for.more.info. - {|#1:ObsoletedWithMessage()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead. - ObsoletedOnAndroid(); // Cross platform and android not in the MSBuild list so not warn + {|CA1416:{|CA1422:Supported8Obsoleted10Unsupported11()|}|}; // This call site is reachable on all platforms. 'Test.Supported8Obsoleted10Unsupported11()' is only supported on: 'Windows' from version 8.0 to 11.0. + // This call site is reachable on all platforms. 'Test.Supported8Obsoleted10Unsupported11()' is obsoleted on: 'Windows' 10.0 and later. + {|CA1416:{|CA1422:Supported10.Obsoleted11Unsupported12()|}|}; // This call site is reachable on all platforms. 'Supported10.Obsoleted11Unsupported12()' is only supported on: 'Windows' from version 10.0 to 12.0. + // This call site is reachable on all platforms. 'Supported10.Obsoleted11Unsupported12()' is obsoleted on: 'Windows' 11.0 and later. + {|CA1416:{|CA1422:Supported10.Obsoleted11()|}|}; // This call site is reachable on all platforms. 'Supported10.Obsoleted11()' is only supported on: 'Windows' 10.0 and later. + // This call site is reachable on all platforms. 'Supported10.Obsoleted11()' is obsoleted on: 'Windows' 11.0 and later. + {|CA1416:{|CA1422:Supported10.Unsupported11Obsoleted12()|}|}; // This call site is reachable on all platforms. 'Supported10.Unsupported11Obsoleted12()' is only supported on: 'Windows' from version 10.0 to 11.0. + // This call site is reachable on all platforms. 'Supported10.Unsupported11Obsoleted12()' is obsoleted on: 'Windows' 12.0 and later. + {|CA1416:{|CA1422:Unsupported.Obsoleted1Windows10Linux()|}|}; // This call site is reachable on all platforms. 'Unsupported.Obsoleted1Windows10Linux()' is unsupported on: 'Windows'. + // This call site is reachable on all platforms. 'Unsupported.Obsoleted1Windows10Linux()' is obsoleted on: 'Linux'. + {|CA1416:{|CA1422:UnsupportedSupported8.Obsoleted10()|}|}; // This call site is reachable on all platforms. 'UnsupportedSupported8.Obsoleted10()' is unsupported on: 'Windows' 8.0 and before + // This call site is reachable on all platforms. 'UnsupportedSupported8.Obsoleted10()' is obsoleted on: 'Windows' 10.0 and later. + {|CA1416:{|CA1422:UnsupportedSupported8.Obsoleted10Unspported11()|}|}; // This call site is reachable on all platforms. 'UnsupportedSupported8.Obsoleted10Unspported11()' is unsupported on: 'Windows' 8.0 and before. + // This call site is reachable on all platforms. 'UnsupportedSupported8.Obsoleted10Unspported11()' is obsoleted on: 'Windows' 10.0 and later. + {|CA1416:{|CA1422:UnsupportedSupported8.ObsoletedWindows10Linux()|}|}; // This call site is reachable on all platforms. 'UnsupportedSupported8.ObsoletedWindows10Linux()' is unsupported on: 'Windows' 8.0 and before. + // This call site is reachable on all platforms. 'UnsupportedSupported8.ObsoletedWindows10Linux()' is obsoleted on: 'Linux', 'Windows' 10.0 and later. } - [ObsoletedInOSPlatform(""android21.0"")] - public void ObsoletedOnAndroid() { } + [SupportedOSPlatform(""Windows"")] + public void WindowsOnly() + { + {|CA1416:{|CA1422:Supported8Obsoleted10Unsupported11()|}|}; // This call site is reachable on: 'Windows' all versions. 'Test.Supported8Obsoleted10Unsupported11()' is only supported on: 'Windows' from version 8.0 to 11.0. + // This call site is reachable on: 'Windows' all versions. 'Test.Supported8Obsoleted10Unsupported11()' is obsoleted on: 'Windows' 10.0 and later. + {|CA1416:{|CA1422:Supported10.Obsoleted11Unsupported12()|}|}; // This call site is reachable on: 'Windows' all versions. 'Supported10.Obsoleted11Unsupported12()' is only supported on: 'Windows' from version 10.0 to 12.0. + // This call site is reachable on: 'Windows' all versions. 'Supported10.Obsoleted11Unsupported12()' is obsoleted on: 'Windows' 11.0 and later. + {|CA1416:{|CA1422:Supported10.Obsoleted11()|}|}; // This call site is reachable on: 'Windows' all versions. 'Supported10.Obsoleted11()' is only supported on: 'Windows' 10.0 and later + // This call site is reachable on: 'Windows' all versions. 'Supported10.Obsoleted11()' is obsoleted on: 'Windows' 11.0 and later. + {|CA1416:{|CA1422:Supported10.Unsupported11Obsoleted12()|}|}; // This call site is reachable on: 'Windows' all versions. 'Supported10.Unsupported11Obsoleted12()' is only supported on: 'Windows' from version 10.0 to 11.0. + // This call site is reachable on: 'Windows' all versions. 'Supported10.Unsupported11Obsoleted12()' is obsoleted on: 'Windows' 12.0 and later. + } + + [SupportedOSPlatform(""Windows8.0"")] + [ObsoletedInOSPlatform(""Windows10.0"")] + [Mock.UnsupportedOSPlatform(""Windows11.0"")] + public void Supported8Obsoleted10Unsupported11() { } +} + +[SupportedOSPlatform(""Windows10.0"")] +public class Supported10 +{ + [ObsoletedInOSPlatform(""Windows11.0"")] + [Mock.UnsupportedOSPlatform(""Windows12.0"")] + public static void Obsoleted11Unsupported12() { } + + [ObsoletedInOSPlatform(""Windows11.0"")] + public static void Obsoleted11() { } + + [ObsoletedInOSPlatform(""Windows12.0"")] + [Mock.UnsupportedOSPlatform(""Windows11.0"")] + public static void Unsupported11Obsoleted12() { } +} +[Mock.UnsupportedOSPlatform(""Windows"")] +[SupportedOSPlatform(""Windows8.0"")] +public class UnsupportedSupported8 +{ + [Mock.ObsoletedInOSPlatform(""Windows10.0"")] + public static void Obsoleted10() { } + + [Mock.ObsoletedInOSPlatform(""Linux"")] + [Mock.ObsoletedInOSPlatform(""Windows10.0"")] + public static void ObsoletedWindows10Linux() { } + + [Mock.ObsoletedInOSPlatform(""Windows10.0"")] + [Mock.UnsupportedOSPlatform(""Windows11.0"")] + public static void Obsoleted10Unspported11() { } +} +[Mock.UnsupportedOSPlatform(""Windows"")] +public class Unsupported +{ + [Mock.ObsoletedInOSPlatform(""Linux"")] + [Mock.ObsoletedInOSPlatform(""Windows10.0"")] + public static void Obsoleted1Windows10Linux() { } +} +" + MockObsoletedAttributeCS; + await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms); + } + + [Fact] + public async Task ObsoletedWithMessageUrlCalledWarns() + { + var csSource = @" +using System; +using System.Runtime.Versioning; +using Mock; +public class Test +{ + public void CrossPlatform() + { + {|#0:ObsoletedWithMessageAndUrl()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessageAndUrl()' is obsoleted on: 'Windows' 10.1.1.1 and later (Use other method instead http://www/look.for.more.info). + {|#1:ObsoletedWithMessage()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later (Use other method instead). + {|#2:ObsoletedWithUrl()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithUrl()' is obsoleted on: 'Windows' 10.1.1.1 and later (http://www/look.for.more.info). + } + + [ObsoletedInOSPlatform(""Windows10.1.1.1"", Url = ""http://www/look.for.more.info"")] + public void ObsoletedWithUrl() { } [ObsoletedInOSPlatform(""Windows10.1.1.1"", ""Use other method instead"", Url = ""http://www/look.for.more.info"")] public void ObsoletedWithMessageAndUrl() { } [ObsoletedInOSPlatform(""Windows10.1.1.1"", ""Use other method instead"")] public void ObsoletedWithMessage() { } }" + MockObsoletedAttributeCS; await VerifyAnalyzerCSAsync(csSource, s_msBuildPlatforms, VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsAllPlatforms).WithLocation(0). - WithArguments("Test.ObsoletedWithMessageAndUrl()", "'Windows' 10.1.1.1 and later, Use other method instead http://www/look.for.more.info"), + WithArguments("Test.ObsoletedWithMessageAndUrl()", "'Windows' 10.1.1.1 and later (Use other method instead http://www/look.for.more.info)"), VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsAllPlatforms).WithLocation(1). - WithArguments("Test.ObsoletedWithMessage()", "'Windows' 10.1.1.1 and later, Use other method instead")); + WithArguments("Test.ObsoletedWithMessage()", "'Windows' 10.1.1.1 and later (Use other method instead)"), + VerifyCS.Diagnostic(PlatformCompatibilityAnalyzer.ObsoletedCsAllPlatforms).WithLocation(2). + WithArguments("Test.ObsoletedWithUrl()", "'Windows' 10.1.1.1 and later (http://www/look.for.more.info)")); } [Fact] @@ -177,8 +267,8 @@ public class Test { public void CrossPlatform() { - [|UnsupportedIosBrowserWatchOS()|]; // This call site is reachable on all platforms. 'Test.UnsupportedIosBrowserWatchOS()' is unsupported on: 'Browser'. Use BrowserSupported() method instead, - // 'ios' 13.0 and later. Use Test.IOsSupported() method instead, 'maccatalyst' 13.0 and later. Use Test.IOsSupported() method instead. + [|UnsupportedIosBrowserWatchOS()|]; // This call site is reachable on all platforms. 'Test.UnsupportedIosBrowserWatchOS()' is unsupported on: 'Browser' (Use BrowserSupported() method instead), + // 'ios' 13.0 and later (Use Test.IOsSupported() method instead), 'maccatalyst' 13.0 and later (Use Test.IOsSupported() method instead). UnsupportedAndroid(); // Cross platform and android not in the MSBuild list so not warn } @@ -186,8 +276,8 @@ public void CrossPlatform() [SupportedOSPlatform(""browser"")] public void ReachableOnAndroidAndBrowser() { - [|UnsupportedIosBrowserWatchOS()|]; // This call site is reachable on: 'Android', 'browser'. 'Test.UnsupportedIosBrowserWatchOS()' is unsupported on: 'Browser', Use BrowserSupported() method instead. - [|UnsupportedAndroid()|]; // This call site is reachable on: 'Android' all versions, 'browser'. 'Test.UnsupportedAndroid()' is unsupported on: 'Android' 21.0 and later, Use other method instead. + [|UnsupportedIosBrowserWatchOS()|]; // This call site is reachable on: 'Android', 'browser'. 'Test.UnsupportedIosBrowserWatchOS()' is unsupported on: 'Browser' (Use BrowserSupported() method instead). + [|UnsupportedAndroid()|]; // This call site is reachable on: 'Android' all versions, 'browser'. 'Test.UnsupportedAndroid()' is unsupported on: 'Android' 21.0 and later (Use other method instead). } [Mock.UnsupportedOSPlatform(""Android21.0"", ""Use other method instead"")] @@ -347,7 +437,7 @@ public void CrossPlatform() { {|CA1422:ObsoletedOnMacOS()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnMacOS()' is obsoleted on: 'macOS/OSX'. {|CA1422:ObsoletedOnMacOS15()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnMacOS15()' is obsoleted on: 'macOS/OSX' 15.0 and later. - ObsoletedOnLinuxAndWindows10(); // Guarded with the attirubted API + ObsoletedOnLinuxAndWindows10(); // Guarded with the attrubuted API } } From fe9829d9d1f3fa580b85fd9219d7d00653de70ae Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Wed, 3 Aug 2022 13:24:12 -0700 Subject: [PATCH 6/6] Apply suggestions from code review Co-authored-by: Jeff Handley --- ...CompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs index 3524147989..d0f0655a37 100644 --- a/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs +++ b/src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/InteropServices/PlatformCompatibilityAnalyzer.ObsoletedInOSPlatformTests.cs @@ -222,7 +222,7 @@ public void SuppressedByCallsiteUnsupported() public void NotSuppressedByCallsiteUnsupported() // obsoleted before unsupported version { {|CA1422:ObsoletedOnWindows()|}; // This call site is reachable on: 'Windows' 11.1.0 and before. 'Test.ObsoletedOnWindows()' is obsoleted on: 'Windows' 10.1.1.1 and later. - {|CA1422:ObsoletedWithMessage()|}; // This call site is reachable on: 'Windows' 11.1.0 and before. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead. + {|CA1422:ObsoletedWithMessage()|}; // This call site is reachable on: 'Windows' 11.1.0 and before. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later (Use other method instead). {|CA1422:ObsoletedOnIOS14()|}; // This call site is reachable on: 'ios' 15.0 and before, 'maccatalyst' 15.0 and before. 'Test.ObsoletedOnIOS14()' is obsoleted on: 'ios' 14.0 and later, 'maccatalyst' 14.0 and later. } @@ -240,7 +240,7 @@ public void SuppressedByCallsiteObsoleted() public void NotSuppressedByCallsiteObsoleted() { {|CA1422:ObsoletedOnWindows()|}; //This call site is reachable on all platforms. 'Test.ObsoletedOnWindows()' is obsoleted on: 'Windows' 10.1.1.1 and later. - {|CA1422:ObsoletedWithMessage()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use other method instead. + {|CA1422:ObsoletedWithMessage()|}; // This call site is reachable on all platforms. 'Test.ObsoletedWithMessage()' is obsoleted on: 'Windows' 10.1.1.1 and later (Use other method instead). {|CA1422:ObsoletedOnIOS14()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnIOS14()' is obsoleted on: 'ios' 14.0 and later, 'maccatalyst' 14.0 and later. } @@ -313,7 +313,7 @@ public void CrossPlatform() { ObsoletedOnMacOS(); ObsoletedOnAndroid21(); // Android is not in MSBuild support list, no warning - {|CA1422:ObsoletedOnLinux4AndWindows10()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Linux' 4.1 and later, Use Linux4Supported, 'Windows' 10.1.1.1 and later, Use Windows10Supported. + {|CA1422:ObsoletedOnLinux4AndWindows10()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Linux' 4.1 and later, Use Linux4Supported, 'Windows' 10.1.1.1 and later (Use Windows10Supported). } if (OperatingSystem.IsMacOSVersionAtLeast(11)) @@ -423,14 +423,14 @@ public void CrossPlatform() { ObsoletedOnMacOS(); // Guarded with the attributed field ObsoletedOnMacOS15(); - {|CA1422:ObsoletedOnLinuxAndWindows10()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Linux', 'Windows' 10.1.1.1 and later, Use Windows10Supported. + {|CA1422:ObsoletedOnLinuxAndWindows10()|}; // This call site is reachable on all platforms. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Linux', 'Windows' 10.1.1.1 and later (Use Windows10Supported). } if (IsWindows11Supported) { ObsoletedOnMacOS(); // reachable on 'Windows' 11.0 and later only ObsoletedOnMacOS15(); - {|CA1422:ObsoletedOnLinuxAndWindows10()|}; // This call site is reachable on: 'Windows' 11.0 and later. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Windows' 10.1.1.1 and later, Use Windows10Supported. + {|CA1422:ObsoletedOnLinuxAndWindows10()|}; // This call site is reachable on: 'Windows' 11.0 and later. 'Test.ObsoletedOnLinux4AndWindows10()' is obsoleted on: 'Windows' 10.1.1.1 and later (Use Windows10Supported). } if (IsLinuxWindows10NotSupported())