diff --git a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs index 4b0b506499d..d1d0a4ab8e2 100644 --- a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs @@ -30,19 +30,11 @@ public class SonarAnalysisContextBase protected static readonly SourceTextValueProvider ProjectConfigProvider = new(x => new ProjectConfigReader(x)); protected static readonly SourceTextValueProvider SonarLintXmlProviderCS = new(x => new SonarLintXmlReader(x, LanguageNames.CSharp)); protected static readonly SourceTextValueProvider SonarLintXmlProviderVB = new(x => new SonarLintXmlReader(x, LanguageNames.VisualBasic)); - private static readonly Lazy> ShouldAnalyzeGeneratedCS = new(() => CreateAnalyzeGeneratedProvider(LanguageNames.CSharp)); - private static readonly Lazy> ShouldAnalyzeGeneratedVB = new(() => CreateAnalyzeGeneratedProvider(LanguageNames.VisualBasic)); protected SonarAnalysisContextBase() { } protected static SourceTextValueProvider SonarLintXmlReader(string language) => language == LanguageNames.CSharp ? SonarLintXmlProviderCS : SonarLintXmlProviderVB; - - protected static SourceTextValueProvider ShouldAnalyzeGeneratedProvider(string language) => - language == LanguageNames.CSharp ? ShouldAnalyzeGeneratedCS.Value : ShouldAnalyzeGeneratedVB.Value; - - private static SourceTextValueProvider CreateAnalyzeGeneratedProvider(string language) => - new(x => PropertiesHelper.ReadAnalyzeGeneratedCodeProperty(PropertiesHelper.ParseXmlSettings(x), language)); } public abstract class SonarAnalysisContextBase : SonarAnalysisContextBase @@ -63,7 +55,7 @@ protected SonarAnalysisContextBase(SonarAnalysisContext analysisContext, TContex /// Tree to decide on. Can be null for Symbol-based and Compilation-based scenarios. And we want to analyze those too. /// When set, generated trees are analyzed only when language-specific 'analyzeGeneratedCode' configuration property is also set. public bool ShouldAnalyzeTree(SyntaxTree tree, GeneratedCodeRecognizer generatedCodeRecognizer) => - (generatedCodeRecognizer is null || ShouldAnalyzeGenerated() || !tree.IsGenerated(generatedCodeRecognizer, Compilation)) + (generatedCodeRecognizer is null || SonarLintFile().AnalyzeGeneratedCode || !tree.IsGenerated(generatedCodeRecognizer, Compilation)) && (tree is null || !IsUnchanged(tree)); /// @@ -132,9 +124,4 @@ public bool HasMatchingScope(DiagnosticDescriptor descriptor) private ImmutableHashSet CreateUnchangedFilesHashSet() => ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase, ProjectConfiguration().AnalysisConfig?.UnchangedFiles() ?? Array.Empty()); - - private bool ShouldAnalyzeGenerated() => - Options.SonarLintXml() is { } sonarLintXml - && AnalysisContext.TryGetValue(sonarLintXml.GetText(), ShouldAnalyzeGeneratedProvider(Compilation.Language), out var shouldAnalyzeGenerated) - && shouldAnalyzeGenerated; } diff --git a/analyzers/src/SonarAnalyzer.Common/Extensions/AnalyzerOptionsExtensions.cs b/analyzers/src/SonarAnalyzer.Common/Extensions/AnalyzerOptionsExtensions.cs index 6cea60b71a5..d3ed1f510bd 100644 --- a/analyzers/src/SonarAnalyzer.Common/Extensions/AnalyzerOptionsExtensions.cs +++ b/analyzers/src/SonarAnalyzer.Common/Extensions/AnalyzerOptionsExtensions.cs @@ -19,7 +19,6 @@ */ using System.IO; -using System.Xml.Linq; namespace SonarAnalyzer.Extensions; @@ -34,9 +33,6 @@ public static class AnalyzerOptionsExtensions public static AdditionalText ProjectOutFolderPath(this AnalyzerOptions options) => options.AdditionalFile("ProjectOutFolderPath.txt"); - public static XElement[] ParseSonarLintXmlSettings(this AnalyzerOptions options) => - options.SonarLintXml() is { } sonarLintXml ? PropertiesHelper.ParseXmlSettings(sonarLintXml.GetText()) : Array.Empty(); - private static AdditionalText AdditionalFile(this AnalyzerOptions options, string fileName) => options.AdditionalFiles.FirstOrDefault(x => x.Path is not null && Path.GetFileName(x.Path).Equals(fileName, StringComparison.OrdinalIgnoreCase)); } diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/PropertiesHelper.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/PropertiesHelper.cs deleted file mode 100644 index ec7286f082b..00000000000 --- a/analyzers/src/SonarAnalyzer.Common/Helpers/PropertiesHelper.cs +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarAnalyzer for .NET - * Copyright (C) 2015-2023 SonarSource SA - * mailto: contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -using System.Xml.Linq; -using Microsoft.CodeAnalysis.Text; - -namespace SonarAnalyzer.Helpers -{ - internal static class PropertiesHelper - { - public static XElement[] ParseXmlSettings(SourceText sourceText) - { - try - { - return XDocument.Parse(sourceText.ToString()).Descendants("Setting").ToArray(); - } - catch - { - return Array.Empty(); // Can not log the exception, so ignore it - } - } - - public static bool ReadAnalyzeGeneratedCodeProperty(IEnumerable settings, string language) => - ReadBooleanProperty(settings, language, "analyzeGeneratedCode"); - - private static bool ReadBooleanProperty(IEnumerable settings, string language, string propertySuffix, bool defaultValue = false) - { - var propertyLanguage = language == LanguageNames.CSharp ? "cs" : "vbnet"; - var propertyName = $"sonar.{propertyLanguage}.{propertySuffix}"; - return settings.Any() - && GetPropertyStringValue(propertyName) is { } propertyStringValue - && bool.TryParse(propertyStringValue, out var propertyValue) - ? propertyValue - : defaultValue; - - string GetPropertyStringValue(string propName) => - settings.FirstOrDefault(s => s.Element("Key")?.Value == propName)?.Element("Value").Value; - } - } -} diff --git a/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs b/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs index d8c35d9468d..6df9b93a53e 100644 --- a/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs @@ -52,19 +52,18 @@ public abstract class UtilityAnalyzerBase : SonarDiagnosticAnalyzer protected void ReadParameters(SonarCompilationStartAnalysisContext context) { - var settings = context.Options.ParseSonarLintXmlSettings(); var outPath = context.ProjectConfiguration().OutPath; // For backward compatibility with S4MSB <= 5.0 if (outPath == null && context.Options.ProjectOutFolderPath() is { } projectOutFolderAdditionalFile) { outPath = projectOutFolderAdditionalFile.GetText().ToString().TrimEnd(); } - if (settings.Any() && !string.IsNullOrEmpty(outPath)) + if (context.Options.SonarLintXml() != null && !string.IsNullOrEmpty(outPath)) { - var language = context.Compilation.Language; - IgnoreHeaderComments = context.SonarLintFile().IgnoreHeaderComments; - AnalyzeGeneratedCode = PropertiesHelper.ReadAnalyzeGeneratedCodeProperty(settings, language); - OutPath = Path.Combine(outPath, language == LanguageNames.CSharp ? "output-cs" : "output-vbnet"); + var sonarLintXml = context.SonarLintFile(); + IgnoreHeaderComments = sonarLintXml.IgnoreHeaderComments; + AnalyzeGeneratedCode = sonarLintXml.AnalyzeGeneratedCode; + OutPath = Path.Combine(outPath, context.Compilation.Language == LanguageNames.CSharp ? "output-cs" : "output-vbnet"); IsAnalyzerEnabled = true; IsTestProject = context.IsTestProject(); } diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs index 54c4b1dc9fe..e0c98dd49aa 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs @@ -225,6 +225,8 @@ public void SonarLintFile_WhenFileChanges_RebuildsCache() [DataRow(null)] [DataRow("\\foo\\bar\\does-not-exit")] [DataRow("\\foo\\bar\\x.xml")] + [DataRow("path//aSonarLint.xml")] // different name + [DataRow("path//SonarLint.xmla")] // different extension public void SonarLintFile_WhenAdditionalFileNotPresent_ReturnsDefaultValues(string folder) { var sut = CreateSut(AnalysisScaffolding.CreateOptions(folder)).SonarLintFile(); diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/PropertiesHelperTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/PropertiesHelperTest.cs deleted file mode 100644 index acb23ca9d43..00000000000 --- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/PropertiesHelperTest.cs +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SonarAnalyzer for .NET - * Copyright (C) 2015-2023 SonarSource SA - * mailto: contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -using System.IO; -using Microsoft.CodeAnalysis.Text; -using SonarAnalyzer.Extensions; - -namespace SonarAnalyzer.UnitTest.Helpers -{ - [TestClass] - public class PropertiesHelperTest - { - [TestMethod] - [DataRow("a/SonarLint.xml")] // unix path - [DataRow("a\\SonarLint.xml")] - public void ShouldAnalyzeGeneratedCode_WithTrueSetting_ReturnsTrue(string filePath) => - GetSetting(SourceText.From(File.ReadAllText("ResourceTests\\AnalyzeGeneratedTrue\\SonarLint.xml")), filePath).Should().BeTrue(); - - [TestMethod] - public void ShouldAnalyzeGeneratedCode_WithFalseSetting_ReturnsFalse() => - GetSetting(SourceText.From(File.ReadAllText("ResourceTests\\AnalyzeGeneratedFalse\\SonarLint.xml"))).Should().BeFalse(); - - [TestMethod] - public void ShouldAnalyzeGeneratedCode_WithNoSetting_ReturnsFalse() => - GetSetting(SourceText.From(File.ReadAllText("ResourceTests\\NoSettings\\SonarLint.xml"))).Should().BeFalse(); - - [TestMethod] - [DataRow("")] - [DataRow("this is not an xml")] - [DataRow(@"")] - public void ShouldAnalyzeGeneratedCode_WithMalformedXml_ReturnsFalse(string sonarLintXmlContent) => - GetSetting(SourceText.From(sonarLintXmlContent)).Should().BeFalse(); - - [TestMethod] - public void ShouldAnalyzeGeneratedCode_WithNotBooleanValue_ReturnsFalse() => - GetSetting(SourceText.From(File.ReadAllText("ResourceTests\\NotBoolean\\SonarLint.xml"))).Should().BeFalse(); - - [TestMethod] - [DataRow("path//aSonarLint.xml")] // different name - [DataRow("path//SonarLint.xmla")] // different extension - public void ShouldAnalyzeGeneratedCode_NonSonarLintXmlPath_ReturnsFalse(string filePath) => - GetSetting(SourceText.From(File.ReadAllText("ResourceTests\\AnalyzeGeneratedTrue\\SonarLint.xml")), filePath).Should().BeFalse(); - - private static bool GetSetting(SourceText text, string path = "fakePath\\SonarLint.xml") - { - var options = AnalysisScaffolding.CreateOptions(path, text); - return PropertiesHelper.ReadAnalyzeGeneratedCodeProperty(options.ParseSonarLintXmlSettings(), LanguageNames.CSharp); - } - } -} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/NoSettings/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/NoSettings/SonarLint.xml deleted file mode 100644 index 7a00c312796..00000000000 --- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/NoSettings/SonarLint.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - S1067 - - - max - 1 - - - - - - - diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/NotBoolean/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/NotBoolean/SonarLint.xml deleted file mode 100644 index fd29e9c1f0a..00000000000 --- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/NotBoolean/SonarLint.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - sonar.cs.ignoreHeaderComments - not-boolean-value - - - sonar.cs.analyzeGeneratedCode - not-boolean-value - - - sonar.cs.file.suffixes - .cs - - - - - S1067 - - - max - 1 - - - - - - -