diff --git a/Tests/SonarScanner.MSBuild.PreProcessor.Test/Infrastructure/MockAnalyzerInstaller.cs b/Tests/SonarScanner.MSBuild.PreProcessor.Test/Infrastructure/MockAnalyzerInstaller.cs index 58f85799c..5c21076e4 100644 --- a/Tests/SonarScanner.MSBuild.PreProcessor.Test/Infrastructure/MockAnalyzerInstaller.cs +++ b/Tests/SonarScanner.MSBuild.PreProcessor.Test/Infrastructure/MockAnalyzerInstaller.cs @@ -31,19 +31,22 @@ internal class MockAnalyzerInstaller : IAnalyzerInstaller public MockAnalyzerInstaller(IList analyzerPluginsToReturn = null) => AnalyzerPluginsToReturn = analyzerPluginsToReturn; - public void AssertExpectedPluginsRequested(IEnumerable plugins) + public void AssertOnlyExpectedPluginsRequested(IEnumerable plugins) { + SuppliedPlugins.Should().HaveSameCount(plugins); foreach (var plugin in plugins) { AssertExpectedPluginRequested(plugin); } } - public void AssertExpectedPluginRequested(string key) + public void AssertExpectedPluginRequested(Plugin plugin) { SuppliedPlugins.Should().NotBeEmpty("No plugins have been requested"); - var found = SuppliedPlugins.Any(x => string.Equals(key, x.Key, System.StringComparison.Ordinal)); - found.Should().BeTrue("Expected plugin was not requested. Id: {0}", key); + var suppliedPlugin = SuppliedPlugins.SingleOrDefault(x => x.Key == plugin.Key); + suppliedPlugin.Should().NotBeNull("Expected plugin was not requested. Id: {0}", plugin.Key); + suppliedPlugin.Version.Should().Be(plugin.Version); + suppliedPlugin.StaticResourceName.Should().Be(plugin.StaticResourceName); } IEnumerable IAnalyzerInstaller.InstallAssemblies(IEnumerable plugins) diff --git a/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynAnalyzerProviderTests.cs b/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynAnalyzerProviderTests.cs index 80dd01f72..6def106b6 100644 --- a/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynAnalyzerProviderTests.cs +++ b/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynAnalyzerProviderTests.cs @@ -54,17 +54,20 @@ public void RoslynConfig_NoActiveRules() } [TestMethod] - public void RoslynConfig_NoAssemblies() + public void RoslynConfig_PropertyWithoutDot() { var sonarProperties = new ListPropertiesProvider(new Dictionary { - { "wintellect.analyzerId", "Wintellect.Analyzers" }, - { "wintellect.ruleNamespace", "Wintellect.Analyzers" }, - { "sonaranalyzer-cs.analyzerId", "SonarAnalyzer.CSharp" }, - { "sonaranalyzer-cs.ruleNamespace", "SonarAnalyzer.CSharp" } + {"propertyWithoutDot", "someValue"} }); - var context = new Context(TestContext, sonarProperties, [[@"c:\assembly1.dll"]]); + var context = new Context(TestContext, sonarProperties, [], []); + context.ActualSettings.Should().NotBeNull(); + } + [TestMethod] + public void RoslynConfig_NoAssemblies() + { + var context = new Context(TestContext, new ListPropertiesProvider(), [[@"c:\assembly1.dll"]]); context.AssertCorrectAnalyzerSettings(); context.AssertNoWarningsOrErrors(); context.AssertInfoMessages("No Roslyn analyzer plugins were specified so no Roslyn analyzers will be run for cs"); @@ -73,48 +76,176 @@ public void RoslynConfig_NoAssemblies() context.AssertExpectedPluginsRequested([]); } - [TestMethod] - public void RoslynConfig_ValidProfile() + [DataTestMethod] + [DataRow(RoslynAnalyzerProvider.CSharpLanguage)] + [DataRow(RoslynAnalyzerProvider.VBNetLanguage)] + public void RoslynConfig_ValidProfile_WithLegacy(string language) + { + var sonarProperties = new ListPropertiesProvider(new Dictionary + { + {"wintellect.pluginKey", "wintellect"}, + {"wintellect.pluginVersion", "1.13.0"}, + {"wintellect.staticResourceName", "wintellect.zip"}, + {"sonar.cs.analyzer.dotnet.pluginKey", "cs"}, + {"sonar.cs.analyzer.dotnet.pluginVersion", "1.42.0"}, + {"sonar.cs.analyzer.dotnet.staticResourceName", "SonarAnalyzer.zip"}, + {"sonar.vbnet.analyzer.dotnet.pluginKey", "vbnet"}, + {"sonar.vbnet.analyzer.dotnet.pluginVersion", "1.42.0"}, + {"sonar.vbnet.analyzer.dotnet.staticResourceName", "SonarAnalyzer.zip"}, + {"sonar.vbnet.testPropertyPattern", "foo"}, + {"sonaranalyzer-cs.analyzerId", "SonarAnalyzer.CSharp"}, + {"sonaranalyzer-cs.ruleNamespace", "SonarAnalyzer.CSharp"}, + {"sonaranalyzer-cs.pluginKey", "cs"}, + {"sonaranalyzer-cs.staticResourceName", "SonarAnalyzer.zip"}, + {"sonaranalyzer-cs.nuget.packageId", "SonarAnalyzer.CSharp"}, + {"sonaranalyzer-cs.pluginVersion", "1.42.0"}, + {"sonaranalyzer-cs.nuget.packageVersion", "1.13.0"}, + {"sonaranalyzer-vbnet.analyzerId", "SonarAnalyzer.CSharp"}, + {"sonaranalyzer-vbnet.ruleNamespace", "SonarAnalyzer.CSharp"}, + {"sonaranalyzer-vbnet.pluginKey", "vbnet"}, + {"sonaranalyzer-vbnet.staticResourceName", "SonarAnalyzer.zip"}, + {"sonaranalyzer-vbnet.nuget.packageId", "SonarAnalyzer.CSharp"}, + {"sonaranalyzer-vbnet.pluginVersion", "1.42.0"}, + {"sonaranalyzer-vbnet.nuget.packageVersion", "1.13.0"}, + {"sonar.cs.testPropertyPattern", "foo"}, + {"sonar.sources", "**/*.*"}, + {"sonar.cs.foo", "bar"}, + {"sonar.vbnet.foo", "bar"}, + {"sonar.cs.analyzer.security.pluginKey", "securitycsharpfrontend" }, + {"sonar.cs.analyzer.security.pluginVersion", "1.42.0" }, + {"sonar.cs.analyzer.security.staticResourceName", "SecurityAnalyzer.zip" }, + {"sonaranalyzer.security.cs.pluginKey", "OLDSecurityCSharpFrontend" }, + {"sonaranalyzer.security.cs.pluginVersion", "OLDSecurityCSharpFrontend" }, + {"sonaranalyzer.security.cs.staticResourceName", "OLDSecurityCSharpFrontend" }, + }); + var context = new Context(TestContext, sonarProperties, [[@"c:\assembly1.dll"], [@"d:\foo\assembly2.dll"]], null, language); + var securityProperties = language == RoslynAnalyzerProvider.CSharpLanguage ? + """ + + + sonar.cs.analyzer.security.pluginKey + securitycsharpfrontend + + + sonar.cs.analyzer.security.pluginVersion + 1.42.0 + + + sonar.cs.analyzer.security.staticResourceName + SecurityAnalyzer.zip + + """ : string.Empty; + var expectedSonarLintXml = $""" + + + + + sonar.{language}.analyzer.dotnet.pluginKey + {language} + + + sonar.{language}.analyzer.dotnet.pluginVersion + 1.42.0 + + + sonar.{language}.analyzer.dotnet.staticResourceName + SonarAnalyzer.zip + + + sonar.{language}.testPropertyPattern + foo + + + sonar.{language}.foo + bar + {securityProperties} + + + + {language}-S1116 + + + key + value + + + + + {language}-S1125 + + + + + + + """; + context.AssertCorrectAnalyzerSettings(); + context.AssertNoWarningsOrErrors(); + context.AssertInfoMessages($"Provisioning analyzer assemblies for {language}..."); + context.AssertCorrectRulesets(); + context.AssertExpectedAssemblies(@"c:\assembly1.dll", @"d:\foo\assembly2.dll"); + var expectedPlugins = new List() + { + new() { Key = "wintellect", Version = "1.13.0", StaticResourceName = "wintellect.zip" }, + new() { Key = language, Version = "1.42.0", StaticResourceName = "SonarAnalyzer.zip" }, + }; + if (language == RoslynAnalyzerProvider.CSharpLanguage) + { + expectedPlugins.Add(new() { Key = "securitycsharpfrontend", Version = "1.42.0", StaticResourceName = "SecurityAnalyzer.zip" }); + } + context.AssertExpectedPluginsRequested(expectedPlugins); + context.AssertExpectedAdditionalFileExists(expectedSonarLintXml); + } + + [DataTestMethod] + [DataRow(RoslynAnalyzerProvider.CSharpLanguage)] + [DataRow(RoslynAnalyzerProvider.VBNetLanguage)] + public void RoslynConfig_ValidProfile_LegacyOnly(string language) { var sonarProperties = new ListPropertiesProvider(new Dictionary { - // for ruleset {"wintellect.analyzerId", "Wintellect.Analyzers" }, {"wintellect.ruleNamespace", "Wintellect.Analyzers" }, - // to fetch assemblies {"wintellect.pluginKey", "wintellect"}, {"wintellect.pluginVersion", "1.13.0"}, - {"wintellect.staticResourceName", "SonarAnalyzer.zip"}, + {"wintellect.staticResourceName", "wintellect.zip"}, {"sonaranalyzer-cs.analyzerId", "SonarAnalyzer.CSharp"}, {"sonaranalyzer-cs.ruleNamespace", "SonarAnalyzer.CSharp"}, - {"sonaranalyzer-cs.pluginKey", "csharp"}, + {"sonaranalyzer-cs.pluginKey", "cs"}, {"sonaranalyzer-cs.staticResourceName", "SonarAnalyzer.zip"}, {"sonaranalyzer-cs.nuget.packageId", "SonarAnalyzer.CSharp"}, - {"sonaranalyzer-cs.pluginVersion", "1.13.0"}, + {"sonaranalyzer-cs.pluginVersion", "1.42.0"}, {"sonaranalyzer-cs.nuget.packageVersion", "1.13.0"}, - // Extra properties - those started sonar.cs should be included, the others ignored - {"sonar.vb.testPropertyPattern", "foo"}, + {"sonaranalyzer-vbnet.analyzerId", "SonarAnalyzer.CSharp"}, + {"sonaranalyzer-vbnet.ruleNamespace", "SonarAnalyzer.CSharp"}, + {"sonaranalyzer-vbnet.pluginKey", "vbnet"}, + {"sonaranalyzer-vbnet.staticResourceName", "SonarAnalyzer.zip"}, + {"sonaranalyzer-vbnet.nuget.packageId", "SonarAnalyzer.CSharp"}, + {"sonaranalyzer-vbnet.pluginVersion", "1.42.0"}, + {"sonaranalyzer-vbnet.nuget.packageVersion", "1.13.0"}, + {"sonar.vbnet.testPropertyPattern", "foo"}, {"sonar.cs.testPropertyPattern", "foo"}, {"sonar.sources", "**/*.*"}, - {"sonar.cs.foo", "bar"} + {"sonar.cs.foo", "bar"}, + {"sonar.vbnet.foo", "bar"} }); - var context = new Context(TestContext, sonarProperties, [[@"c:\assembly1.dll"], [@"d:\foo\assembly2.dll"]]); - var expectedSonarLintXml = """ + var context = new Context(TestContext, sonarProperties, [[@"c:\assembly1.dll"], [@"d:\foo\assembly2.dll"]], null, language); + var expectedSonarLintXml = $""" - sonar.cs.testPropertyPattern + sonar.{language}.testPropertyPattern foo - sonar.cs.foo + sonar.{language}.foo bar - S1116 + {language}-S1116 key @@ -123,7 +254,7 @@ public void RoslynConfig_ValidProfile() - S1125 + {language}-S1125 @@ -131,16 +262,141 @@ public void RoslynConfig_ValidProfile() """; + context.AssertCorrectAnalyzerSettings(); + context.AssertNoWarningsOrErrors(); + context.AssertCorrectRulesets(); + context.AssertExpectedAssemblies(@"c:\assembly1.dll", @"d:\foo\assembly2.dll"); + context.AssertExpectedPluginsRequested([ + new() { Key = "wintellect", Version = "1.13.0", StaticResourceName = "wintellect.zip" }, + new() { Key = language, Version = "1.42.0", StaticResourceName = "SonarAnalyzer.zip" }]); + context.AssertExpectedAdditionalFileExists(expectedSonarLintXml); + } + [DataTestMethod] + [DataRow(RoslynAnalyzerProvider.CSharpLanguage)] + [DataRow(RoslynAnalyzerProvider.VBNetLanguage)] + public void RoslynConfig_ValidProfile_WithoutLegacy(string language) + { + var sonarProperties = new ListPropertiesProvider(new Dictionary + { + {"wintellect.pluginKey", "wintellect"}, + {"wintellect.pluginVersion", "1.13.0"}, + {"wintellect.staticResourceName", "wintellect.zip"}, + {"sonar.cs.analyzer.dotnet.pluginKey", "cs"}, + {"sonar.cs.analyzer.dotnet.pluginVersion", "1.42.0"}, + {"sonar.cs.analyzer.dotnet.staticResourceName", "SonarAnalyzer.zip"}, + {"sonar.vbnet.analyzer.dotnet.pluginKey", "vbnet"}, + {"sonar.vbnet.analyzer.dotnet.pluginVersion", "1.42.0"}, + {"sonar.vbnet.analyzer.dotnet.staticResourceName", "SonarAnalyzer.zip"}, + {"sonar.vbnet.testPropertyPattern", "foo"}, + {"sonar.cs.testPropertyPattern", "foo"}, + {"sonar.sources", "**/*.*"}, + {"sonar.cs.foo", "bar"}, + {"sonar.vbnet.foo", "bar"}, + {"sonar.cs.analyzer.security.pluginKey", "securitycsharpfrontend"}, + {"sonar.cs.analyzer.security.pluginVersion", "1.13.0"}, + {"sonar.cs.analyzer.security.staticResourceName", "SecurityAnalyzer.zip"}, + }); + var context = new Context(TestContext, sonarProperties, [[@"c:\assembly1.dll"], [@"d:\foo\assembly2.dll"]], null, language); + var securityProperties = language == RoslynAnalyzerProvider.CSharpLanguage ? + """ + + + sonar.cs.analyzer.security.pluginKey + securitycsharpfrontend + + + sonar.cs.analyzer.security.pluginVersion + 1.13.0 + + + sonar.cs.analyzer.security.staticResourceName + SecurityAnalyzer.zip + + """ : string.Empty; + var expectedSonarLintXml = $""" + + + + + sonar.{language}.analyzer.dotnet.pluginKey + {language} + + + sonar.{language}.analyzer.dotnet.pluginVersion + 1.42.0 + + + sonar.{language}.analyzer.dotnet.staticResourceName + SonarAnalyzer.zip + + + sonar.{language}.testPropertyPattern + foo + + + sonar.{language}.foo + bar + {securityProperties} + + + + {language}-S1116 + + + key + value + + + + + {language}-S1125 + + + + + + + """; context.AssertCorrectAnalyzerSettings(); context.AssertNoWarningsOrErrors(); - context.AssertInfoMessages("Provisioning analyzer assemblies for cs..."); + context.AssertInfoMessages($"Provisioning analyzer assemblies for {language}..."); context.AssertCorrectRulesets(); context.AssertExpectedAssemblies(@"c:\assembly1.dll", @"d:\foo\assembly2.dll"); - context.AssertExpectedPluginsRequested(["wintellect", "csharp"]); + var expectedPlugins = new List() + { + new() { Key = "wintellect", Version = "1.13.0", StaticResourceName = "wintellect.zip" }, + new() { Key = language, Version = "1.42.0", StaticResourceName = "SonarAnalyzer.zip" }, + }; + if (language == RoslynAnalyzerProvider.CSharpLanguage) + { + expectedPlugins.Add(new() { Key = "securitycsharpfrontend", Version = "1.13.0", StaticResourceName = "SecurityAnalyzer.zip" }); + } + context.AssertExpectedPluginsRequested(expectedPlugins); context.AssertExpectedAdditionalFileExists(expectedSonarLintXml); } + [DataTestMethod] + [DataRow("sonar.cs.analyzer.dotnet.missing-pluginKey", "sonar.cs.analyzer.dotnet.version", "sonar.cs.analyzer.dotnet.staticResourceName")] + [DataRow("sonar.cs.analyzer.dotnet.pluginKey", "sonar.cs.analyzer.dotnet.missing-version", "sonar.cs.analyzer.dotnet.staticResourceName")] + [DataRow("sonar.cs.analyzer.dotnet.pluginKey", "sonar.cs.analyzer.dotnet.version", "sonar.cs.analyzer.dotnet.missing-staticResourceName")] + public void RoslynConfig_IncompletePluginIgnored(string analyzerIdProperty, string verisonProperty, string staticResourceProperty) + { + var sonarProperties = new ListPropertiesProvider(new Dictionary + { + {analyzerIdProperty, "SonarAnalyzer.CSharp"}, + {verisonProperty, "SonarAnalyzer.CSharp"}, + {staticResourceProperty, "SonarAnalyzer.zip"}, + }); + var context = new Context(TestContext, sonarProperties, [[@"c:\assembly1.dll"], [@"d:\foo\assembly2.dll"]]); + context.AssertCorrectAnalyzerSettings(); + context.AssertNoWarningsOrErrors(); + context.AssertInfoMessages("No Roslyn analyzer plugins were specified so no Roslyn analyzers will be run for cs"); + context.AssertCorrectRulesets(); + context.AssertExpectedAssemblies([]); + context.AssertExpectedPluginsRequested([]); + } + private static BuildSettings CreateSettings(string rootDir) => BuildSettings.CreateNonTeamBuildSettingsForTesting(rootDir); @@ -150,22 +406,24 @@ private class Context private readonly TestLogger logger = new(); private readonly string rootDir; private readonly MockAnalyzerInstaller analyzerInstaller; + private readonly string language; public AnalyzerSettings ActualSettings { get; set; } - public Context(TestContext testContext, ListPropertiesProvider properties, List analyzerPlugins, IEnumerable rules = null) + public Context(TestContext testContext, ListPropertiesProvider properties, List analyzerPlugins, IEnumerable rules = null, string language = null) { this.testContext = testContext; rootDir = CreateTestFolders(); analyzerInstaller = new MockAnalyzerInstaller(CreateAnalyzerPlugins(analyzerPlugins)); - var sut = new RoslynAnalyzerProvider(analyzerInstaller, logger, CreateSettings(rootDir), properties, rules ?? CreateRules(), RoslynAnalyzerProvider.CSharpLanguage); + this.language = language ?? RoslynAnalyzerProvider.CSharpLanguage; + var sut = new RoslynAnalyzerProvider(analyzerInstaller, logger, CreateSettings(rootDir), properties, rules ?? CreateRules(), this.language); ActualSettings = sut.SetupAnalyzer(); } - public void AssertCorrectRulesets() + public void AssertCorrectRulesets(string expectedRules = null) { - CheckRuleset(ActualSettings.RulesetPath, false); - CheckRuleset(ActualSettings.DeactivatedRulesetPath, true); + CheckRuleset(ActualSettings.RulesetPath, false, expectedRules); + CheckRuleset(ActualSettings.DeactivatedRulesetPath, true, expectedRules); } public void AssertNoWarningsOrErrors() @@ -209,8 +467,8 @@ public void AssertExpectedAssemblies(params string[] expected) ActualSettings.AnalyzerPlugins.Should().HaveCount(expected.Length, "Too many assembly file paths returned"); } - public void AssertExpectedPluginsRequested(IEnumerable plugins) => - analyzerInstaller.AssertExpectedPluginsRequested(plugins); + public void AssertExpectedPluginsRequested(IEnumerable plugins) => + analyzerInstaller.AssertOnlyExpectedPluginsRequested(plugins); public void AssertExpectedAdditionalFileExists(string expectedContent, string expectedFileName = "SonarLint.xml") { @@ -234,27 +492,35 @@ public void AssertExpectedAdditionalFileExists(string expectedContent, string ex private static List CreateRules() => [ - new("csharpsquid", "S1116", true) { Parameters = new() { { "key", "value" } } }, - new("csharpsquid", "S1125", true), + new("csharpsquid", "cs-S1116", true) { Parameters = new() { { "key", "value" } } }, + new("csharpsquid", "cs-S1125", true), new("roslyn.wintellect", "Wintellect003", true), - new("csharpsquid", "S1000", false) + new("csharpsquid", "cs-S1000", false), + new("vbnet", "vbnet-S1116", true) { Parameters = new() { { "key", "value" } } }, + new("vbnet", "vbnet-S1125", true), + new("vbnet", "vbnet-S1000", false), + new("roslyn.sonaranalyzer.security.cs", "SECURITY2076", true) ]; - private void CheckRuleset(string ruleSetPath, bool isDeactivated) + private void CheckRuleset(string ruleSetPath, bool isDeactivated, string expectedRules = null) { - var expectedFileName = isDeactivated ? $"Sonar-{RoslynAnalyzerProvider.CSharpLanguage}-none.ruleset" : $"Sonar-{RoslynAnalyzerProvider.CSharpLanguage}.ruleset"; + var expectedFileName = isDeactivated ? $"Sonar-{language}-none.ruleset" : $"Sonar-{language}.ruleset"; var expectedRule = isDeactivated ? "None" : "Warning"; - var expectedContent = $""" + var expectedContent = string.Format(expectedRules ?? """ - - - - + + + + + + + + - """; + """, expectedRule); ruleSetPath.Should().NotBeNullOrEmpty("Ruleset file path should be set"); Path.IsPathRooted(ruleSetPath).Should().BeTrue("Ruleset file path should be absolute"); Path.GetFileName(ruleSetPath).Should().Be(expectedFileName, "Ruleset file does not have the expected name"); diff --git a/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynRuleSetGeneratorTests.cs b/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynRuleSetGeneratorTests.cs index d48aa9658..c4c6474aa 100644 --- a/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynRuleSetGeneratorTests.cs +++ b/Tests/SonarScanner.MSBuild.PreProcessor.Test/RoslynRuleSetGeneratorTests.cs @@ -135,7 +135,7 @@ private sealed class Context public Context(List rules, bool deactivateAll = false) { - var sut = new RoslynRuleSetGenerator(deactivateAll); + var sut = new RoslynRuleSetGenerator(deactivateAll); RuleSet = sut.Generate(rules); ValidateCommonParameters(); } diff --git a/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynAnalyzerProvider.cs b/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynAnalyzerProvider.cs index ef31e36ef..44e3b294a 100644 --- a/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynAnalyzerProvider.cs +++ b/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynAnalyzerProvider.cs @@ -35,8 +35,9 @@ public class RoslynAnalyzerProvider( public const string CSharpLanguage = "cs"; public const string VBNetLanguage = "vbnet"; - private const string LegacyServerPropertyPrefix = "sonaranalyzer-"; - private const string RoslynRepoPrefix = "roslyn."; + private const string ServerPropertyFormat = "sonar.{0}.analyzer"; + private const string RoslynRepoPrefix = "roslyn."; // Used for plugins generated by SonarQube Roslyn SDK, and legacy Sonar Security C# Frontend + private const string LegacyServerPropertyPrefix = "sonaranalyzer-"; // backwards compatibility with plugin version <= 10.4 & SQ Version 10.8. protected readonly IAnalysisPropertyProvider sonarProperties = sonarProperties ?? throw new ArgumentNullException(nameof(sonarProperties)); @@ -117,14 +118,33 @@ private Plugin[] CreatePlugins() plugin.AddProperty(property.Id, property.Value); } } + // If both legacy and new properties are present, remove the legacy version + if (candidates.ContainsKey(string.Format(ServerPropertyFormat, language) + ".dotnet")) + { + candidates.Remove(LegacyServerPropertyPrefix + language); + } + if (candidates.ContainsKey(string.Format(ServerPropertyFormat, language) + ".security") || language == VBNetLanguage) + { + candidates.Remove("sonaranalyzer.security.cs"); + } return candidates.Values.Where(x => x.IsValid).ToArray(); } private string PluginPropertyPrefix(string propertyId) { - var parts = propertyId.Split('.'); - return parts[0] == LegacyServerPropertyPrefix + language || roslynPropertyKeys.Contains(parts[0]) - ? parts[0] - : null; + var index = propertyId.LastIndexOf('.'); + if (index > 0) + { + var prefix = propertyId.Substring(0, index); + return prefix.StartsWith(string.Format(ServerPropertyFormat, language)) + || prefix == LegacyServerPropertyPrefix + language + || roslynPropertyKeys.Contains(prefix) + ? prefix + : null; + } + else + { + return null; + } } } diff --git a/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynRuleSetGenerator.cs b/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynRuleSetGenerator.cs index ba6fe4d20..d0e6654d3 100644 --- a/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynRuleSetGenerator.cs +++ b/src/SonarScanner.MSBuild.PreProcessor/Roslyn/RoslynRuleSetGenerator.cs @@ -18,11 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using System; -using System.Collections.Generic; -using System.Linq; -using SonarScanner.MSBuild.Common; - namespace SonarScanner.MSBuild.PreProcessor.Roslyn.Model; public class RoslynRuleSetGenerator(bool deactivateAll)