From 5ed52635d236d8aacbad433df2927479747b7087 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C4=8Caba=20=C5=A0agi?=
<75226367+csaba-sagi-sonarsource@users.noreply.github.com>
Date: Thu, 2 Mar 2023 12:28:27 +0100
Subject: [PATCH 01/14] Add support for wildcard to regex mapping (#6835)
* Implement pattern widlcardpattern matching logic
* Address review comments
* Add parameter validation
---
.../Helpers/WildcardPatternMatcher.cs | 134 ++++++++++++++++++
.../Helpers/WildcardPatternMatcherTest.cs | 129 +++++++++++++++++
2 files changed, 263 insertions(+)
create mode 100644 analyzers/src/SonarAnalyzer.Common/Helpers/WildcardPatternMatcher.cs
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/Helpers/WildcardPatternMatcherTest.cs
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/WildcardPatternMatcher.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/WildcardPatternMatcher.cs
new file mode 100644
index 00000000000..b72a702d8e9
--- /dev/null
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/WildcardPatternMatcher.cs
@@ -0,0 +1,134 @@
+/*
+ * 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.Collections.Concurrent;
+using System.IO;
+using System.Text;
+using System.Text.RegularExpressions;
+
+namespace SonarAnalyzer.Helpers;
+
+internal static class WildcardPatternMatcher
+{
+ public static bool IsMatch(string pattern, string input) =>
+ !(string.IsNullOrWhiteSpace(pattern) || string.IsNullOrWhiteSpace(input))
+ && WildcardPattern.Create(pattern).Match(input);
+
+ ///
+ /// Copied from https://github.com/SonarSource/sonar-plugin-api/blob/a9bd7ff48f0f77811ed909070030678c443c975a/sonar-plugin-api/src/main/java/org/sonar/api/utils/WildcardPattern.java.
+ ///
+ private sealed class WildcardPattern
+ {
+ private const string SpecialChars = "()[]^$.{}+|";
+ private static readonly ConcurrentDictionary Cache = new();
+ private readonly Regex pattern;
+
+ private WildcardPattern(string pattern, string directorySeparator) =>
+ this.pattern = new Regex(ToRegexp(pattern, directorySeparator), RegexOptions.Compiled, RegexConstants.DefaultTimeout);
+
+ public bool Match(string value)
+ {
+ value = value.TrimStart('/');
+ value = value.TrimEnd('/');
+ try
+ {
+ return pattern.IsMatch(value);
+ }
+ catch (RegexMatchTimeoutException)
+ {
+ return false;
+ }
+ }
+
+ public static WildcardPattern Create(string pattern) =>
+ Create(pattern, Path.DirectorySeparatorChar.ToString());
+
+ private static WildcardPattern Create(string pattern, string directorySeparator) =>
+ Cache.GetOrAdd(pattern + directorySeparator, _ => new WildcardPattern(pattern, directorySeparator));
+
+ private static string ToRegexp(string wildcardPattern, string directorySeparator)
+ {
+ var escapedDirectorySeparator = '\\' + directorySeparator;
+ var sb = new StringBuilder(wildcardPattern.Length);
+
+ sb.Append('^');
+
+ var i = wildcardPattern.StartsWith("/") || wildcardPattern.StartsWith("\\") ? 1 : 0;
+ while (i < wildcardPattern.Length)
+ {
+ var ch = wildcardPattern[i];
+
+ if (SpecialChars.IndexOf(ch) != -1)
+ {
+ // Escape regexp-specific characters
+ sb.Append('\\').Append(ch);
+ }
+ else if (ch == '*')
+ {
+ if (i + 1 < wildcardPattern.Length && wildcardPattern[i + 1] == '*')
+ {
+ // Double asterisk
+ // Zero or more directories
+ if (i + 2 < wildcardPattern.Length && IsSlash(wildcardPattern[i + 2]))
+ {
+ sb.Append("(?:.*").Append(escapedDirectorySeparator).Append("|)");
+ i += 2;
+ }
+ else
+ {
+ sb.Append(".*");
+ i += 1;
+ }
+ }
+ else
+ {
+ // Single asterisk
+ // Zero or more characters excluding directory separator
+ sb.Append("[^").Append(escapedDirectorySeparator).Append("]*?");
+ }
+ }
+ else if (ch == '?')
+ {
+ // Any single character excluding directory separator
+ sb.Append("[^").Append(escapedDirectorySeparator).Append("]");
+ }
+ else if (IsSlash(ch))
+ {
+ // Directory separator
+ sb.Append(escapedDirectorySeparator);
+ }
+ else
+ {
+ // Single character
+ sb.Append(ch);
+ }
+
+ i++;
+ }
+
+ sb.Append('$');
+
+ return sb.ToString();
+ }
+
+ private static bool IsSlash(char ch) =>
+ ch == '/' || ch == '\\';
+ }
+}
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/WildcardPatternMatcherTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/WildcardPatternMatcherTest.cs
new file mode 100644
index 00000000000..f8b02ce4aa8
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/WildcardPatternMatcherTest.cs
@@ -0,0 +1,129 @@
+/*
+ * 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;
+
+namespace SonarAnalyzer.UnitTest.Helpers
+{
+ [TestClass]
+ public class WildcardPatternMatcherTest
+ {
+ ///
+ /// Based on https://github.com/SonarSource/sonar-plugin-api/blob/master/plugin-api/src/test/java/org/sonar/api/utils/WildcardPatternTest.java.
+ ///
+ [DataTestMethod]
+
+ [DataRow("Foo", "Foo", true)]
+ [DataRow("foo", "FOO", false)]
+ [DataRow("Foo", "Foot", false)]
+ [DataRow("Foo", "Bar", false)]
+
+ [DataRow("org/T?st.java", "org/Test.java", true)]
+ [DataRow("org/T?st.java", "org/Tost.java", true)]
+ [DataRow("org/T?st.java", "org/Teeest.java", false)]
+
+ [DataRow("org/*.java", "org/Foo.java", true)]
+ [DataRow("org/*.java", "org/Bar.java", true)]
+
+ [DataRow("org/**", "org/Foo.java", true)]
+ [DataRow("org/**", "org/foo/bar.jsp", true)]
+
+ [DataRow("org/**/Test.java", "org/Test.java", true)]
+ [DataRow("org/**/Test.java", "org/foo/Test.java", true)]
+ [DataRow("org/**/Test.java", "org/foo/bar/Test.java", true)]
+
+ [DataRow("org/**/*.java", "org/Foo.java", true)]
+ [DataRow("org/**/*.java", "org/foo/Bar.java", true)]
+ [DataRow("org/**/*.java", "org/foo/bar/Baz.java", true)]
+
+ [DataRow("o?/**/*.java", "org/test.java", false)]
+ [DataRow("o?/**/*.java", "o/test.java", false)]
+ [DataRow("o?/**/*.java", "og/test.java", true)]
+ [DataRow("o?/**/*.java", "og/foo/bar/test.java", true)]
+ [DataRow("o?/**/*.java", "og/foo/bar/test.jav", false)]
+
+ [DataRow("org/sonar/**", "org/sonar/commons/Foo", true)]
+ [DataRow("org/sonar/**", "org/sonar/Foo.java", true)]
+
+ [DataRow("xxx/org/sonar/**", "org/sonar/Foo", false)]
+
+ [DataRow("org/sonar/**/**", "org/sonar/commons/Foo", true)]
+ [DataRow("org/sonar/**/**", "org/sonar/commons/sub/Foo.java", true)]
+
+ [DataRow("org/sonar/**/Foo", "org/sonar/commons/sub/Foo", true)]
+ [DataRow("org/sonar/**/Foo", "org/sonar/Foo", true)]
+
+ [DataRow("*/foo/*", "org/foo/Bar", true)]
+ [DataRow("*/foo/*", "foo/Bar", false)]
+ [DataRow("*/foo/*", "foo", false)]
+ [DataRow("*/foo/*", "org/foo/bar/Hello", false)]
+
+ [DataRow("hell?", "hell", false)]
+ [DataRow("hell?", "hello", true)]
+ [DataRow("hell?", "helloworld", false)]
+
+ [DataRow("**/Reader", "java/io/Reader", true)]
+ [DataRow("**/Reader", "org/sonar/channel/CodeReader", false)]
+
+ [DataRow("**", "java/io/Reader", true)]
+
+ [DataRow("**/app/**", "com/app/Utils", true)]
+ [DataRow("**/app/**", "com/application/MyService", false)]
+
+ [DataRow("**/*$*", "foo/bar", false)]
+ [DataRow("**/*$*", "foo/bar$baz", true)]
+ [DataRow("a+", "aa", false)]
+ [DataRow("a+", "a+", true)]
+ [DataRow("[ab]", "a", false)]
+ [DataRow("[ab]", "[ab]", true)]
+
+ [DataRow("\\n", "\n", false)]
+ [DataRow("foo\\bar", "foo/bar", true)]
+
+ [DataRow("/foo", "foo", true)]
+ [DataRow("\\foo", "foo", true)]
+
+ [DataRow("foo\\bar", "foo\\bar", true)]
+ [DataRow("foo/bar", "foo\\bar", true)]
+ [DataRow("foo\\bar/baz", "foo\\bar\\baz", true)]
+
+ public void IsMatch_MatchesPatternsAsExpected(string pattern, string input, bool expectedResult)
+ {
+ // The test cases are copied from the plugin-api and the directory separators need replacing as Roslyn will not give us the paths with '/'.
+ input = input.Replace("/", Path.DirectorySeparatorChar.ToString());
+
+ WildcardPatternMatcher.IsMatch(pattern, input).Should().Be(expectedResult);
+ }
+
+ [DataTestMethod]
+ [DataRow("")]
+ [DataRow(" ")]
+ [DataRow("/")]
+ [DataRow("\\")]
+ public void IsMatch_InvalidPattern_ReturnsFalse(string pattern) =>
+ WildcardPatternMatcher.IsMatch(pattern, "foo").Should().BeFalse();
+
+ [DataTestMethod]
+ [DataRow(null, "foo")]
+ [DataRow("foo", null)]
+ public void IsMatch_InputParametersArenull_DoesNotThrow(string pattern, string input) =>
+ WildcardPatternMatcher.IsMatch(pattern, input).Should().BeFalse();
+ }
+}
From a88884b06861bf7932e22cd3feb81d917cce55ea Mon Sep 17 00:00:00 2001
From: Cristian Ambrosini
<114916336+cristian-ambrosini-sonarsource@users.noreply.github.com>
Date: Fri, 3 Mar 2023 17:09:12 +0100
Subject: [PATCH 02/14] Create data class for SonarLint.xml and reading
mechanism for reading the file (#6832)
---
.../SonarAnalysisContextBase.cs | 23 +
.../Helpers/SonarLintXml.cs | 59 ++
.../Helpers/SonarLintXmlReader.cs | 93 ++
.../SonarAnalysisContextBaseTest.cs | 93 +-
.../Helpers/SonarLintXmlReaderTest.cs | 106 +++
.../Helpers/SonarLintXmlTest.cs | 82 ++
.../All_properties_cs/SonarLint.xml | 889 ++++++++++++++++++
.../SonarLint.xml | 81 ++
.../All_properties_vbnet/SonarLint.xml | 889 ++++++++++++++++++
.../Incorrect_value_type/SonarLint.xml | 21 +
.../SonarLintXml/Invalid_Xml/SonarLint.xml | 13 +
.../Missing_properties/SonarLint.xml | 13 +
.../SonarLint.xml | 25 +
13 files changed, 2386 insertions(+), 1 deletion(-)
create mode 100644 analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXml.cs
create mode 100644 analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlTest.cs
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_cs/SonarLint.xml
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_small_template/SonarLint.xml
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_vbnet/SonarLint.xml
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Incorrect_value_type/SonarLint.xml
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Invalid_Xml/SonarLint.xml
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Missing_properties/SonarLint.xml
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Partially_missing_properties/SonarLint.xml
diff --git a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
index e18e7365ae7..4b0b506499d 100644
--- a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
+++ b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
@@ -28,11 +28,16 @@ public class SonarAnalysisContextBase
{
protected static readonly ConditionalWeakTable> UnchangedFilesCache = new();
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;
@@ -80,6 +85,24 @@ public ProjectConfigReader ProjectConfiguration()
}
}
+ ///
+ /// Reads the properties from the SonarLint.xml file and caches the result for the scope of this analysis.
+ ///
+ public SonarLintXmlReader SonarLintFile()
+ {
+ if (Options.SonarLintXml() is { } sonarLintXml)
+ {
+ return sonarLintXml.GetText() is { } sourceText
+ && AnalysisContext.TryGetValue(sourceText, SonarLintXmlReader(Compilation.Language), out var sonarLintXmlReader)
+ ? sonarLintXmlReader
+ : throw new InvalidOperationException($"File '{Path.GetFileName(sonarLintXml.Path)}' has been added as an AdditionalFile but could not be read and parsed.");
+ }
+ else
+ {
+ return Helpers.SonarLintXmlReader.Empty;
+ }
+ }
+
public bool IsTestProject()
{
var projectType = ProjectConfiguration().ProjectType;
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXml.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXml.cs
new file mode 100644
index 00000000000..d699d960638
--- /dev/null
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXml.cs
@@ -0,0 +1,59 @@
+/*
+ * 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.Serialization;
+
+namespace SonarAnalyzer.Helpers;
+
+///
+/// DTO to represent the SonarLint.xml for our analyzers.
+///
+///
+/// This class should not be used in this codebase. To get SonarLint.xml properties, use .
+///
+[XmlRoot(ElementName = "AnalysisInput")]
+public class SonarLintXml
+{
+ public static readonly SonarLintXml Empty = new();
+
+ [XmlArray("Settings")]
+ [XmlArrayItem("Setting")]
+ public List Settings { get; set; }
+
+ [XmlArray("Rules")]
+ [XmlArrayItem("Rule")]
+ public List Rules { get; set; }
+}
+
+public class SonarLintXmlRule
+{
+ [XmlElement("Key")]
+ public string Key { get; set; }
+
+ [XmlArray("Parameters")]
+ [XmlArrayItem("Parameter")]
+ public List Parameters { get; set; }
+}
+
+public class SonarLintXmlKeyValuePair
+{
+ public string Key { get; set; }
+ public string Value { get; set; }
+}
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
new file mode 100644
index 00000000000..8c717d7a31d
--- /dev/null
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
@@ -0,0 +1,93 @@
+/*
+ * 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 System.Text;
+using System.Xml;
+using System.Xml.Serialization;
+using Microsoft.CodeAnalysis.Text;
+
+namespace SonarAnalyzer.Helpers;
+
+public class SonarLintXmlReader
+{
+ public static readonly SonarLintXmlReader Empty = new(null, LanguageNames.CSharp);
+
+ private readonly SonarLintXml sonarLintXml;
+ private readonly string propertyLanguage;
+
+ private bool? ignoreHeaderComments;
+ public bool IgnoreHeaderComments => ignoreHeaderComments ??= ReadBoolean(ReadProperty($"sonar.{propertyLanguage}.ignoreHeaderComments"));
+
+ private bool? analyzeGeneratedCode;
+ public bool AnalyzeGeneratedCode => analyzeGeneratedCode ??= ReadBoolean(ReadProperty($"sonar.{propertyLanguage}.analyzeGeneratedCode"));
+
+ private string[] exclusions;
+ public string[] Exclusions => exclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.exclusions"));
+
+ private string[] inclusions;
+ public string[] Inclusions => inclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.inclusions"));
+
+ private string[] globalExclusions;
+ public string[] GlobalExclusions => globalExclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.global.exclusions"));
+
+ private string[] testExclusions;
+ public string[] TestExclusions => testExclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.test.exclusions"));
+
+ private string[] testInclusions;
+ public string[] TestInclusions => testInclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.test.inclusions"));
+
+ private string[] globalTestExclusions;
+ public string[] GlobalTestExclusions => globalTestExclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.global.test.exclusions"));
+
+ public SonarLintXmlReader(SourceText sonarLintXml, string language)
+ {
+ this.sonarLintXml = sonarLintXml == null ? SonarLintXml.Empty : ParseContent(sonarLintXml);
+ propertyLanguage = language == LanguageNames.CSharp ? "cs" : "vbnet";
+ }
+
+ private static SonarLintXml ParseContent(SourceText sonarLintXml)
+ {
+ try
+ {
+ var serializer = new XmlSerializer(typeof(SonarLintXml));
+ var byteArray = Encoding.UTF8.GetBytes(sonarLintXml.ToString());
+ var stream = new MemoryStream(byteArray);
+ using var sr = new StreamReader(stream, Encoding.UTF8, false);
+ using var reader = XmlReader.Create(sr);
+ return (SonarLintXml)serializer.Deserialize(reader);
+ }
+ catch
+ {
+ return SonarLintXml.Empty;
+ }
+ }
+
+ private string ReadProperty(string property) =>
+ sonarLintXml is { Settings: { } settings }
+ ? settings.Where(x => x.Key.Equals(property)).Select(x => x.Value).FirstOrDefault()
+ : string.Empty;
+
+ private static string[] ReadCommaSeparatedArray(string str) =>
+ string.IsNullOrEmpty(str) ? Array.Empty() : str.Split(',');
+
+ private static bool ReadBoolean(string str, bool defaultValue = false) =>
+ bool.TryParse(str, out var propertyValue) ? propertyValue : defaultValue;
+}
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs
index d402e7b82a4..54c4b1dc9fe 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs
@@ -19,6 +19,7 @@
*/
using SonarAnalyzer.AnalysisContext;
+using SonarAnalyzer.Common;
namespace SonarAnalyzer.UnitTest.AnalysisContext;
@@ -131,7 +132,7 @@ public void ProjectConfiguration_WhenFileChanges_RebuildsCache()
secondConfig.Should().NotBeSameAs(firstConfig);
}
- [TestMethod]
+ [DataTestMethod]
[DataRow(null)]
[DataRow("/foo/bar/does-not-exit")]
[DataRow("/foo/bar/x.xml")]
@@ -170,6 +171,96 @@ public void ProjectConfiguration_WhenInvalidXml_ThrowException()
.WithMessage("File 'SonarProjectConfig.xml' has been added as an AdditionalFile but could not be read and parsed.");
}
+ [DataTestMethod]
+ [DataRow("cs")]
+ [DataRow("vbnet")]
+ public void SonarLintFile_LoadsExpectedValues(string language)
+ {
+ var analyzerLanguage = language == "cs" ? AnalyzerLanguage.CSharp : AnalyzerLanguage.VisualBasic;
+ var (compilation, _) = CreateDummyCompilation(analyzerLanguage, "ExtraEmptyFile");
+ var options = AnalysisScaffolding.CreateOptions($"ResourceTests\\SonarLintXml\\All_properties_{language}\\SonarLint.xml");
+ var sut = CreateSut(compilation, options).SonarLintFile();
+
+ sut.IgnoreHeaderComments.Should().BeTrue();
+ sut.AnalyzeGeneratedCode.Should().BeFalse();
+ AssertArrayContent(sut.Exclusions, nameof(sut.Exclusions));
+ AssertArrayContent(sut.Inclusions, nameof(sut.Inclusions));
+ AssertArrayContent(sut.GlobalExclusions, nameof(sut.GlobalExclusions));
+ AssertArrayContent(sut.TestExclusions, nameof(sut.TestExclusions));
+ AssertArrayContent(sut.TestInclusions, nameof(sut.TestInclusions));
+ AssertArrayContent(sut.GlobalTestExclusions, nameof(sut.GlobalTestExclusions));
+
+ static void AssertArrayContent(string[] array, string folder)
+ {
+ array.Should().HaveCount(2);
+ array[0].Should().BeEquivalentTo($"Fake/{folder}/**/*");
+ array[1].Should().BeEquivalentTo($"Fake/{folder}/Second*/**/*");
+ }
+ }
+
+ [TestMethod]
+ public void SonarLintFile_UsesCachedValue()
+ {
+ var options = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
+ var firstSut = CreateSut(options);
+ var secondSut = CreateSut(options);
+ var firstFile = firstSut.SonarLintFile();
+ var secondFile = secondSut.SonarLintFile();
+
+ secondFile.Should().BeSameAs(firstFile);
+ }
+
+ [TestMethod]
+ public void SonarLintFile_WhenFileChanges_RebuildsCache()
+ {
+ var firstOptions = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
+ var secondOptions = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\All_properties_vbnet\\SonarLint.xml");
+ var firstFile = CreateSut(firstOptions).SonarLintFile();
+ var secondFile = CreateSut(secondOptions).SonarLintFile();
+
+ secondFile.Should().NotBeSameAs(firstFile);
+ }
+
+ [DataTestMethod]
+ [DataRow(null)]
+ [DataRow("\\foo\\bar\\does-not-exit")]
+ [DataRow("\\foo\\bar\\x.xml")]
+ public void SonarLintFile_WhenAdditionalFileNotPresent_ReturnsDefaultValues(string folder)
+ {
+ var sut = CreateSut(AnalysisScaffolding.CreateOptions(folder)).SonarLintFile();
+ CheckSonarLintXmlDefaultValues(sut);
+ }
+
+ [TestMethod]
+ public void SonarLintFile_WhenInvalidXml_ReturnsDefaultValues()
+ {
+ var sut = CreateSut(AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\Invalid_Xml\\SonarLint.xml")).SonarLintFile();
+ CheckSonarLintXmlDefaultValues(sut);
+ }
+
+ [TestMethod]
+ public void SonarLintFile_WhenFileIsMissing_ThrowException()
+ {
+ var sut = CreateSut(AnalysisScaffolding.CreateOptions("ThisPathDoesNotExist\\SonarLint.xml"));
+
+ sut.Invoking(x => x.SonarLintFile())
+ .Should()
+ .Throw()
+ .WithMessage("File 'SonarLint.xml' has been added as an AdditionalFile but could not be read and parsed.");
+ }
+
+ private static void CheckSonarLintXmlDefaultValues(SonarLintXmlReader sut)
+ {
+ sut.AnalyzeGeneratedCode.Should().BeFalse();
+ sut.IgnoreHeaderComments.Should().BeFalse();
+ sut.Exclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.Inclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.GlobalExclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.TestExclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.TestInclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.GlobalTestExclusions.Should().NotBeNull().And.HaveCount(0);
+ }
+
private SonarCompilationReportingContext CreateSut(ProjectType projectType, bool isScannerRun) =>
CreateSut(AnalysisScaffolding.CreateOptions(AnalysisScaffolding.CreateSonarProjectConfig(TestContext, projectType, isScannerRun)));
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
new file mode 100644
index 00000000000..b8502beb93f
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
@@ -0,0 +1,106 @@
+/*
+ * 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;
+
+namespace SonarAnalyzer.UnitTest.Helpers;
+
+[TestClass]
+public class SonarLintXmlReaderTest
+{
+ [DataTestMethod]
+ [DataRow(LanguageNames.CSharp, "cs")]
+ [DataRow(LanguageNames.VisualBasic, "vbnet")]
+ public void SonarLintXmlReader_WhenAllValuesAreSet_ExpectedValues(string language, string propertyLanguage)
+ {
+ var sut = CreateSonarLintXmlReader($"ResourceTests\\SonarLintXml\\All_Properties_{propertyLanguage}\\SonarLint.xml", language);
+ sut.IgnoreHeaderComments.Should().BeTrue();
+ sut.AnalyzeGeneratedCode.Should().BeFalse();
+ AssertArrayContent(sut.Exclusions, nameof(sut.Exclusions));
+ AssertArrayContent(sut.Inclusions, nameof(sut.Inclusions));
+ AssertArrayContent(sut.GlobalExclusions, nameof(sut.GlobalExclusions));
+ AssertArrayContent(sut.TestExclusions, nameof(sut.TestExclusions));
+ AssertArrayContent(sut.TestInclusions, nameof(sut.TestInclusions));
+ AssertArrayContent(sut.GlobalTestExclusions, nameof(sut.GlobalTestExclusions));
+
+ static void AssertArrayContent(string[] array, string folder)
+ {
+ array.Should().HaveCount(2);
+ array[0].Should().BeEquivalentTo($"Fake/{folder}/**/*");
+ array[1].Should().BeEquivalentTo($"Fake/{folder}/Second*/**/*");
+ }
+ }
+
+ [TestMethod]
+ public void SonarLintXmlReader_PartiallyMissingProperties_ExpectedAndDefaultValues()
+ {
+ var sut = CreateSonarLintXmlReader("ResourceTests\\SonarLintXml\\Partially_missing_properties\\SonarLint.xml");
+ sut.IgnoreHeaderComments.Should().BeFalse();
+ sut.AnalyzeGeneratedCode.Should().BeTrue();
+ AssertArrayContent(sut.Exclusions, nameof(sut.Exclusions));
+ AssertArrayContent(sut.Inclusions, nameof(sut.Inclusions));
+ sut.GlobalExclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.TestExclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.TestInclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.GlobalTestExclusions.Should().NotBeNull().And.HaveCount(0);
+ }
+
+ [DataTestMethod]
+ [DataRow("")]
+ [DataRow("this is not an xml")]
+ [DataRow(@"")]
+ public void SonarLintXmlReader_WithMalformedXml_DefaultBehaviour(string sonarLintXmlContent) =>
+ CheckSonarLintXmlReaderDefaultValues(new SonarLintXmlReader(SourceText.From(sonarLintXmlContent), LanguageNames.CSharp));
+
+ [TestMethod]
+ public void SonarLintXmlReader_MissingProperties_DefaultBehaviour() =>
+ CheckSonarLintXmlReaderDefaultValues(CreateSonarLintXmlReader("ResourceTests\\SonarLintXml\\Missing_properties\\SonarLint.xml"));
+
+ [TestMethod]
+ public void SonarLintXmlReader_WithIncorrectValueType_DefaultBehaviour() =>
+ CheckSonarLintXmlReaderDefaultValues(CreateSonarLintXmlReader("ResourceTests\\SonarLintXml\\Incorrect_value_type\\SonarLint.xml"));
+
+ [TestMethod]
+ public void SonarLintXmlReader_CheckEmpty_DefaultBehaviour() =>
+ CheckSonarLintXmlReaderDefaultValues(SonarLintXmlReader.Empty);
+
+ private static void CheckSonarLintXmlReaderDefaultValues(SonarLintXmlReader sut)
+ {
+ sut.AnalyzeGeneratedCode.Should().BeFalse();
+ sut.IgnoreHeaderComments.Should().BeFalse();
+ sut.Exclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.Inclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.GlobalExclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.TestExclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.TestInclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.GlobalTestExclusions.Should().NotBeNull().And.HaveCount(0);
+ }
+
+ private static void AssertArrayContent(string[] array, string folder)
+ {
+ array.Should().HaveCount(2);
+ array[0].Should().BeEquivalentTo($"Fake/{folder}/**/*");
+ array[1].Should().BeEquivalentTo($"Fake/{folder}/Second*/**/*");
+ }
+
+ private static SonarLintXmlReader CreateSonarLintXmlReader(string relativePath, string language = LanguageNames.CSharp) =>
+ new(SourceText.From(File.ReadAllText(relativePath)), language);
+}
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlTest.cs
new file mode 100644
index 00000000000..b27c8f4b38d
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlTest.cs
@@ -0,0 +1,82 @@
+/*
+ * 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 System.Xml.Serialization;
+
+namespace SonarAnalyzer.UnitTest.Helpers;
+
+[TestClass]
+public class SonarLintXmlTest
+{
+ [TestMethod]
+ public void SonarLintXml_DeserializeFile_ExpectedValues()
+ {
+ var deserializer = new XmlSerializer(typeof(SonarLintXml));
+ using TextReader textReader = new StreamReader("ResourceTests\\SonarLintXml\\All_properties_small_template\\SonarLint.xml");
+ var sonarLintXml = (SonarLintXml)deserializer.Deserialize(textReader);
+
+ AssertSettings(sonarLintXml.Settings);
+ AssertRules(sonarLintXml.Rules);
+ }
+
+ private static void AssertSettings(List settings)
+ {
+ settings.Should().HaveCount(10);
+
+ AssertKeyValuePair(settings[0], "sonar.cs.ignoreHeaderComments", "true");
+ AssertKeyValuePair(settings[1], "sonar.cs.analyzeGeneratedCode", "false");
+ AssertKeyValuePair(settings[2], "sonar.cs.file.suffixes", ".cs");
+ AssertKeyValuePair(settings[3], "sonar.cs.roslyn.ignoreIssues", "false");
+ AssertKeyValuePair(settings[4], "sonar.exclusions", "Fake/Exclusions/**/*,Fake/Exclusions/Second*/**/*");
+ AssertKeyValuePair(settings[5], "sonar.inclusions", "Fake/Inclusions/**/*,Fake/Inclusions/Second*/**/*");
+ AssertKeyValuePair(settings[6], "sonar.global.exclusions", "Fake/GlobalExclusions/**/*,Fake/GlobalExclusions/Second*/**/*");
+ AssertKeyValuePair(settings[7], "sonar.test.exclusions", "Fake/TestExclusions/**/*,Fake/TestExclusions/Second*/**/*");
+ AssertKeyValuePair(settings[8], "sonar.test.inclusions", "Fake/TestInclusions/**/*,Fake/TestInclusions/Second*/**/*");
+ AssertKeyValuePair(settings[9], "sonar.global.test.exclusions", "Fake/GlobalTestExclusions/**/*,Fake/GlobalTestExclusions/Second*/**/*");
+ }
+
+ private static void AssertRules(List rules)
+ {
+ rules.Should().HaveCount(4);
+ rules.Where(x => x.Parameters.Any()).Should().HaveCount(2);
+
+ rules[0].Key.Should().BeEquivalentTo("S0001");
+ rules[0].Parameters.Should().BeEmpty();
+ rules[1].Key.Should().BeEquivalentTo("S0002");
+ rules[1].Parameters.Should().BeEmpty();
+
+ rules[2].Key.Should().BeEquivalentTo("S0003");
+ rules[2].Parameters.Should().HaveCount(2);
+ AssertKeyValuePair(rules[2].Parameters[0], "format", "^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$");
+ AssertKeyValuePair(rules[2].Parameters[1], "flagsAttributeFormat", "^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$");
+
+ rules[3].Key.Should().BeEquivalentTo("S0004");
+ rules[3].Parameters.Should().HaveCount(2);
+ AssertKeyValuePair(rules[3].Parameters[0], "threshold", "15");
+ AssertKeyValuePair(rules[3].Parameters[1], "propertyThreshold", "3");
+ }
+
+ private static void AssertKeyValuePair(SonarLintXmlKeyValuePair pair, string expectedKey, string expectedValue)
+ {
+ pair.Key.Should().BeEquivalentTo(expectedKey);
+ pair.Value.Should().BeEquivalentTo(expectedValue);
+ }
+}
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_cs/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_cs/SonarLint.xml
new file mode 100644
index 00000000000..0dc284bc00d
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_cs/SonarLint.xml
@@ -0,0 +1,889 @@
+
+
+
+
+ sonar.cs.ignoreHeaderComments
+ true
+
+
+ sonar.cs.analyzeGeneratedCode
+ false
+
+
+ sonar.cs.file.suffixes
+ .cs
+
+
+ sonar.cs.roslyn.ignoreIssues
+ false
+
+
+ sonar.exclusions
+ Fake/Exclusions/**/*,Fake/Exclusions/Second*/**/*
+
+
+ sonar.inclusions
+ Fake/Inclusions/**/*,Fake/Inclusions/Second*/**/*
+
+
+ sonar.global.exclusions
+ Fake/GlobalExclusions/**/*,Fake/GlobalExclusions/Second*/**/*
+
+
+ sonar.test.exclusions
+ Fake/TestExclusions/**/*,Fake/TestExclusions/Second*/**/*
+
+
+ sonar.test.inclusions
+ Fake/TestInclusions/**/*,Fake/TestInclusions/Second*/**/*
+
+
+ sonar.global.test.exclusions
+ Fake/GlobalTestExclusions/**/*,Fake/GlobalTestExclusions/Second*/**/*
+
+
+
+
+ S2225
+
+
+ S2346
+
+
+ S2589
+
+
+ S3433
+
+
+ S1135
+
+
+ S2223
+
+
+ S2344
+
+
+ S2345
+
+
+ S4524
+
+
+ S1134
+
+
+ S2222
+
+
+ S2342
+
+
+ format
+ ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$
+
+
+ flagsAttributeFormat
+ ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$
+
+
+
+
+ S2115
+
+
+ S2583
+
+
+ S3447
+
+
+ S2234
+
+
+ S2479
+
+
+ S3444
+
+
+ S3445
+
+
+ S1144
+
+
+ S1264
+
+
+ S2114
+
+
+ S3442
+
+
+ S3443
+
+
+ S3329
+
+
+ S3440
+
+
+ S3449
+
+
+ S3655
+
+
+ S3776
+
+
+ threshold
+ 15
+
+
+ propertyThreshold
+ 3
+
+
+
+
+ S3897
+
+
+ S2201
+
+
+ S2688
+
+
+ S4502
+
+
+ S1110
+
+
+ S1117
+
+
+ S1118
+
+
+ S2328
+
+
+ S2681
+
+
+ S2326
+
+
+ S3415
+
+
+ S4507
+
+
+ S1116
+
+
+ S1125
+
+
+ S1479
+
+
+ maximum
+ 30
+
+
+
+
+ S2699
+
+
+ S4635
+
+
+ S1123
+
+
+ S2696
+
+
+ S1121
+
+
+ S2692
+
+
+ S1006
+
+
+ S1481
+
+
+ S2219
+
+
+ S3237
+
+
+ S3427
+
+
+ S3236
+
+
+ S3358
+
+
+ S3598
+
+
+ S2386
+
+
+ S3597
+
+
+ S4200
+
+
+ S5773
+
+
+ S1172
+
+
+ S4201
+
+
+ S5659
+
+
+ S3249
+
+
+ S4456
+
+
+ S4457
+
+
+ S3005
+
+
+ S3246
+
+
+ S3247
+
+
+ S5547
+
+
+ S3244
+
+
+ S4211
+
+
+ S5542
+
+
+ S1066
+
+
+ S4210
+
+
+ S1185
+
+
+ S1186
+
+
+ S2275
+
+
+ S2368
+
+
+ S3241
+
+
+ S3457
+
+
+ S3458
+
+
+ S4423
+
+
+ S1155
+
+
+ S2245
+
+
+ S3453
+
+
+ S3456
+
+
+ S4426
+
+
+ S2123
+
+
+ S2365
+
+
+ S2486
+
+
+ S3451
+
+
+ S3330
+
+
+ S4428
+
+
+ S5753
+
+
+ S3217
+
+
+ S3218
+
+
+ S3459
+
+
+ S927
+
+
+ S3450
+
+
+ S5766
+
+
+ S1048
+
+
+ S1168
+
+
+ S2259
+
+
+ S3466
+
+
+ S2257
+
+
+ S3343
+
+
+ S3346
+
+
+ S3464
+
+
+ S2376
+
+
+ S3220
+
+
+ S4433
+
+
+ S1163
+
+
+ S2252
+
+
+ S4790
+
+
+ S818
+
+
+ S2251
+
+
+ S2372
+
+
+ S2743
+
+
+ S4792
+
+
+ S1656
+
+
+ S907
+
+
+ S2995
+
+
+ S3600
+
+
+ S2996
+
+
+ S3963
+
+
+ S2755
+
+
+ S2757
+
+
+ S3604
+
+
+ S2997
+
+
+ S3603
+
+
+ S3966
+
+
+ S1751
+
+
+ S1871
+
+
+ S1643
+
+
+ S1764
+
+
+ S2737
+
+
+ S2971
+
+
+ S2612
+
+
+ S2857
+
+
+ S3875
+
+
+ S3871
+
+
+ S1210
+
+
+ S1450
+
+
+ S2306
+
+
+ S3877
+
+
+ S3998
+
+
+ S1104
+
+
+ S1215
+
+
+ S1699
+
+
+ S3887
+
+
+ S3400
+
+
+ S3884
+
+
+ S3885
+
+
+ S2551
+
+
+ S3881
+
+
+ S2436
+
+
+ maxMethod
+ 3
+
+
+ max
+ 2
+
+
+
+
+ S3889
+
+
+ S1313
+
+
+ S2437
+
+
+ S3972
+
+
+ S2761
+
+
+ S3610
+
+
+ S3973
+
+
+ S3971
+
+
+ S3984
+
+
+ S4830
+
+
+ S3981
+
+
+ S1206
+
+
+ S3626
+
+
+ S3869
+
+
+ S1940
+
+
+ S1944
+
+
+ S1939
+
+
+ S1905
+
+
+ S5034
+
+
+ S4061
+
+
+ S5042
+
+
+ S1854
+
+
+ S4070
+
+
+ S1862
+
+
+ S3925
+
+
+ S3926
+
+
+ S3927
+
+
+ S3928
+
+
+ S2953
+
+
+ S3923
+
+
+ S125
+
+
+ S1607
+
+
+ S1848
+
+
+ S2930
+
+
+ S2933
+
+
+ S3903
+
+
+ S3904
+
+
+ S2934
+
+
+ S6422
+
+
+ S110
+
+
+ max
+ 5
+
+
+
+
+ S2068
+
+
+ credentialWords
+ password, passwd, pwd, passphrase
+
+
+
+
+ S5332
+
+
+ S112
+
+
+ S6424
+
+
+ S2187
+
+
+ S3397
+
+
+ S4487
+
+
+ S2184
+
+
+ S6420
+
+
+ S2183
+
+
+ S5693
+
+
+ fileUploadSizeLimit
+ 8000000
+
+
+
+
+ S107
+
+
+ max
+ 7
+
+
+
+
+ S108
+
+
+ S3169
+
+
+ S4019
+
+
+ S3168
+
+
+ S4015
+
+
+ S4136
+
+
+ S2077
+
+
+ S2190
+
+
+ S1199
+
+
+ S3376
+
+
+ S3011
+
+
+ S3256
+
+
+ S1075
+
+
+ S4581
+
+
+ S4586
+
+
+ S3010
+
+
+ S3251
+
+
+ S4220
+
+
+ S4583
+
+
+ S2178
+
+
+ S3264
+
+
+ S3267
+
+
+ S5443
+
+
+ S101
+
+
+ S3265
+
+
+ S5445
+
+
+ S3262
+
+
+ S6419
+
+
+ S2053
+
+
+ S3263
+
+
+ S2292
+
+
+ S3260
+
+
+ S3261
+
+
+ S2290
+
+
+ S2291
+
+
+ S4144
+
+
+ S6444
+
+
+ S3172
+
+
+ S4143
+
+
+ S4159
+
+
+ S4260
+
+
+ S4036
+
+
+ S4158
+
+
+ S4277
+
+
+ S4035
+
+
+ S4275
+
+
+ S2092
+
+
+ S3060
+
+
+ S5122
+
+
+
+
+
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_small_template/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_small_template/SonarLint.xml
new file mode 100644
index 00000000000..70ca0115566
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_small_template/SonarLint.xml
@@ -0,0 +1,81 @@
+
+
+
+
+ sonar.cs.ignoreHeaderComments
+ true
+
+
+ sonar.cs.analyzeGeneratedCode
+ false
+
+
+ sonar.cs.file.suffixes
+ .cs
+
+
+ sonar.cs.roslyn.ignoreIssues
+ false
+
+
+ sonar.exclusions
+ Fake/Exclusions/**/*,Fake/Exclusions/Second*/**/*
+
+
+ sonar.inclusions
+ Fake/Inclusions/**/*,Fake/Inclusions/Second*/**/*
+
+
+ sonar.global.exclusions
+ Fake/GlobalExclusions/**/*,Fake/GlobalExclusions/Second*/**/*
+
+
+ sonar.test.exclusions
+ Fake/TestExclusions/**/*,Fake/TestExclusions/Second*/**/*
+
+
+ sonar.test.inclusions
+ Fake/TestInclusions/**/*,Fake/TestInclusions/Second*/**/*
+
+
+ sonar.global.test.exclusions
+ Fake/GlobalTestExclusions/**/*,Fake/GlobalTestExclusions/Second*/**/*
+
+
+
+
+ S0001
+
+
+ S0002
+
+
+ S0003
+
+
+ format
+ ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$
+
+
+ flagsAttributeFormat
+ ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$
+
+
+
+
+ S0004
+
+
+ threshold
+ 15
+
+
+ propertyThreshold
+ 3
+
+
+
+
+
+
+
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_vbnet/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_vbnet/SonarLint.xml
new file mode 100644
index 00000000000..f848061efac
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_vbnet/SonarLint.xml
@@ -0,0 +1,889 @@
+
+
+
+
+ sonar.vbnet.ignoreHeaderComments
+ true
+
+
+ sonar.vbnet.analyzeGeneratedCode
+ false
+
+
+ sonar.vbnet.file.suffixes
+ .vb
+
+
+ sonar.vbnet.roslyn.ignoreIssues
+ false
+
+
+ sonar.exclusions
+ Fake/Exclusions/**/*,Fake/Exclusions/Second*/**/*
+
+
+ sonar.inclusions
+ Fake/Inclusions/**/*,Fake/Inclusions/Second*/**/*
+
+
+ sonar.global.exclusions
+ Fake/GlobalExclusions/**/*,Fake/GlobalExclusions/Second*/**/*
+
+
+ sonar.test.exclusions
+ Fake/TestExclusions/**/*,Fake/TestExclusions/Second*/**/*
+
+
+ sonar.test.inclusions
+ Fake/TestInclusions/**/*,Fake/TestInclusions/Second*/**/*
+
+
+ sonar.global.test.exclusions
+ Fake/GlobalTestExclusions/**/*,Fake/GlobalTestExclusions/Second*/**/*
+
+
+
+
+ S2225
+
+
+ S2346
+
+
+ S2589
+
+
+ S3433
+
+
+ S1135
+
+
+ S2223
+
+
+ S2344
+
+
+ S2345
+
+
+ S4524
+
+
+ S1134
+
+
+ S2222
+
+
+ S2342
+
+
+ format
+ ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$
+
+
+ flagsAttributeFormat
+ ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$
+
+
+
+
+ S2115
+
+
+ S2583
+
+
+ S3447
+
+
+ S2234
+
+
+ S2479
+
+
+ S3444
+
+
+ S3445
+
+
+ S1144
+
+
+ S1264
+
+
+ S2114
+
+
+ S3442
+
+
+ S3443
+
+
+ S3329
+
+
+ S3440
+
+
+ S3449
+
+
+ S3655
+
+
+ S3776
+
+
+ threshold
+ 15
+
+
+ propertyThreshold
+ 3
+
+
+
+
+ S3897
+
+
+ S2201
+
+
+ S2688
+
+
+ S4502
+
+
+ S1110
+
+
+ S1117
+
+
+ S1118
+
+
+ S2328
+
+
+ S2681
+
+
+ S2326
+
+
+ S3415
+
+
+ S4507
+
+
+ S1116
+
+
+ S1125
+
+
+ S1479
+
+
+ maximum
+ 30
+
+
+
+
+ S2699
+
+
+ S4635
+
+
+ S1123
+
+
+ S2696
+
+
+ S1121
+
+
+ S2692
+
+
+ S1006
+
+
+ S1481
+
+
+ S2219
+
+
+ S3237
+
+
+ S3427
+
+
+ S3236
+
+
+ S3358
+
+
+ S3598
+
+
+ S2386
+
+
+ S3597
+
+
+ S4200
+
+
+ S5773
+
+
+ S1172
+
+
+ S4201
+
+
+ S5659
+
+
+ S3249
+
+
+ S4456
+
+
+ S4457
+
+
+ S3005
+
+
+ S3246
+
+
+ S3247
+
+
+ S5547
+
+
+ S3244
+
+
+ S4211
+
+
+ S5542
+
+
+ S1066
+
+
+ S4210
+
+
+ S1185
+
+
+ S1186
+
+
+ S2275
+
+
+ S2368
+
+
+ S3241
+
+
+ S3457
+
+
+ S3458
+
+
+ S4423
+
+
+ S1155
+
+
+ S2245
+
+
+ S3453
+
+
+ S3456
+
+
+ S4426
+
+
+ S2123
+
+
+ S2365
+
+
+ S2486
+
+
+ S3451
+
+
+ S3330
+
+
+ S4428
+
+
+ S5753
+
+
+ S3217
+
+
+ S3218
+
+
+ S3459
+
+
+ S927
+
+
+ S3450
+
+
+ S5766
+
+
+ S1048
+
+
+ S1168
+
+
+ S2259
+
+
+ S3466
+
+
+ S2257
+
+
+ S3343
+
+
+ S3346
+
+
+ S3464
+
+
+ S2376
+
+
+ S3220
+
+
+ S4433
+
+
+ S1163
+
+
+ S2252
+
+
+ S4790
+
+
+ S818
+
+
+ S2251
+
+
+ S2372
+
+
+ S2743
+
+
+ S4792
+
+
+ S1656
+
+
+ S907
+
+
+ S2995
+
+
+ S3600
+
+
+ S2996
+
+
+ S3963
+
+
+ S2755
+
+
+ S2757
+
+
+ S3604
+
+
+ S2997
+
+
+ S3603
+
+
+ S3966
+
+
+ S1751
+
+
+ S1871
+
+
+ S1643
+
+
+ S1764
+
+
+ S2737
+
+
+ S2971
+
+
+ S2612
+
+
+ S2857
+
+
+ S3875
+
+
+ S3871
+
+
+ S1210
+
+
+ S1450
+
+
+ S2306
+
+
+ S3877
+
+
+ S3998
+
+
+ S1104
+
+
+ S1215
+
+
+ S1699
+
+
+ S3887
+
+
+ S3400
+
+
+ S3884
+
+
+ S3885
+
+
+ S2551
+
+
+ S3881
+
+
+ S2436
+
+
+ maxMethod
+ 3
+
+
+ max
+ 2
+
+
+
+
+ S3889
+
+
+ S1313
+
+
+ S2437
+
+
+ S3972
+
+
+ S2761
+
+
+ S3610
+
+
+ S3973
+
+
+ S3971
+
+
+ S3984
+
+
+ S4830
+
+
+ S3981
+
+
+ S1206
+
+
+ S3626
+
+
+ S3869
+
+
+ S1940
+
+
+ S1944
+
+
+ S1939
+
+
+ S1905
+
+
+ S5034
+
+
+ S4061
+
+
+ S5042
+
+
+ S1854
+
+
+ S4070
+
+
+ S1862
+
+
+ S3925
+
+
+ S3926
+
+
+ S3927
+
+
+ S3928
+
+
+ S2953
+
+
+ S3923
+
+
+ S125
+
+
+ S1607
+
+
+ S1848
+
+
+ S2930
+
+
+ S2933
+
+
+ S3903
+
+
+ S3904
+
+
+ S2934
+
+
+ S6422
+
+
+ S110
+
+
+ max
+ 5
+
+
+
+
+ S2068
+
+
+ credentialWords
+ password, passwd, pwd, passphrase
+
+
+
+
+ S5332
+
+
+ S112
+
+
+ S6424
+
+
+ S2187
+
+
+ S3397
+
+
+ S4487
+
+
+ S2184
+
+
+ S6420
+
+
+ S2183
+
+
+ S5693
+
+
+ fileUploadSizeLimit
+ 8000000
+
+
+
+
+ S107
+
+
+ max
+ 7
+
+
+
+
+ S108
+
+
+ S3169
+
+
+ S4019
+
+
+ S3168
+
+
+ S4015
+
+
+ S4136
+
+
+ S2077
+
+
+ S2190
+
+
+ S1199
+
+
+ S3376
+
+
+ S3011
+
+
+ S3256
+
+
+ S1075
+
+
+ S4581
+
+
+ S4586
+
+
+ S3010
+
+
+ S3251
+
+
+ S4220
+
+
+ S4583
+
+
+ S2178
+
+
+ S3264
+
+
+ S3267
+
+
+ S5443
+
+
+ S101
+
+
+ S3265
+
+
+ S5445
+
+
+ S3262
+
+
+ S6419
+
+
+ S2053
+
+
+ S3263
+
+
+ S2292
+
+
+ S3260
+
+
+ S3261
+
+
+ S2290
+
+
+ S2291
+
+
+ S4144
+
+
+ S6444
+
+
+ S3172
+
+
+ S4143
+
+
+ S4159
+
+
+ S4260
+
+
+ S4036
+
+
+ S4158
+
+
+ S4277
+
+
+ S4035
+
+
+ S4275
+
+
+ S2092
+
+
+ S3060
+
+
+ S5122
+
+
+
+
+
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Incorrect_value_type/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Incorrect_value_type/SonarLint.xml
new file mode 100644
index 00000000000..ff59ba614a5
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Incorrect_value_type/SonarLint.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ sonar.cs.ignoreHeaderComments
+ abc
+
+
+ sonar.cs.analyzeGeneratedCode
+ null
+
+
+ sonar.cs.roslyn.ignoreIssues
+
+
+
+
+
+
+
+
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Invalid_Xml/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Invalid_Xml/SonarLint.xml
new file mode 100644
index 00000000000..9a259cbeb32
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Invalid_Xml/SonarLint.xml
@@ -0,0 +1,13 @@
+
+
+ Setting>
+ sonar.nothing
+ nothing
+
+
+
+
+ Files>
+
+
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Missing_properties/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Missing_properties/SonarLint.xml
new file mode 100644
index 00000000000..8d8f8135bfc
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Missing_properties/SonarLint.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ sonar.nothing
+ nothing
+
+
+
+
+
+
+
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Partially_missing_properties/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Partially_missing_properties/SonarLint.xml
new file mode 100644
index 00000000000..ed671af08b6
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/Partially_missing_properties/SonarLint.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ sonar.nothing
+ nothing
+
+
+ sonar.cs.analyzeGeneratedCode
+ true
+
+
+ sonar.exclusions
+ Fake/Exclusions/**/*,Fake/Exclusions/Second*/**/*
+
+
+ sonar.inclusions
+ Fake/Inclusions/**/*,Fake/Inclusions/Second*/**/*
+
+
+
+
+
+
+
From 27838e7176a61a95db68e6d70bbcd8f78619d7c0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C4=8Caba=20=C5=A0agi?=
<75226367+csaba-sagi-sonarsource@users.noreply.github.com>
Date: Mon, 6 Mar 2023 10:54:33 +0100
Subject: [PATCH 03/14] Use new way of retrieving the IgnoreHeaderComments
parameter (#6858)
---
analyzers/src/SonarAnalyzer.Common/Helpers/PropertiesHelper.cs | 3 ---
.../Rules/Utilities/UtilityAnalyzerBase.cs | 2 +-
2 files changed, 1 insertion(+), 4 deletions(-)
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/PropertiesHelper.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/PropertiesHelper.cs
index 55844a6ba58..ec7286f082b 100644
--- a/analyzers/src/SonarAnalyzer.Common/Helpers/PropertiesHelper.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/PropertiesHelper.cs
@@ -40,9 +40,6 @@ public static XElement[] ParseXmlSettings(SourceText sourceText)
public static bool ReadAnalyzeGeneratedCodeProperty(IEnumerable settings, string language) =>
ReadBooleanProperty(settings, language, "analyzeGeneratedCode");
- public static bool ReadIgnoreHeaderCommentsProperty(IEnumerable settings, string language) =>
- ReadBooleanProperty(settings, language, "ignoreHeaderComments");
-
private static bool ReadBooleanProperty(IEnumerable settings, string language, string propertySuffix, bool defaultValue = false)
{
var propertyLanguage = language == LanguageNames.CSharp ? "cs" : "vbnet";
diff --git a/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs b/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs
index 9ccc48ce48f..d8c35d9468d 100644
--- a/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs
@@ -62,7 +62,7 @@ protected void ReadParameters(SonarCompilationStartAnalysisContext context)
if (settings.Any() && !string.IsNullOrEmpty(outPath))
{
var language = context.Compilation.Language;
- IgnoreHeaderComments = PropertiesHelper.ReadIgnoreHeaderCommentsProperty(settings, language);
+ IgnoreHeaderComments = context.SonarLintFile().IgnoreHeaderComments;
AnalyzeGeneratedCode = PropertiesHelper.ReadAnalyzeGeneratedCodeProperty(settings, language);
OutPath = Path.Combine(outPath, language == LanguageNames.CSharp ? "output-cs" : "output-vbnet");
IsAnalyzerEnabled = true;
From 37ba063ae380e5a4512f3081added3e138cd347b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C4=8Caba=20=C5=A0agi?=
<75226367+csaba-sagi-sonarsource@users.noreply.github.com>
Date: Tue, 7 Mar 2023 13:45:11 +0100
Subject: [PATCH 04/14] Use new way of reading should analyze generated
parameter (#6865)
---
.../SonarAnalysisContextBase.cs | 15 +----
.../Extensions/AnalyzerOptionsExtensions.cs | 4 --
.../Helpers/PropertiesHelper.cs | 57 ----------------
.../Rules/Utilities/UtilityAnalyzerBase.cs | 11 ++-
.../SonarAnalysisContextBaseTest.cs | 2 +
.../Helpers/PropertiesHelperTest.cs | 67 -------------------
.../ResourceTests/NoSettings/SonarLint.xml | 16 -----
.../ResourceTests/NotBoolean/SonarLint.xml | 30 ---------
8 files changed, 8 insertions(+), 194 deletions(-)
delete mode 100644 analyzers/src/SonarAnalyzer.Common/Helpers/PropertiesHelper.cs
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/Helpers/PropertiesHelperTest.cs
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/NoSettings/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/NotBoolean/SonarLint.xml
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
-
-
-
-
-
-
-
From 3bfd511e5b404afa22e897772cd31ee6df2b5153 Mon Sep 17 00:00:00 2001
From: Cristian Ambrosini
<114916336+cristian-ambrosini-sonarsource@users.noreply.github.com>
Date: Thu, 9 Mar 2023 16:31:26 +0100
Subject: [PATCH 05/14] Apply exclusion inclusion logic for all rules (except
utility) (#6860)
---
.../SonarAnalysisContextBase.cs | 28 +++-
...alysisContextBaseTest.ShouldAnalyzeTree.cs | 156 +++++++++++++-----
.../TestFramework/AnalysisScaffolding.cs | 40 +++++
3 files changed, 183 insertions(+), 41 deletions(-)
diff --git a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
index d1d0a4ab8e2..70fd96b25ee 100644
--- a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
+++ b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
@@ -18,6 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+using System.Collections.Concurrent;
using System.IO;
using System.Runtime.CompilerServices;
using static SonarAnalyzer.Helpers.DiagnosticDescriptorFactory;
@@ -26,6 +27,7 @@ namespace SonarAnalyzer.AnalysisContext;
public class SonarAnalysisContextBase
{
+ protected static readonly ConditionalWeakTable> FileInclusionCache = new();
protected static readonly ConditionalWeakTable> UnchangedFilesCache = new();
protected static readonly SourceTextValueProvider ProjectConfigProvider = new(x => new ProjectConfigReader(x));
protected static readonly SourceTextValueProvider SonarLintXmlProviderCS = new(x => new SonarLintXmlReader(x, LanguageNames.CSharp));
@@ -55,8 +57,9 @@ 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 || SonarLintFile().AnalyzeGeneratedCode || !tree.IsGenerated(generatedCodeRecognizer, Compilation))
- && (tree is null || !IsUnchanged(tree));
+ SonarLintFile() is var sonarLintReader
+ && (generatedCodeRecognizer is null || sonarLintReader.AnalyzeGeneratedCode || !tree.IsGenerated(generatedCodeRecognizer, Compilation))
+ && (tree is null || (!IsUnchanged(tree) && ShouldAnalyzeFile(sonarLintReader, tree.FilePath)));
///
/// Reads configuration from SonarProjectConfig.xml file and caches the result for scope of this analysis.
@@ -122,6 +125,27 @@ public bool HasMatchingScope(DiagnosticDescriptor descriptor)
descriptor.CustomTags.Contains(tag);
}
+ private bool ShouldAnalyzeFile(SonarLintXmlReader sonarLintXml, string filePath) =>
+ ProjectConfiguration().ProjectType != ProjectType.Unknown // Not SonarLint context, NuGet or Scanner <= 5.0
+ || (FileInclusionCache.GetValue(Compilation, _ => new()) is var cache
+ && cache.GetOrAdd(filePath, _ => IsFileIncluded(sonarLintXml, filePath)));
+
private ImmutableHashSet CreateUnchangedFilesHashSet() =>
ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase, ProjectConfiguration().AnalysisConfig?.UnchangedFiles() ?? Array.Empty());
+
+ private bool IsFileIncluded(SonarLintXmlReader sonarLintXml, string filePath) =>
+ IsTestProject()
+ ? IsFileIncluded(sonarLintXml.TestInclusions, sonarLintXml.TestExclusions, sonarLintXml.GlobalTestExclusions, filePath)
+ : IsFileIncluded(sonarLintXml.Inclusions, sonarLintXml.Exclusions, sonarLintXml.GlobalExclusions, filePath);
+
+ private static bool IsFileIncluded(string[] inclusions, string[] exclusions, string[] globalExclusions, string filePath) =>
+ IsIncluded(inclusions, filePath)
+ && !IsExcluded(exclusions, filePath)
+ && !IsExcluded(globalExclusions, filePath);
+
+ private static bool IsIncluded(string[] inclusions, string filePath) =>
+ inclusions is { Length: 0 } || inclusions.Any(x => WildcardPatternMatcher.IsMatch(x, filePath));
+
+ private static bool IsExcluded(string[] exclusions, string filePath) =>
+ exclusions.Any(x => WildcardPatternMatcher.IsMatch(x, filePath));
}
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.ShouldAnalyzeTree.cs b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.ShouldAnalyzeTree.cs
index 0d1d18583c9..c667b8898e2 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.ShouldAnalyzeTree.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.ShouldAnalyzeTree.cs
@@ -18,7 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-using System.IO;
using System.Text;
using Microsoft.CodeAnalysis.Text;
using Moq;
@@ -78,7 +77,7 @@ public void ShouldAnalyzeTree_Scanner_UnchangedFiles_ContainsOtherFile()
[DataRow(OtherFileName, true)]
public void ShouldAnalyzeTree_GeneratedFile_NoSonarLintXml(string fileName, bool expected)
{
- var sonarLintXml = CreateSonarLintXml(true);
+ var sonarLintXml = new DummySourceText(AnalysisScaffolding.GenerateSonarLintXmlContent(analyzeGeneratedCode: true));
var (compilation, tree) = CreateDummyCompilation(AnalyzerLanguage.CSharp, fileName);
var sut = CreateSut(compilation, CreateOptions(sonarLintXml, @"ResourceTests\Foo.xml"));
@@ -89,7 +88,7 @@ public void ShouldAnalyzeTree_GeneratedFile_NoSonarLintXml(string fileName, bool
[TestMethod]
public void ShouldAnalyzeTree_GeneratedFile_ShouldAnalyzeGeneratedProvider_IsCached()
{
- var sonarLintXml = CreateSonarLintXml(true);
+ var sonarLintXml = new DummySourceText(AnalysisScaffolding.GenerateSonarLintXmlContent(analyzeGeneratedCode: true));
var additionalText = new Mock();
additionalText.Setup(x => x.Path).Returns("SonarLint.xml");
additionalText.Setup(x => x.GetText(default)).Returns(sonarLintXml);
@@ -129,7 +128,7 @@ public void ShouldAnalyzeTree_GeneratedFile_InvalidSonarLintXml(string fileName,
[DataRow(OtherFileName)]
public void ShouldAnalyzeTree_GeneratedFile_AnalyzeGenerated_AnalyzeAllFiles(string fileName)
{
- var sonarLintXml = CreateSonarLintXml(true);
+ var sonarLintXml = new DummySourceText(AnalysisScaffolding.GenerateSonarLintXmlContent(analyzeGeneratedCode: true));
var (compilation, tree) = CreateDummyCompilation(AnalyzerLanguage.CSharp, fileName);
var sut = CreateSut(compilation, CreateOptions(sonarLintXml));
@@ -137,25 +136,24 @@ public void ShouldAnalyzeTree_GeneratedFile_AnalyzeGenerated_AnalyzeAllFiles(str
}
[DataTestMethod]
- [DataRow(GeneratedFileName, false)]
- [DataRow(OtherFileName, true)]
- public void ShouldAnalyzeTree_CorrectSettingUsed(string fileName, bool expectedCSharp)
+ [DataRow(GeneratedFileName, LanguageNames.CSharp, false)]
+ [DataRow(OtherFileName, LanguageNames.CSharp, true)]
+ [DataRow(GeneratedFileName, LanguageNames.VisualBasic, false)]
+ [DataRow(OtherFileName, LanguageNames.VisualBasic, true)]
+ public void ShouldAnalyzeTree_CorrectSettingUsed(string fileName, string language, bool expected)
{
- var sonarLintXml = CreateSonarLintXml(false);
- var (compilationCS, treeCS) = CreateDummyCompilation(AnalyzerLanguage.CSharp, fileName);
- var (compilationVB, treeVB) = CreateDummyCompilation(AnalyzerLanguage.VisualBasic, fileName);
- var sutCS = CreateSut(compilationCS, CreateOptions(sonarLintXml));
- var sutVB = CreateSut(compilationVB, CreateOptions(sonarLintXml));
-
- sutCS.ShouldAnalyzeTree(treeCS, CSharpGeneratedCodeRecognizer.Instance).Should().Be(expectedCSharp);
- sutVB.ShouldAnalyzeTree(treeVB, VisualBasicGeneratedCodeRecognizer.Instance).Should().BeTrue();
+ var sonarLintXml = new DummySourceText(AnalysisScaffolding.GenerateSonarLintXmlContent(language: language, analyzeGeneratedCode: false));
+ var analyzerLanguage = language == LanguageNames.CSharp ? AnalyzerLanguage.CSharp : AnalyzerLanguage.VisualBasic;
+ var (compilation, tree) = CreateDummyCompilation(analyzerLanguage, fileName);
+ var sut = CreateSut(compilation, CreateOptions(sonarLintXml));
+ GeneratedCodeRecognizer generatedCodeRecognizer = language == LanguageNames.CSharp ? CSharpGeneratedCodeRecognizer.Instance : VisualBasicGeneratedCodeRecognizer.Instance;
- sonarLintXml.ToStringCallCount.Should().Be(2, "file should be read once per language");
+ sut.ShouldAnalyzeTree(tree, generatedCodeRecognizer).Should().Be(expected);
+ sonarLintXml.ToStringCallCount.Should().Be(1, "file should be read once per language");
// Read again to check caching
- sutVB.ShouldAnalyzeTree(treeVB, VisualBasicGeneratedCodeRecognizer.Instance).Should().BeTrue();
-
- sonarLintXml.ToStringCallCount.Should().Be(2, "file should not have been read again");
+ sut.ShouldAnalyzeTree(tree, generatedCodeRecognizer).Should().Be(expected);
+ sonarLintXml.ToStringCallCount.Should().Be(1, "file should not have been read again");
}
// Until https://github.com/SonarSource/sonar-dotnet/issues/2228, we were considering a file as generated if the word "generated" was contained inside a region.
@@ -329,26 +327,106 @@ public class GenericAttribute : Attribute { }
VerifyEmpty("test.cs", sourceCs, new CS.EmptyStatement());
}
- private static DummySourceText CreateSonarLintXml(bool analyzeGeneratedCSharp) =>
- new($"""
-
-
-
-
- dummy
- false
-
-
- sonar.cs.analyzeGeneratedCode
- {analyzeGeneratedCSharp.ToString().ToLower()}
-
-
- sonar.vbnet.analyzeGeneratedCode
- true
-
-
-
- """);
+ [DataTestMethod]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Product, false)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Product, true)]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Test, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Test, true)]
+ public void ShouldAnalyzeTree_Exclusions_ReturnExpected(string filePath, string[] exclusions, ProjectType projectType, bool expectedResult) =>
+ ShouldAnalyzeTree_WithExclusionInclusionParametersSet_ReturnsTrueForIncludedFilesOnly(filePath, projectType, expectedResult, exclusions: exclusions);
+
+ [DataTestMethod]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Product, false)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Product, true)]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Test, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Test, true)]
+ public void ShouldAnalyzeTree_GlobalExclusions_ReturnExpected(string filePath, string[] globalExclusions, ProjectType projectType, bool expectedResult) =>
+ ShouldAnalyzeTree_WithExclusionInclusionParametersSet_ReturnsTrueForIncludedFilesOnly(filePath, projectType, expectedResult, globalExclusions: globalExclusions);
+
+ [DataTestMethod]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Product, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Product, true)]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Test, false)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Test, true)]
+ public void ShouldAnalyzeTree_TestExclusions_ReturnExpected(string filePath, string[] testExclusions, ProjectType projectType, bool expectedResult) =>
+ ShouldAnalyzeTree_WithExclusionInclusionParametersSet_ReturnsTrueForIncludedFilesOnly(filePath, projectType, expectedResult, testExclusions: testExclusions);
+
+ [DataTestMethod]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Product, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Product, true)]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Test, false)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Test, true)]
+ public void ShouldAnalyzeTree_GlobalTestExclusions_ReturnExpected(string filePath, string[] globalTestExclusions, ProjectType projectType, bool expectedResult) =>
+ ShouldAnalyzeTree_WithExclusionInclusionParametersSet_ReturnsTrueForIncludedFilesOnly(filePath, projectType, expectedResult, globalTestExclusions: globalTestExclusions);
+
+ [DataTestMethod]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Product, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Product, false)]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Test, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Test, true)]
+ public void ShouldAnalyzeTree_Inclusions_ReturnExpected(string filePath, string[] inclusions, ProjectType projectType, bool expectedResult) =>
+ ShouldAnalyzeTree_WithExclusionInclusionParametersSet_ReturnsTrueForIncludedFilesOnly(filePath, projectType, expectedResult, inclusions: inclusions);
+
+ [DataTestMethod]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Product, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Product, true)]
+ [DataRow("Foo", new string[] { "Foo" }, ProjectType.Test, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, ProjectType.Test, false)]
+ public void ShouldAnalyzeTree_TestInclusions_ReturnExpected(string filePath, string[] testInclusions, ProjectType projectType, bool expectedResult) =>
+ ShouldAnalyzeTree_WithExclusionInclusionParametersSet_ReturnsTrueForIncludedFilesOnly(filePath, projectType, expectedResult, testInclusions: testInclusions);
+
+ [DataTestMethod]
+ [DataRow("Foo", new string[] { "Foo" }, new string[] { "Foo" }, false)]
+ [DataRow("Foo", new string[] { "NotFoo" }, new string[] { "Foo" }, false)]
+ [DataRow("Foo", new string[] { "Foo" }, new string[] { "NotFoo" }, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, new string[] { "NotFoo" }, false)]
+ public void ShouldAnalyzeTree_MixedInput_ProductProject_ReturnExpected(string filePath, string[] inclusions, string[] exclusions, bool expectedResult) =>
+ ShouldAnalyzeTree_WithExclusionInclusionParametersSet_ReturnsTrueForIncludedFilesOnly(filePath, ProjectType.Product, expectedResult, inclusions: inclusions, exclusions: exclusions);
+
+ [DataTestMethod]
+ [DataRow("Foo", new string[] { "Foo" }, new string[] { "Foo" }, false)]
+ [DataRow("Foo", new string[] { "NotFoo" }, new string[] { "Foo" }, false)]
+ [DataRow("Foo", new string[] { "Foo" }, new string[] { "NotFoo" }, true)]
+ [DataRow("Foo", new string[] { "NotFoo" }, new string[] { "NotFoo" }, false)]
+ public void ShouldAnalyzeTree_MixedInput_TestProject_ReturnExpected(string filePath, string[] testInclusions, string[] testExclusions, bool expectedResult) =>
+ ShouldAnalyzeTree_WithExclusionInclusionParametersSet_ReturnsTrueForIncludedFilesOnly(filePath, ProjectType.Test, expectedResult, testInclusions: testInclusions, testExclusions: testExclusions);
+
+ private void ShouldAnalyzeTree_WithExclusionInclusionParametersSet_ReturnsTrueForIncludedFilesOnly(
+ string fileName,
+ ProjectType projectType,
+ bool shouldAnalyze,
+ string language = LanguageNames.CSharp,
+ string[] exclusions = null,
+ string[] inclusions = null,
+ string[] globalExclusions = null,
+ string[] testExclusions = null,
+ string[] testInclusions = null,
+ string[] globalTestExclusions = null)
+ {
+ var analyzerLanguage = language == LanguageNames.CSharp ? AnalyzerLanguage.CSharp : AnalyzerLanguage.VisualBasic;
+ var sonarLintXml = AnalysisScaffolding.CreateSonarLintXml(
+ TestContext,
+ language: language,
+ exclusions: exclusions,
+ inclusions: inclusions,
+ globalExclusions: globalExclusions,
+ testExclusions: testExclusions,
+ testInclusions: testInclusions,
+ globalTestExclusions: globalTestExclusions);
+ var options = AnalysisScaffolding.CreateOptions(sonarLintXml);
+
+ var compilation = SolutionBuilder
+ .Create()
+ .AddProject(analyzerLanguage, createExtraEmptyFile: false)
+ .AddReferences(TestHelper.ProjectTypeReference(projectType))
+ .AddSnippet(string.Empty, fileName)
+ .GetCompilation();
+ var tree = compilation.SyntaxTrees.Single(x => x.FilePath.Contains(fileName));
+ var sut = CreateSut(compilation, options);
+
+ GeneratedCodeRecognizer codeRecognizer = language == LanguageNames.CSharp ? CSharpGeneratedCodeRecognizer.Instance : VisualBasicGeneratedCodeRecognizer.Instance;
+ sut.ShouldAnalyzeTree(tree, codeRecognizer).Should().Be(shouldAnalyze);
+ }
private AnalyzerOptions CreateOptions(string[] unchangedFiles) =>
AnalysisScaffolding.CreateOptions(AnalysisScaffolding.CreateSonarProjectConfigWithUnchangedFiles(TestContext, unchangedFiles));
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs
index d15e6b096af..5f518397a40 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs
@@ -19,6 +19,7 @@
*/
using System.IO;
+using System.Xml.Linq;
using Microsoft.CodeAnalysis.Text;
using Moq;
using SonarAnalyzer.AnalysisContext;
@@ -80,6 +81,45 @@ public static string CreateSonarProjectConfigWithFilesToAnalyze(TestContext cont
public static string CreateSonarProjectConfig(TestContext context, ProjectType projectType, bool isScannerRun = true) =>
CreateSonarProjectConfig(context, "ProjectType", projectType.ToString(), isScannerRun);
+ public static string CreateSonarLintXml(
+ TestContext context,
+ string language = LanguageNames.CSharp,
+ bool analyzeGeneratedCode = false,
+ string[] exclusions = null,
+ string[] inclusions = null,
+ string[] globalExclusions = null,
+ string[] testExclusions = null,
+ string[] testInclusions = null,
+ string[] globalTestExclusions = null) =>
+ TestHelper.WriteFile(context, "SonarLint.xml", GenerateSonarLintXmlContent(language, analyzeGeneratedCode, exclusions, inclusions, globalExclusions, testExclusions, testInclusions, globalTestExclusions));
+
+ public static string GenerateSonarLintXmlContent(
+ string language = LanguageNames.CSharp,
+ bool analyzeGeneratedCode = false,
+ string[] exclusions = null,
+ string[] inclusions = null,
+ string[] globalExclusions = null,
+ string[] testExclusions = null,
+ string[] testInclusions = null,
+ string[] globalTestExclusions = null) =>
+ new XDocument(
+ new XDeclaration("1.0", "utf-8", "yes"),
+ new XElement("AnalysisInput",
+ new XElement("Settings",
+ CreateSetting($"sonar.{(language == LanguageNames.CSharp ? "cs" : "vbnet")}.analyzeGeneratedCode", analyzeGeneratedCode.ToString()),
+ CreateSetting("sonar.exclusions", ConcatenateStringArray(exclusions)),
+ CreateSetting("sonar.inclusions", ConcatenateStringArray(inclusions)),
+ CreateSetting("sonar.global.exclusions", ConcatenateStringArray(globalExclusions)),
+ CreateSetting("sonar.test.exclusions", ConcatenateStringArray(testExclusions)),
+ CreateSetting("sonar.test.inclusions", ConcatenateStringArray(testInclusions)),
+ CreateSetting("sonar.global.test.exclusions", ConcatenateStringArray(globalTestExclusions))))).ToString();
+
+ private static XElement CreateSetting(string key, string value) =>
+ new("Setting", new XElement("Key", key), new XElement("Value", value));
+
+ private static string ConcatenateStringArray(string[] array) =>
+ string.Join(",", array ?? Array.Empty());
+
private static string CreateSonarProjectConfig(TestContext context, string element, string value, bool isScannerRun, string analysisConfigPath = null)
{
var sonarProjectConfigPath = TestHelper.TestPath(context, "SonarProjectConfig.xml");
From 36819f906ca0dd9ec0fb201fd4b98c92b1cf4c43 Mon Sep 17 00:00:00 2001
From: Cristian Ambrosini
<114916336+cristian-ambrosini-sonarsource@users.noreply.github.com>
Date: Fri, 10 Mar 2023 10:28:57 +0100
Subject: [PATCH 06/14] Use SonarLint data class to provide the rule parameters
to the rules (#6888)
---
.../ParametrizedDiagnosticAnalyzer.cs | 2 +-
.../Helpers/ParameterLoader.cs | 85 +----------
.../Helpers/SonarLintXmlReader.cs | 28 ++--
.../Helpers/ParameterLoaderTest.cs | 139 ++++++++----------
.../Helpers/SonarLintXmlReaderTest.cs | 9 ++
.../TestFramework/AnalysisScaffolding.cs | 35 ++++-
6 files changed, 126 insertions(+), 172 deletions(-)
diff --git a/analyzers/src/SonarAnalyzer.Common/DiagnosticAnalyzer/ParametrizedDiagnosticAnalyzer.cs b/analyzers/src/SonarAnalyzer.Common/DiagnosticAnalyzer/ParametrizedDiagnosticAnalyzer.cs
index c1ae6279f85..cb3d06010dd 100644
--- a/analyzers/src/SonarAnalyzer.Common/DiagnosticAnalyzer/ParametrizedDiagnosticAnalyzer.cs
+++ b/analyzers/src/SonarAnalyzer.Common/DiagnosticAnalyzer/ParametrizedDiagnosticAnalyzer.cs
@@ -32,7 +32,7 @@ protected sealed override void Initialize(SonarAnalysisContext context)
context.RegisterCompilationStartAction(
c =>
{
- ParameterLoader.SetParameterValues(this, c.Options);
+ ParameterLoader.SetParameterValues(this, c.SonarLintFile());
parameterContext.ExecutePostponedActions(c);
});
}
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/ParameterLoader.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/ParameterLoader.cs
index b472cd3e53e..98772ed382c 100644
--- a/analyzers/src/SonarAnalyzer.Common/Helpers/ParameterLoader.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/ParameterLoader.cs
@@ -19,10 +19,7 @@
*/
using System.Globalization;
-using System.IO;
using System.Reflection;
-using System.Xml;
-using System.Xml.Linq;
namespace SonarAnalyzer.Helpers
{
@@ -39,84 +36,30 @@ internal static class ParameterLoader
* - diffing the contents of the configuration file
* - associating the file with a unique identifier for the build project
*/
- internal static void SetParameterValues(ParametrizedDiagnosticAnalyzer parameteredAnalyzer,
- AnalyzerOptions options)
+ internal static void SetParameterValues(ParametrizedDiagnosticAnalyzer parameteredAnalyzer, SonarLintXmlReader sonarLintXml)
{
- var sonarLintXml = options.SonarLintXml();
- if (sonarLintXml == null)
- {
- return;
- }
-
- var parameters = ParseParameters(sonarLintXml);
- if (parameters.IsEmpty)
+ if (!sonarLintXml.ParametrizedRules.Any())
{
return;
}
var propertyParameterPairs = parameteredAnalyzer.GetType()
.GetRuntimeProperties()
- .Select(p => new { Property = p, Descriptor = p.GetCustomAttributes().SingleOrDefault() })
- .Where(p => p.Descriptor != null);
+ .Select(x => new { Property = x, Descriptor = x.GetCustomAttributes().SingleOrDefault() })
+ .Where(x => x.Descriptor is not null);
var ids = new HashSet(parameteredAnalyzer.SupportedDiagnostics.Select(diagnostic => diagnostic.Id));
foreach (var propertyParameterPair in propertyParameterPairs)
{
- var parameter = parameters
- .FirstOrDefault(p => ids.Contains(p.RuleId));
-
- var parameterValue = parameter?.ParameterValues
- .FirstOrDefault(pv => pv.ParameterKey == propertyParameterPair.Descriptor.Key);
-
- if (TryConvertToParameterType(parameterValue?.ParameterValue, propertyParameterPair.Descriptor.Type, out var value))
+ var parameter = sonarLintXml.ParametrizedRules.FirstOrDefault(x => ids.Contains(x.Key));
+ var parameterValue = parameter?.Parameters.FirstOrDefault(x => x.Key == propertyParameterPair.Descriptor.Key);
+ if (TryConvertToParameterType(parameterValue?.Value, propertyParameterPair.Descriptor.Type, out var value))
{
propertyParameterPair.Property.SetValue(parameteredAnalyzer, value);
}
}
}
- private static ImmutableList ParseParameters(AdditionalText sonarLintXml)
- {
- try
- {
- var xml = XDocument.Parse(sonarLintXml.GetText().ToString());
- return ParseParameters(xml);
- }
- catch (Exception ex) when (ex is IOException || ex is XmlException)
- {
- // cannot log exception
- return ImmutableList.Create();
- }
- }
-
- private static ImmutableList ParseParameters(XContainer xml)
- {
- var builder = ImmutableList.CreateBuilder();
- foreach (var rule in xml.Descendants("Rule").Where(e => e.Elements("Parameters").Any()))
- {
- var analyzerId = rule.Elements("Key").Single().Value;
-
- var parameterValues = rule
- .Elements("Parameters").Single()
- .Elements("Parameter")
- .Select(e => new RuleParameterValue
- {
- ParameterKey = e.Elements("Key").Single().Value,
- ParameterValue = e.Elements("Value").Single().Value
- });
-
- var pvs = new RuleParameterValues
- {
- RuleId = analyzerId
- };
- pvs.ParameterValues.AddRange(parameterValues);
-
- builder.Add(pvs);
- }
-
- return builder.ToImmutable();
- }
-
private static bool TryConvertToParameterType(string parameter, PropertyType type, out object result)
{
if (parameter == null)
@@ -144,19 +87,5 @@ private static bool TryConvertToParameterType(string parameter, PropertyType typ
return false;
}
}
-
- private sealed class RuleParameterValues
- {
- public string RuleId { get; set; }
-
- public List ParameterValues { get; } = new List();
- }
-
- private sealed class RuleParameterValue
- {
- public string ParameterKey { get; set; }
-
- public string ParameterValue { get; set; }
- }
}
}
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
index 8c717d7a31d..83fb3a13080 100644
--- a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
@@ -34,30 +34,33 @@ public class SonarLintXmlReader
private readonly string propertyLanguage;
private bool? ignoreHeaderComments;
- public bool IgnoreHeaderComments => ignoreHeaderComments ??= ReadBoolean(ReadProperty($"sonar.{propertyLanguage}.ignoreHeaderComments"));
+ public bool IgnoreHeaderComments => ignoreHeaderComments ??= ReadBoolean(ReadSettingsProperty($"sonar.{propertyLanguage}.ignoreHeaderComments"));
private bool? analyzeGeneratedCode;
- public bool AnalyzeGeneratedCode => analyzeGeneratedCode ??= ReadBoolean(ReadProperty($"sonar.{propertyLanguage}.analyzeGeneratedCode"));
+ public bool AnalyzeGeneratedCode => analyzeGeneratedCode ??= ReadBoolean(ReadSettingsProperty($"sonar.{propertyLanguage}.analyzeGeneratedCode"));
private string[] exclusions;
- public string[] Exclusions => exclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.exclusions"));
+ public string[] Exclusions => exclusions ??= ReadCommaSeparatedArray(ReadSettingsProperty("sonar.exclusions"));
private string[] inclusions;
- public string[] Inclusions => inclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.inclusions"));
+ public string[] Inclusions => inclusions ??= ReadCommaSeparatedArray(ReadSettingsProperty("sonar.inclusions"));
private string[] globalExclusions;
- public string[] GlobalExclusions => globalExclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.global.exclusions"));
+ public string[] GlobalExclusions => globalExclusions ??= ReadCommaSeparatedArray(ReadSettingsProperty("sonar.global.exclusions"));
private string[] testExclusions;
- public string[] TestExclusions => testExclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.test.exclusions"));
+ public string[] TestExclusions => testExclusions ??= ReadCommaSeparatedArray(ReadSettingsProperty("sonar.test.exclusions"));
private string[] testInclusions;
- public string[] TestInclusions => testInclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.test.inclusions"));
+ public string[] TestInclusions => testInclusions ??= ReadCommaSeparatedArray(ReadSettingsProperty("sonar.test.inclusions"));
private string[] globalTestExclusions;
- public string[] GlobalTestExclusions => globalTestExclusions ??= ReadCommaSeparatedArray(ReadProperty("sonar.global.test.exclusions"));
+ public string[] GlobalTestExclusions => globalTestExclusions ??= ReadCommaSeparatedArray(ReadSettingsProperty("sonar.global.test.exclusions"));
- public SonarLintXmlReader(SourceText sonarLintXml, string language)
+ private List parametrizedRules;
+ public List ParametrizedRules => parametrizedRules ??= ReadRuleParameters();
+
+ public SonarLintXmlReader(SourceText sonarLintXml, string language = LanguageNames.CSharp)
{
this.sonarLintXml = sonarLintXml == null ? SonarLintXml.Empty : ParseContent(sonarLintXml);
propertyLanguage = language == LanguageNames.CSharp ? "cs" : "vbnet";
@@ -80,7 +83,12 @@ private static SonarLintXml ParseContent(SourceText sonarLintXml)
}
}
- private string ReadProperty(string property) =>
+ private List ReadRuleParameters() =>
+ sonarLintXml is { Rules: { } rules }
+ ? rules.Where(x => x.Parameters.Any()).ToList()
+ : new();
+
+ private string ReadSettingsProperty(string property) =>
sonarLintXml is { Settings: { } settings }
? settings.Where(x => x.Key.Equals(property)).Select(x => x.Value).FirstOrDefault()
: string.Empty;
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
index 646ceb2fb34..bcf46ee97b6 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
@@ -20,6 +20,8 @@
using System.IO;
using Microsoft.CodeAnalysis.Text;
+using SonarAnalyzer.AnalysisContext;
+using SonarAnalyzer.Common;
using SonarAnalyzer.Rules.CSharp;
namespace SonarAnalyzer.UnitTest.Helpers
@@ -27,17 +29,19 @@ namespace SonarAnalyzer.UnitTest.Helpers
[TestClass]
public class ParameterLoaderTest
{
+ public TestContext TestContext { get; set; }
+
[TestMethod]
[DataRow("path//aSonarLint.xml")] // different name
[DataRow("path//SonarLint.xmla")] // different extension
public void SetParameterValues_WhenNoSonarLintIsGiven_DoesNotPopulateParameters(string filePath)
{
// Arrange
- var options = AnalysisScaffolding.CreateOptions(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLint.xml")));
+ var compilation = CreateCompilationWithOption(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLint.xml")));
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
analyzer.Maximum.Should().Be(3); // Default value
@@ -49,11 +53,11 @@ public void SetParameterValues_WhenNoSonarLintIsGiven_DoesNotPopulateParameters(
public void SetParameterValues_WhenGivenValidSonarLintFilePath_PopulatesProperties(string filePath)
{
// Arrange
- var options = AnalysisScaffolding.CreateOptions(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLint.xml")));
+ var compilation = CreateCompilationWithOption(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLint.xml")));
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
analyzer.Maximum.Should().Be(1); // Value from the xml file
@@ -63,11 +67,11 @@ public void SetParameterValues_WhenGivenValidSonarLintFilePath_PopulatesProperti
public void SetParameterValues_WhenGivenSonarLintFileHasIntParameterType_PopulatesProperties()
{
// Arrange
- var options = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\SonarLint.xml");
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
analyzer.Maximum.Should().Be(1); // Value from the xml file
@@ -77,11 +81,11 @@ public void SetParameterValues_WhenGivenSonarLintFileHasIntParameterType_Populat
public void SetParameterValues_WhenGivenSonarLintFileHasStringParameterType_OnlyOneParameter_PopulatesProperty()
{
// Arrange
- var options = AnalysisScaffolding.CreateOptions("ResourceTests\\RuleWithStringParameter\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\RuleWithStringParameter\\SonarLint.xml");
var analyzer = new EnumNameShouldFollowRegex(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
analyzer.FlagsEnumNamePattern.Should().Be("1"); // value from XML file
@@ -91,11 +95,11 @@ public void SetParameterValues_WhenGivenSonarLintFileHasStringParameterType_Only
public void SetParameterValues_WhenGivenSonarLintFileHasBooleanParameterType_OnlyOneParameter_PopulatesProperty()
{
// Arrange
- var options = AnalysisScaffolding.CreateOptions("ResourceTests\\RuleWithBooleanParameter\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\RuleWithBooleanParameter\\SonarLint.xml");
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
analyzer.IsRegularExpression.Should().BeTrue(); // value from XML file
@@ -105,85 +109,54 @@ public void SetParameterValues_WhenGivenSonarLintFileHasBooleanParameterType_Onl
public void SetParameterValues_WhenGivenValidSonarLintFileAndDoesNotContainAnalyzerParameters_DoesNotPopulateProperties()
{
// Arrange
- var options = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\SonarLint.xml");
var analyzer = new LineLength(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
analyzer.Maximum.Should().Be(200); // Default value
}
- [TestMethod]
- public void SetParameterValues_WithNonExistentPath_UsesInMemoryText()
- {
- // Arrange
- const string fakeSonarLintXmlFilePath = "ThisPathDoesNotExist\\SonarLint.xml";
- const string sonarLintXmlContent = @"
-
-
-
-
- S1067
-
-
- max
- 1
-
-
-
-
-
-
-";
-
- var options = AnalysisScaffolding.CreateOptions(fakeSonarLintXmlFilePath, SourceText.From(sonarLintXmlContent));
- var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
-
- // Act
- ParameterLoader.SetParameterValues(analyzer, options);
-
- // Assert
- analyzer.Maximum.Should().Be(1); // In-memory value
- }
-
[TestMethod]
public void SetParameterValues_CalledTwiceAfterChangeInConfigFile_UpdatesProperties()
{
// Arrange
- const string fakeSonarLintXmlFilePath = "ThisPathDoesNotExist\\SonarLint.xml";
- const string originalSonarLintXmlContent = @"
-
-
-
-
- S1067
-
-
- max
- 1
-
-
-
-
-
-
-";
-
- var options = AnalysisScaffolding.CreateOptions(fakeSonarLintXmlFilePath, SourceText.From(originalSonarLintXmlContent));
+ var maxValue = 1;
+ var ruleParameters = new List()
+ {
+ new SonarLintXmlRule()
+ {
+ Key = "S1067",
+ Parameters = new List()
+ {
+ new SonarLintXmlKeyValuePair()
+ {
+ Key = "max",
+ Value = maxValue.ToString()
+ }
+ }
+ }
+ };
+ var sonarLintXml = AnalysisScaffolding.GenerateSonarLintXmlContent(rulesParameters: ruleParameters);
+ var filePath = TestHelper.WriteFile(TestContext, "SonarLint.xml", sonarLintXml);
+ var compilation = CreateCompilationWithOption(filePath);
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
- analyzer.Maximum.Should().Be(1);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ analyzer.Maximum.Should().Be(maxValue);
// Modify the in-memory additional file
- var modifiedSonarLintXmlContent = originalSonarLintXmlContent.Replace("1", "42");
- var modifiedOptions = AnalysisScaffolding.CreateOptions(fakeSonarLintXmlFilePath, SourceText.From(modifiedSonarLintXmlContent));
-
- ParameterLoader.SetParameterValues(analyzer, modifiedOptions);
- analyzer.Maximum.Should().Be(42);
+ maxValue = 42;
+ ruleParameters.First().Parameters.First().Value = maxValue.ToString();
+ var modifiedSonarLintXml = AnalysisScaffolding.GenerateSonarLintXmlContent(rulesParameters: ruleParameters);
+ var modifiedFilePath = TestHelper.WriteFile(TestContext, "SonarLint.xml", modifiedSonarLintXml);
+ compilation = CreateCompilationWithOption(modifiedFilePath);
+
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ analyzer.Maximum.Should().Be(maxValue);
}
[TestMethod]
@@ -193,11 +166,11 @@ public void SetParameterValues_CalledTwiceAfterChangeInConfigFile_UpdatesPropert
public void SetParameterValues_WithMalformedXml_DoesNotPopulateProperties(string sonarLintXmlContent)
{
// Arrange
- var options = AnalysisScaffolding.CreateOptions("fakePath\\SonarLint.xml", SourceText.From(sonarLintXmlContent));
+ var compilation = CreateCompilationWithOption("fakePath\\SonarLint.xml", SourceText.From(sonarLintXmlContent));
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
analyzer.Maximum.Should().Be(3); // Default value
@@ -207,11 +180,11 @@ public void SetParameterValues_WithMalformedXml_DoesNotPopulateProperties(string
public void SetParameterValues_WithWrongPropertyType_StringInsteadOfInt_DoesNotPopulateProperties()
{
// Arrange
- var options = AnalysisScaffolding.CreateOptions("ResourceTests\\StringInsteadOfInt\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\StringInsteadOfInt\\SonarLint.xml");
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
analyzer.Maximum.Should().Be(3); // Default value
@@ -221,14 +194,24 @@ public void SetParameterValues_WithWrongPropertyType_StringInsteadOfInt_DoesNotP
public void SetParameterValues_WithWrongPropertyType_StringInsteadOfBoolean_DoesNotPopulateProperties()
{
// Arrange
- var options = AnalysisScaffolding.CreateOptions("ResourceTests\\StringInsteadOfBoolean\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\StringInsteadOfBoolean\\SonarLint.xml");
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, options);
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
analyzer.IsRegularExpression.Should().BeFalse(); // Default value
}
+
+ private static SonarCompilationReportingContext CreateCompilationWithOption(string filePath, SourceText text = null)
+ {
+ var options = text is null
+ ? AnalysisScaffolding.CreateOptions(filePath)
+ : AnalysisScaffolding.CreateOptions(filePath, text);
+ var compilation = SolutionBuilder.Create().AddProject(AnalyzerLanguage.CSharp).GetCompilation();
+ var compilationContext = new CompilationAnalysisContext(compilation, options, _ => { }, _ => true, default);
+ return new(AnalysisScaffolding.CreateSonarAnalysisContext(), compilationContext);
+ }
}
}
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
index b8502beb93f..737148185f8 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
@@ -41,6 +41,13 @@ public void SonarLintXmlReader_WhenAllValuesAreSet_ExpectedValues(string languag
AssertArrayContent(sut.TestInclusions, nameof(sut.TestInclusions));
AssertArrayContent(sut.GlobalTestExclusions, nameof(sut.GlobalTestExclusions));
+ sut.ParametrizedRules.Should().HaveCount(8);
+ var rule = sut.ParametrizedRules.First(x => x.Key.Equals("S2342"));
+ rule.Parameters[0].Key.Should().Be("format");
+ rule.Parameters[0].Value.Should().Be("^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$");
+ rule.Parameters[1].Key.Should().Be("flagsAttributeFormat");
+ rule.Parameters[1].Value.Should().Be("^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$");
+
static void AssertArrayContent(string[] array, string folder)
{
array.Should().HaveCount(2);
@@ -61,6 +68,7 @@ public void SonarLintXmlReader_PartiallyMissingProperties_ExpectedAndDefaultValu
sut.TestExclusions.Should().NotBeNull().And.HaveCount(0);
sut.TestInclusions.Should().NotBeNull().And.HaveCount(0);
sut.GlobalTestExclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.ParametrizedRules.Should().NotBeNull().And.HaveCount(0);
}
[DataTestMethod]
@@ -92,6 +100,7 @@ private static void CheckSonarLintXmlReaderDefaultValues(SonarLintXmlReader sut)
sut.TestExclusions.Should().NotBeNull().And.HaveCount(0);
sut.TestInclusions.Should().NotBeNull().And.HaveCount(0);
sut.GlobalTestExclusions.Should().NotBeNull().And.HaveCount(0);
+ sut.ParametrizedRules.Should().NotBeNull().And.HaveCount(0);
}
private static void AssertArrayContent(string[] array, string folder)
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs
index 5f518397a40..aa476e1131e 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs
@@ -19,6 +19,7 @@
*/
using System.IO;
+using System.Runtime.CompilerServices;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.Text;
using Moq;
@@ -90,8 +91,9 @@ public static string CreateSonarProjectConfigWithFilesToAnalyze(TestContext cont
string[] globalExclusions = null,
string[] testExclusions = null,
string[] testInclusions = null,
- string[] globalTestExclusions = null) =>
- TestHelper.WriteFile(context, "SonarLint.xml", GenerateSonarLintXmlContent(language, analyzeGeneratedCode, exclusions, inclusions, globalExclusions, testExclusions, testInclusions, globalTestExclusions));
+ string[] globalTestExclusions = null,
+ List rulesParameters = null) =>
+ TestHelper.WriteFile(context, "SonarLint.xml", GenerateSonarLintXmlContent(language, analyzeGeneratedCode, exclusions, inclusions, globalExclusions, testExclusions, testInclusions, globalTestExclusions, rulesParameters));
public static string GenerateSonarLintXmlContent(
string language = LanguageNames.CSharp,
@@ -101,7 +103,8 @@ public static string CreateSonarProjectConfigWithFilesToAnalyze(TestContext cont
string[] globalExclusions = null,
string[] testExclusions = null,
string[] testInclusions = null,
- string[] globalTestExclusions = null) =>
+ string[] globalTestExclusions = null,
+ List rulesParameters = null) =>
new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("AnalysisInput",
@@ -112,10 +115,32 @@ public static string CreateSonarProjectConfigWithFilesToAnalyze(TestContext cont
CreateSetting("sonar.global.exclusions", ConcatenateStringArray(globalExclusions)),
CreateSetting("sonar.test.exclusions", ConcatenateStringArray(testExclusions)),
CreateSetting("sonar.test.inclusions", ConcatenateStringArray(testInclusions)),
- CreateSetting("sonar.global.test.exclusions", ConcatenateStringArray(globalTestExclusions))))).ToString();
+ CreateSetting("sonar.global.test.exclusions", ConcatenateStringArray(globalTestExclusions))),
+ new XElement("Rules", CreateRules(rulesParameters)))).ToString();
+
+ private static IEnumerable CreateRules(List ruleParameters)
+ {
+ foreach (var rule in ruleParameters ?? new())
+ {
+ yield return CreateRule(rule);
+ }
+ }
+
+ private static XElement CreateRule(SonarLintXmlRule rule)
+ {
+ List elements = new();
+ foreach (var param in rule.Parameters)
+ {
+ elements.Add(CreateKeyValuePair("Parameter", param.Key, param.Value));
+ }
+ return new("Rule", new XElement("Key", rule.Key), new XElement("Parameters", elements));
+ }
private static XElement CreateSetting(string key, string value) =>
- new("Setting", new XElement("Key", key), new XElement("Value", value));
+ CreateKeyValuePair("Setting", key, value);
+
+ private static XElement CreateKeyValuePair(string containerName, string key, string value) =>
+ new(containerName, new XElement("Key", key), new XElement("Value", value));
private static string ConcatenateStringArray(string[] array) =>
string.Join(",", array ?? Array.Empty());
From bc50fb056bd1080f7751187868aa2eaa596dd443 Mon Sep 17 00:00:00 2001
From: Mary Georgiou
<89914005+mary-georgiou-sonarsource@users.noreply.github.com>
Date: Fri, 10 Mar 2023 14:56:39 +0100
Subject: [PATCH 07/14] Add SonarLint exclusion/inclusion IT (#6884)
---
...SonarAnalyzer.Testing.ImportBefore.targets | 2 +
.../config/SonarLintExclusions/SonarLint.xml | 40 +++++++++++++++++++
.../SonarLintExclusions--net7.0-S2094.json | 17 ++++++++
.../SonarLintExclusions--net7.0-S3990.json | 9 +++++
.../SonarLintExclusions--net7.0-S3992.json | 9 +++++
...SonarLintExclusionsTest--net7.0-S2699.json | 17 ++++++++
analyzers/its/regression-test.ps1 | 3 +-
.../SonarLintExclusions.sln | 36 +++++++++++++++++
.../Included/ExcludedByExclusion.cs | 4 ++
.../Included/ExcludedByExclusion2.cs | 4 ++
.../Included/ExcludedByGlobalExclusion.cs | 4 ++
.../SonarLintExclusions/Included/Included.cs | 4 ++
.../SonarLintExclusions/NotIncluded.cs | 4 ++
.../SonarLintExclusions.csproj | 8 ++++
.../IncludedTest/ExcludedByExclusionTest.cs | 10 +++++
.../ExcludedByGlobalExclusionTest.cs | 10 +++++
.../IncludedTest/IncludedTest.cs | 10 +++++
.../NotIncludedTest.cs | 10 +++++
.../SonarLintExclusionsTest.csproj | 15 +++++++
.../sources/SonarLintExclusions/global.json | 6 +++
20 files changed, 221 insertions(+), 1 deletion(-)
create mode 100644 analyzers/its/config/SonarLintExclusions/SonarLint.xml
create mode 100644 analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S2094.json
create mode 100644 analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S3990.json
create mode 100644 analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S3992.json
create mode 100644 analyzers/its/expected/SonarLintExclusions/SonarLintExclusionsTest--net7.0-S2699.json
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusions.sln
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByExclusion.cs
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByExclusion2.cs
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByGlobalExclusion.cs
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/Included.cs
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/NotIncluded.cs
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/SonarLintExclusions.csproj
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/ExcludedByExclusionTest.cs
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/ExcludedByGlobalExclusionTest.cs
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/IncludedTest.cs
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/NotIncludedTest.cs
create mode 100644 analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/SonarLintExclusionsTest.csproj
create mode 100644 analyzers/its/sources/SonarLintExclusions/global.json
diff --git a/analyzers/its/SonarAnalyzer.Testing.ImportBefore.targets b/analyzers/its/SonarAnalyzer.Testing.ImportBefore.targets
index f3fda742c51..ea85c04a441 100644
--- a/analyzers/its/SonarAnalyzer.Testing.ImportBefore.targets
+++ b/analyzers/its/SonarAnalyzer.Testing.ImportBefore.targets
@@ -11,6 +11,8 @@
Product
Test
+
+ Unknown
diff --git a/analyzers/its/config/SonarLintExclusions/SonarLint.xml b/analyzers/its/config/SonarLintExclusions/SonarLint.xml
new file mode 100644
index 00000000000..be8726ef80a
--- /dev/null
+++ b/analyzers/its/config/SonarLintExclusions/SonarLint.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ sonar.cs.ignoreHeaderComments
+ true
+
+
+ sonar.vbnet.ignoreHeaderComments
+ true
+
+
+ sonar.inclusions
+ **/Included/*.cs
+
+
+ sonar.exclusions
+ **/ExcludedByExclusion.cs,**/ExcludedByExclusion2.cs
+
+
+ sonar.global.exclusions
+ **/ExcludedByGlobalExclusion.cs
+
+
+
+ sonar.test.inclusions
+ **/IncludedTest/*.cs
+
+
+ sonar.test.exclusions
+ **/ExcludedByExclusionTest.cs
+
+
+ sonar.global.test.exclusions
+ **/ExcludedByGlobalExclusionTest.cs
+
+
+
\ No newline at end of file
diff --git a/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S2094.json b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S2094.json
new file mode 100644
index 00000000000..e86aa12d401
--- /dev/null
+++ b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S2094.json
@@ -0,0 +1,17 @@
+{
+"issues": [
+{
+"id": "S2094",
+"message": "Remove this empty class, write its code or make it an "interface".",
+"location": {
+"uri": "sources\SonarLintExclusions\SonarLintExclusions\Included\Included.cs",
+"region": {
+"startLine": 3,
+"startColumn": 18,
+"endLine": 3,
+"endColumn": 26
+}
+}
+}
+]
+}
diff --git a/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S3990.json b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S3990.json
new file mode 100644
index 00000000000..17786f2ed3f
--- /dev/null
+++ b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S3990.json
@@ -0,0 +1,9 @@
+{
+"issues": [
+{
+"id": "S3990",
+"message": "Provide a 'CLSCompliant' attribute for assembly 'SonarLintExclusions'.",
+"location": null
+}
+]
+}
diff --git a/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S3992.json b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S3992.json
new file mode 100644
index 00000000000..dfd144e2a2e
--- /dev/null
+++ b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S3992.json
@@ -0,0 +1,9 @@
+{
+"issues": [
+{
+"id": "S3992",
+"message": "Provide a 'ComVisible' attribute for assembly 'SonarLintExclusions'.",
+"location": null
+}
+]
+}
diff --git a/analyzers/its/expected/SonarLintExclusions/SonarLintExclusionsTest--net7.0-S2699.json b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusionsTest--net7.0-S2699.json
new file mode 100644
index 00000000000..9a66c44306c
--- /dev/null
+++ b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusionsTest--net7.0-S2699.json
@@ -0,0 +1,17 @@
+{
+"issues": [
+{
+"id": "S2699",
+"message": "Add at least one assertion to this test case.",
+"location": {
+"uri": "sources\SonarLintExclusions\SonarLintExclusionsTest\IncludedTest\IncludedTest.cs",
+"region": {
+"startLine": 8,
+"startColumn": 21,
+"endLine": 8,
+"endColumn": 32
+}
+}
+}
+]
+}
diff --git a/analyzers/its/regression-test.ps1 b/analyzers/its/regression-test.ps1
index ad7cf9d8057..513681eedbc 100644
--- a/analyzers/its/regression-test.ps1
+++ b/analyzers/its/regression-test.ps1
@@ -12,7 +12,7 @@ param
$ruleId,
[Parameter(HelpMessage = "The name of single project to build. If ommited, all projects will be build.")]
- [ValidateSet("AnalyzeGenerated.CS", "AnalyzeGenerated.VB", "akka.net", "Automapper", "Ember-MM", "Nancy", "NetCore31", "Net5", "Net6", "Net7", "NetCore31WithConfigurableRules" , "ManuallyAddedNoncompliantIssues.CS", "ManuallyAddedNoncompliantIssues.VB", "Roslyn.1.3.1", "SkipGenerated.CS", "SkipGenerated.VB", "WebConfig")]
+ [ValidateSet("AnalyzeGenerated.CS", "AnalyzeGenerated.VB", "akka.net", "Automapper", "Ember-MM", "Nancy", "NetCore31", "Net5", "Net6", "Net7", "NetCore31WithConfigurableRules" , "ManuallyAddedNoncompliantIssues.CS", "ManuallyAddedNoncompliantIssues.VB", "Roslyn.1.3.1", "SkipGenerated.CS", "SkipGenerated.VB", "SonarLintExclusions", "WebConfig")]
[string]
$project
)
@@ -499,6 +499,7 @@ try {
Build-Project-DotnetTool "NetCore31WithConfigurableRules" "NetCore31WithConfigurableRules.sln"
Build-Project-DotnetTool "akka.net" "src\Akka.sln"
Build-Project-DotnetTool "Automapper" "Automapper.sln"
+ Build-Project-DotnetTool "SonarLintExclusions" "SonarLintExclusions.sln"
Write-Header "Processing analyzer results"
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions.sln b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions.sln
new file mode 100644
index 00000000000..3e5bcbbe34b
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions.sln
@@ -0,0 +1,36 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.6.33417.168
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SonarLintExclusions", "SonarLintExclusions\SonarLintExclusions.csproj", "{F5D0F2AC-2BED-42AA-B219-674F970E8400}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SonarLintExclusionsTest", "SonarLintExclusionsTest\SonarLintExclusionsTest.csproj", "{0F14329D-7A71-489B-BB85-2B257A866429}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1CF8B86B-6A00-4E05-931E-F278FCFDF1CF}"
+ ProjectSection(SolutionItems) = preProject
+ global.json = global.json
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F5D0F2AC-2BED-42AA-B219-674F970E8400}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F5D0F2AC-2BED-42AA-B219-674F970E8400}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F5D0F2AC-2BED-42AA-B219-674F970E8400}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F5D0F2AC-2BED-42AA-B219-674F970E8400}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0F14329D-7A71-489B-BB85-2B257A866429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0F14329D-7A71-489B-BB85-2B257A866429}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0F14329D-7A71-489B-BB85-2B257A866429}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0F14329D-7A71-489B-BB85-2B257A866429}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {9FA0AE0B-19EB-4F4F-A69E-5AB50EE8240E}
+ EndGlobalSection
+EndGlobal
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByExclusion.cs b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByExclusion.cs
new file mode 100644
index 00000000000..c33727affc7
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByExclusion.cs
@@ -0,0 +1,4 @@
+namespace SonarLintExclusions
+{
+ public class ExcludedByExclusion { } // S2094
+}
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByExclusion2.cs b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByExclusion2.cs
new file mode 100644
index 00000000000..8366890afef
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByExclusion2.cs
@@ -0,0 +1,4 @@
+namespace SonarLintExclusions
+{
+ public class ExcludedByExclusion2 { } // S2094
+}
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByGlobalExclusion.cs b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByGlobalExclusion.cs
new file mode 100644
index 00000000000..8eafecd8f7f
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/ExcludedByGlobalExclusion.cs
@@ -0,0 +1,4 @@
+namespace SonarLintExclusions
+{
+ public class ExcludedByGlobalExclusion { } // S2094
+}
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/Included.cs b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/Included.cs
new file mode 100644
index 00000000000..6fba906c697
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/Included/Included.cs
@@ -0,0 +1,4 @@
+namespace SonarLintExclusions
+{
+ public class Included { } // S2094
+}
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/NotIncluded.cs b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/NotIncluded.cs
new file mode 100644
index 00000000000..95a9911ce76
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/NotIncluded.cs
@@ -0,0 +1,4 @@
+namespace SonarLintExclusions
+{
+ public class NotIncluded { } // S2094
+}
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/SonarLintExclusions.csproj b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/SonarLintExclusions.csproj
new file mode 100644
index 00000000000..15297210401
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusions/SonarLintExclusions.csproj
@@ -0,0 +1,8 @@
+
+
+
+ net7.0
+ true
+
+
+
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/ExcludedByExclusionTest.cs b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/ExcludedByExclusionTest.cs
new file mode 100644
index 00000000000..d3fcf14795b
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/ExcludedByExclusionTest.cs
@@ -0,0 +1,10 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+namespace SonarLintExclusionsTest
+{
+ [TestClass]
+ public class ExcludedByExclusionTest
+ {
+ [TestMethod]
+ public void TestMethod1() { }
+ }
+}
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/ExcludedByGlobalExclusionTest.cs b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/ExcludedByGlobalExclusionTest.cs
new file mode 100644
index 00000000000..b1aadee0880
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/ExcludedByGlobalExclusionTest.cs
@@ -0,0 +1,10 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+namespace SonarLintExclusionsTest
+{
+ [TestClass]
+ public class ExcludedByGlobalExclusionTest
+ {
+ [TestMethod]
+ public void TestMethod1() { }
+ }
+}
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/IncludedTest.cs b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/IncludedTest.cs
new file mode 100644
index 00000000000..cc364afdccc
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/IncludedTest/IncludedTest.cs
@@ -0,0 +1,10 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+namespace SonarLintExclusionsTest
+{
+ [TestClass]
+ public class IncludedTest
+ {
+ [TestMethod]
+ public void TestMethod1() { }
+ }
+}
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/NotIncludedTest.cs b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/NotIncludedTest.cs
new file mode 100644
index 00000000000..8b81a00464c
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/NotIncludedTest.cs
@@ -0,0 +1,10 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+namespace SonarLintExclusionsTest
+{
+ [TestClass]
+ public class NotIncludedTest
+ {
+ [TestMethod]
+ public void TestMethod1() { }
+ }
+}
diff --git a/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/SonarLintExclusionsTest.csproj b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/SonarLintExclusionsTest.csproj
new file mode 100644
index 00000000000..0d99fb1aff7
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/SonarLintExclusionsTest/SonarLintExclusionsTest.csproj
@@ -0,0 +1,15 @@
+
+
+
+ net7.0
+ false
+ true
+
+
+
+
+
+
+
+
+
diff --git a/analyzers/its/sources/SonarLintExclusions/global.json b/analyzers/its/sources/SonarLintExclusions/global.json
new file mode 100644
index 00000000000..4037c7755e7
--- /dev/null
+++ b/analyzers/its/sources/SonarLintExclusions/global.json
@@ -0,0 +1,6 @@
+{
+ "sdk": {
+ "version": "7.0.100",
+ "rollForward": "latestMinor"
+ }
+}
\ No newline at end of file
From bbefe664f4f126ef31c756ea23ec6b832090d544 Mon Sep 17 00:00:00 2001
From: Cristian Ambrosini
<114916336+cristian-ambrosini-sonarsource@users.noreply.github.com>
Date: Mon, 13 Mar 2023 11:19:50 +0100
Subject: [PATCH 08/14] UTs: Cleanup ResourceTest folder (#6891)
---
.../Helpers/ParameterLoaderTest.cs | 16 +-
.../Helpers/SonarLintXmlReaderTest.cs | 2 +-
.../Helpers/SonarLintXmlTest.cs | 24 +-
.../AnalyzeGeneratedFalse/SonarLint.xml | 9 -
.../AnalyzeGeneratedFalseVbnet/SonarLint.xml | 9 -
.../AnalyzeGeneratedTrue/SonarLint.xml | 9 -
.../AnalyzeGeneratedTrueVbnet/SonarLint.xml | 9 -
.../SonarLint.xml | 9 -
.../SonarLint.xml | 9 -
.../SonarLint.xml | 9 -
.../SonarLint.xml | 9 -
.../ResourceTests/SonarLint.xml | 30 -
.../All_properties_cs/SonarLint.xml | 822 +-----------------
.../SonarLint.xml | 81 --
.../All_properties_vbnet/SonarLint.xml | 808 -----------------
.../RuleWithBooleanParameter/SonarLint.xml | 0
.../RuleWithStringParameter/SonarLint.xml | 0
.../StringInsteadOfBoolean/SonarLint.xml | 0
.../StringInsteadOfInt/SonarLint.xml | 0
.../ResourceTests/ToChange/SonarLint.xml | 30 -
.../Utilities/UtilityAnalyzerBaseTest.cs | 33 +-
.../TestFramework/AnalysisScaffolding.cs | 5 +-
22 files changed, 48 insertions(+), 1875 deletions(-)
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedFalse/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedFalseVbnet/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedTrue/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedTrueVbnet/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsFalseCSharp/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsFalseVbnet/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsTrueCSharp/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsTrueVbnet/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_small_template/SonarLint.xml
rename analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/{ => SonarLintXml}/RuleWithBooleanParameter/SonarLint.xml (100%)
rename analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/{ => SonarLintXml}/RuleWithStringParameter/SonarLint.xml (100%)
rename analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/{ => SonarLintXml}/StringInsteadOfBoolean/SonarLint.xml (100%)
rename analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/{ => SonarLintXml}/StringInsteadOfInt/SonarLint.xml (100%)
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/ToChange/SonarLint.xml
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
index bcf46ee97b6..5ed1026cd73 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
@@ -37,7 +37,7 @@ public class ParameterLoaderTest
public void SetParameterValues_WhenNoSonarLintIsGiven_DoesNotPopulateParameters(string filePath)
{
// Arrange
- var compilation = CreateCompilationWithOption(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLint.xml")));
+ var compilation = CreateCompilationWithOption(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml")));
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
@@ -53,7 +53,7 @@ public void SetParameterValues_WhenNoSonarLintIsGiven_DoesNotPopulateParameters(
public void SetParameterValues_WhenGivenValidSonarLintFilePath_PopulatesProperties(string filePath)
{
// Arrange
- var compilation = CreateCompilationWithOption(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLint.xml")));
+ var compilation = CreateCompilationWithOption(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml")));
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
@@ -67,7 +67,7 @@ public void SetParameterValues_WhenGivenValidSonarLintFilePath_PopulatesProperti
public void SetParameterValues_WhenGivenSonarLintFileHasIntParameterType_PopulatesProperties()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
@@ -81,7 +81,7 @@ public void SetParameterValues_WhenGivenSonarLintFileHasIntParameterType_Populat
public void SetParameterValues_WhenGivenSonarLintFileHasStringParameterType_OnlyOneParameter_PopulatesProperty()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\RuleWithStringParameter\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\RuleWithStringParameter\\SonarLint.xml");
var analyzer = new EnumNameShouldFollowRegex(); // Cannot use mock because we use reflection to find properties.
// Act
@@ -95,7 +95,7 @@ public void SetParameterValues_WhenGivenSonarLintFileHasStringParameterType_Only
public void SetParameterValues_WhenGivenSonarLintFileHasBooleanParameterType_OnlyOneParameter_PopulatesProperty()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\RuleWithBooleanParameter\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\RuleWithBooleanParameter\\SonarLint.xml");
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.
// Act
@@ -109,7 +109,7 @@ public void SetParameterValues_WhenGivenSonarLintFileHasBooleanParameterType_Onl
public void SetParameterValues_WhenGivenValidSonarLintFileAndDoesNotContainAnalyzerParameters_DoesNotPopulateProperties()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
var analyzer = new LineLength(); // Cannot use mock because we use reflection to find properties.
// Act
@@ -180,7 +180,7 @@ public void SetParameterValues_WithMalformedXml_DoesNotPopulateProperties(string
public void SetParameterValues_WithWrongPropertyType_StringInsteadOfInt_DoesNotPopulateProperties()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\StringInsteadOfInt\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\StringInsteadOfInt\\SonarLint.xml");
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
@@ -194,7 +194,7 @@ public void SetParameterValues_WithWrongPropertyType_StringInsteadOfInt_DoesNotP
public void SetParameterValues_WithWrongPropertyType_StringInsteadOfBoolean_DoesNotPopulateProperties()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\StringInsteadOfBoolean\\SonarLint.xml");
+ var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\StringInsteadOfBoolean\\SonarLint.xml");
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.
// Act
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
index 737148185f8..009508344c2 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
@@ -41,7 +41,7 @@ public void SonarLintXmlReader_WhenAllValuesAreSet_ExpectedValues(string languag
AssertArrayContent(sut.TestInclusions, nameof(sut.TestInclusions));
AssertArrayContent(sut.GlobalTestExclusions, nameof(sut.GlobalTestExclusions));
- sut.ParametrizedRules.Should().HaveCount(8);
+ sut.ParametrizedRules.Should().HaveCount(2);
var rule = sut.ParametrizedRules.First(x => x.Key.Equals("S2342"));
rule.Parameters[0].Key.Should().Be("format");
rule.Parameters[0].Value.Should().Be("^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$");
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlTest.cs
index b27c8f4b38d..47c834dbe53 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlTest.cs
@@ -30,7 +30,7 @@ public class SonarLintXmlTest
public void SonarLintXml_DeserializeFile_ExpectedValues()
{
var deserializer = new XmlSerializer(typeof(SonarLintXml));
- using TextReader textReader = new StreamReader("ResourceTests\\SonarLintXml\\All_properties_small_template\\SonarLint.xml");
+ using TextReader textReader = new StreamReader("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
var sonarLintXml = (SonarLintXml)deserializer.Deserialize(textReader);
AssertSettings(sonarLintXml.Settings);
@@ -58,20 +58,20 @@ private static void AssertRules(List rules)
rules.Should().HaveCount(4);
rules.Where(x => x.Parameters.Any()).Should().HaveCount(2);
- rules[0].Key.Should().BeEquivalentTo("S0001");
+ rules[0].Key.Should().BeEquivalentTo("S2225");
rules[0].Parameters.Should().BeEmpty();
- rules[1].Key.Should().BeEquivalentTo("S0002");
- rules[1].Parameters.Should().BeEmpty();
- rules[2].Key.Should().BeEquivalentTo("S0003");
- rules[2].Parameters.Should().HaveCount(2);
- AssertKeyValuePair(rules[2].Parameters[0], "format", "^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$");
- AssertKeyValuePair(rules[2].Parameters[1], "flagsAttributeFormat", "^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$");
+ rules[1].Key.Should().BeEquivalentTo("S2342");
+ rules[1].Parameters.Should().HaveCount(2);
+ AssertKeyValuePair(rules[1].Parameters[0], "format", "^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$");
+ AssertKeyValuePair(rules[1].Parameters[1], "flagsAttributeFormat", "^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$");
- rules[3].Key.Should().BeEquivalentTo("S0004");
- rules[3].Parameters.Should().HaveCount(2);
- AssertKeyValuePair(rules[3].Parameters[0], "threshold", "15");
- AssertKeyValuePair(rules[3].Parameters[1], "propertyThreshold", "3");
+ rules[2].Key.Should().BeEquivalentTo("S2346");
+ rules[2].Parameters.Should().BeEmpty();
+
+ rules[3].Key.Should().BeEquivalentTo("S1067");
+ rules[3].Parameters.Should().HaveCount(1);
+ AssertKeyValuePair(rules[3].Parameters[0], "max", "1");
}
private static void AssertKeyValuePair(SonarLintXmlKeyValuePair pair, string expectedKey, string expectedValue)
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedFalse/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedFalse/SonarLint.xml
deleted file mode 100644
index 06ff5bc2533..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedFalse/SonarLint.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- sonar.cs.analyzeGeneratedCode
- false
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedFalseVbnet/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedFalseVbnet/SonarLint.xml
deleted file mode 100644
index a3e4d99a79d..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedFalseVbnet/SonarLint.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- sonar.vbnet.analyzeGeneratedCode
- false
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedTrue/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedTrue/SonarLint.xml
deleted file mode 100644
index 058877ce0c4..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedTrue/SonarLint.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- sonar.cs.analyzeGeneratedCode
- true
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedTrueVbnet/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedTrueVbnet/SonarLint.xml
deleted file mode 100644
index 60d17ee38f1..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/AnalyzeGeneratedTrueVbnet/SonarLint.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- sonar.vbnet.analyzeGeneratedCode
- true
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsFalseCSharp/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsFalseCSharp/SonarLint.xml
deleted file mode 100644
index 4656ffb30d8..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsFalseCSharp/SonarLint.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- false
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsFalseVbnet/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsFalseVbnet/SonarLint.xml
deleted file mode 100644
index 19364407ace..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsFalseVbnet/SonarLint.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- sonar.vbnet.ignoreHeaderComments
- false
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsTrueCSharp/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsTrueCSharp/SonarLint.xml
deleted file mode 100644
index b9a6871be55..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsTrueCSharp/SonarLint.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsTrueVbnet/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsTrueVbnet/SonarLint.xml
deleted file mode 100644
index 89a7cfce399..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/IgnoreHeaderCommentsTrueVbnet/SonarLint.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
- sonar.vbnet.ignoreHeaderComments
- true
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLint.xml
deleted file mode 100644
index b99df9c60f6..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLint.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
- sonar.cs.analyzeGeneratedCode
- false
-
-
- sonar.cs.file.suffixes
- .cs
-
-
-
-
- S1067
-
-
- max
- 1
-
-
-
-
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_cs/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_cs/SonarLint.xml
index 0dc284bc00d..54a1ed9e464 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_cs/SonarLint.xml
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_cs/SonarLint.xml
@@ -46,36 +46,6 @@
S2225
-
- S2346
-
-
- S2589
-
-
- S3433
-
-
- S1135
-
-
- S2223
-
-
- S2344
-
-
- S2345
-
-
- S4524
-
-
- S1134
-
-
- S2222
-
S2342
@@ -90,799 +60,17 @@
- S2115
-
-
- S2583
-
-
- S3447
-
-
- S2234
-
-
- S2479
-
-
- S3444
-
-
- S3445
-
-
- S1144
-
-
- S1264
-
-
- S2114
-
-
- S3442
-
-
- S3443
-
-
- S3329
-
-
- S3440
-
-
- S3449
-
-
- S3655
-
-
- S3776
-
-
- threshold
- 15
-
-
- propertyThreshold
- 3
-
-
-
-
- S3897
-
-
- S2201
-
-
- S2688
-
-
- S4502
-
-
- S1110
-
-
- S1117
-
-
- S1118
-
-
- S2328
-
-
- S2681
-
-
- S2326
-
-
- S3415
-
-
- S4507
-
-
- S1116
-
-
- S1125
+ S2346
-
- S1479
+
+ S1067
- maximum
- 30
+ max
+ 1
-
- S2699
-
-
- S4635
-
-
- S1123
-
-
- S2696
-
-
- S1121
-
-
- S2692
-
-
- S1006
-
-
- S1481
-
-
- S2219
-
-
- S3237
-
-
- S3427
-
-
- S3236
-
-
- S3358
-
-
- S3598
-
-
- S2386
-
-
- S3597
-
-
- S4200
-
-
- S5773
-
-
- S1172
-
-
- S4201
-
-
- S5659
-
-
- S3249
-
-
- S4456
-
-
- S4457
-
-
- S3005
-
-
- S3246
-
-
- S3247
-
-
- S5547
-
-
- S3244
-
-
- S4211
-
-
- S5542
-
-
- S1066
-
-
- S4210
-
-
- S1185
-
-
- S1186
-
-
- S2275
-
-
- S2368
-
-
- S3241
-
-
- S3457
-
-
- S3458
-
-
- S4423
-
-
- S1155
-
-
- S2245
-
-
- S3453
-
-
- S3456
-
-
- S4426
-
-
- S2123
-
-
- S2365
-
-
- S2486
-
-
- S3451
-
-
- S3330
-
-
- S4428
-
-
- S5753
-
-
- S3217
-
-
- S3218
-
-
- S3459
-
-
- S927
-
-
- S3450
-
-
- S5766
-
-
- S1048
-
-
- S1168
-
-
- S2259
-
-
- S3466
-
-
- S2257
-
-
- S3343
-
-
- S3346
-
-
- S3464
-
-
- S2376
-
-
- S3220
-
-
- S4433
-
-
- S1163
-
-
- S2252
-
-
- S4790
-
-
- S818
-
-
- S2251
-
-
- S2372
-
-
- S2743
-
-
- S4792
-
-
- S1656
-
-
- S907
-
-
- S2995
-
-
- S3600
-
-
- S2996
-
-
- S3963
-
-
- S2755
-
-
- S2757
-
-
- S3604
-
-
- S2997
-
-
- S3603
-
-
- S3966
-
-
- S1751
-
-
- S1871
-
-
- S1643
-
-
- S1764
-
-
- S2737
-
-
- S2971
-
-
- S2612
-
-
- S2857
-
-
- S3875
-
-
- S3871
-
-
- S1210
-
-
- S1450
-
-
- S2306
-
-
- S3877
-
-
- S3998
-
-
- S1104
-
-
- S1215
-
-
- S1699
-
-
- S3887
-
-
- S3400
-
-
- S3884
-
-
- S3885
-
-
- S2551
-
-
- S3881
-
-
- S2436
-
-
- maxMethod
- 3
-
-
- max
- 2
-
-
-
-
- S3889
-
-
- S1313
-
-
- S2437
-
-
- S3972
-
-
- S2761
-
-
- S3610
-
-
- S3973
-
-
- S3971
-
-
- S3984
-
-
- S4830
-
-
- S3981
-
-
- S1206
-
-
- S3626
-
-
- S3869
-
-
- S1940
-
-
- S1944
-
-
- S1939
-
-
- S1905
-
-
- S5034
-
-
- S4061
-
-
- S5042
-
-
- S1854
-
-
- S4070
-
-
- S1862
-
-
- S3925
-
-
- S3926
-
-
- S3927
-
-
- S3928
-
-
- S2953
-
-
- S3923
-
-
- S125
-
-
- S1607
-
-
- S1848
-
-
- S2930
-
-
- S2933
-
-
- S3903
-
-
- S3904
-
-
- S2934
-
-
- S6422
-
-
- S110
-
-
- max
- 5
-
-
-
-
- S2068
-
-
- credentialWords
- password, passwd, pwd, passphrase
-
-
-
-
- S5332
-
-
- S112
-
-
- S6424
-
-
- S2187
-
-
- S3397
-
-
- S4487
-
-
- S2184
-
-
- S6420
-
-
- S2183
-
-
- S5693
-
-
- fileUploadSizeLimit
- 8000000
-
-
-
-
- S107
-
-
- max
- 7
-
-
-
-
- S108
-
-
- S3169
-
-
- S4019
-
-
- S3168
-
-
- S4015
-
-
- S4136
-
-
- S2077
-
-
- S2190
-
-
- S1199
-
-
- S3376
-
-
- S3011
-
-
- S3256
-
-
- S1075
-
-
- S4581
-
-
- S4586
-
-
- S3010
-
-
- S3251
-
-
- S4220
-
-
- S4583
-
-
- S2178
-
-
- S3264
-
-
- S3267
-
-
- S5443
-
-
- S101
-
-
- S3265
-
-
- S5445
-
-
- S3262
-
-
- S6419
-
-
- S2053
-
-
- S3263
-
-
- S2292
-
-
- S3260
-
-
- S3261
-
-
- S2290
-
-
- S2291
-
-
- S4144
-
-
- S6444
-
-
- S3172
-
-
- S4143
-
-
- S4159
-
-
- S4260
-
-
- S4036
-
-
- S4158
-
-
- S4277
-
-
- S4035
-
-
- S4275
-
-
- S2092
-
-
- S3060
-
-
- S5122
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_small_template/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_small_template/SonarLint.xml
deleted file mode 100644
index 70ca0115566..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_small_template/SonarLint.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
- sonar.cs.analyzeGeneratedCode
- false
-
-
- sonar.cs.file.suffixes
- .cs
-
-
- sonar.cs.roslyn.ignoreIssues
- false
-
-
- sonar.exclusions
- Fake/Exclusions/**/*,Fake/Exclusions/Second*/**/*
-
-
- sonar.inclusions
- Fake/Inclusions/**/*,Fake/Inclusions/Second*/**/*
-
-
- sonar.global.exclusions
- Fake/GlobalExclusions/**/*,Fake/GlobalExclusions/Second*/**/*
-
-
- sonar.test.exclusions
- Fake/TestExclusions/**/*,Fake/TestExclusions/Second*/**/*
-
-
- sonar.test.inclusions
- Fake/TestInclusions/**/*,Fake/TestInclusions/Second*/**/*
-
-
- sonar.global.test.exclusions
- Fake/GlobalTestExclusions/**/*,Fake/GlobalTestExclusions/Second*/**/*
-
-
-
-
- S0001
-
-
- S0002
-
-
- S0003
-
-
- format
- ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?$
-
-
- flagsAttributeFormat
- ^([A-Z]{1,3}[a-z0-9]+)*([A-Z]{2})?s$
-
-
-
-
- S0004
-
-
- threshold
- 15
-
-
- propertyThreshold
- 3
-
-
-
-
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_vbnet/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_vbnet/SonarLint.xml
index f848061efac..270c5c95dd8 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_vbnet/SonarLint.xml
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/All_properties_vbnet/SonarLint.xml
@@ -46,36 +46,6 @@
S2225
-
- S2346
-
-
- S2589
-
-
- S3433
-
-
- S1135
-
-
- S2223
-
-
- S2344
-
-
- S2345
-
-
- S4524
-
-
- S1134
-
-
- S2222
-
S2342
@@ -92,51 +62,6 @@
S2115
-
- S2583
-
-
- S3447
-
-
- S2234
-
-
- S2479
-
-
- S3444
-
-
- S3445
-
-
- S1144
-
-
- S1264
-
-
- S2114
-
-
- S3442
-
-
- S3443
-
-
- S3329
-
-
- S3440
-
-
- S3449
-
-
- S3655
-
S3776
@@ -150,739 +75,6 @@
-
- S3897
-
-
- S2201
-
-
- S2688
-
-
- S4502
-
-
- S1110
-
-
- S1117
-
-
- S1118
-
-
- S2328
-
-
- S2681
-
-
- S2326
-
-
- S3415
-
-
- S4507
-
-
- S1116
-
-
- S1125
-
-
- S1479
-
-
- maximum
- 30
-
-
-
-
- S2699
-
-
- S4635
-
-
- S1123
-
-
- S2696
-
-
- S1121
-
-
- S2692
-
-
- S1006
-
-
- S1481
-
-
- S2219
-
-
- S3237
-
-
- S3427
-
-
- S3236
-
-
- S3358
-
-
- S3598
-
-
- S2386
-
-
- S3597
-
-
- S4200
-
-
- S5773
-
-
- S1172
-
-
- S4201
-
-
- S5659
-
-
- S3249
-
-
- S4456
-
-
- S4457
-
-
- S3005
-
-
- S3246
-
-
- S3247
-
-
- S5547
-
-
- S3244
-
-
- S4211
-
-
- S5542
-
-
- S1066
-
-
- S4210
-
-
- S1185
-
-
- S1186
-
-
- S2275
-
-
- S2368
-
-
- S3241
-
-
- S3457
-
-
- S3458
-
-
- S4423
-
-
- S1155
-
-
- S2245
-
-
- S3453
-
-
- S3456
-
-
- S4426
-
-
- S2123
-
-
- S2365
-
-
- S2486
-
-
- S3451
-
-
- S3330
-
-
- S4428
-
-
- S5753
-
-
- S3217
-
-
- S3218
-
-
- S3459
-
-
- S927
-
-
- S3450
-
-
- S5766
-
-
- S1048
-
-
- S1168
-
-
- S2259
-
-
- S3466
-
-
- S2257
-
-
- S3343
-
-
- S3346
-
-
- S3464
-
-
- S2376
-
-
- S3220
-
-
- S4433
-
-
- S1163
-
-
- S2252
-
-
- S4790
-
-
- S818
-
-
- S2251
-
-
- S2372
-
-
- S2743
-
-
- S4792
-
-
- S1656
-
-
- S907
-
-
- S2995
-
-
- S3600
-
-
- S2996
-
-
- S3963
-
-
- S2755
-
-
- S2757
-
-
- S3604
-
-
- S2997
-
-
- S3603
-
-
- S3966
-
-
- S1751
-
-
- S1871
-
-
- S1643
-
-
- S1764
-
-
- S2737
-
-
- S2971
-
-
- S2612
-
-
- S2857
-
-
- S3875
-
-
- S3871
-
-
- S1210
-
-
- S1450
-
-
- S2306
-
-
- S3877
-
-
- S3998
-
-
- S1104
-
-
- S1215
-
-
- S1699
-
-
- S3887
-
-
- S3400
-
-
- S3884
-
-
- S3885
-
-
- S2551
-
-
- S3881
-
-
- S2436
-
-
- maxMethod
- 3
-
-
- max
- 2
-
-
-
-
- S3889
-
-
- S1313
-
-
- S2437
-
-
- S3972
-
-
- S2761
-
-
- S3610
-
-
- S3973
-
-
- S3971
-
-
- S3984
-
-
- S4830
-
-
- S3981
-
-
- S1206
-
-
- S3626
-
-
- S3869
-
-
- S1940
-
-
- S1944
-
-
- S1939
-
-
- S1905
-
-
- S5034
-
-
- S4061
-
-
- S5042
-
-
- S1854
-
-
- S4070
-
-
- S1862
-
-
- S3925
-
-
- S3926
-
-
- S3927
-
-
- S3928
-
-
- S2953
-
-
- S3923
-
-
- S125
-
-
- S1607
-
-
- S1848
-
-
- S2930
-
-
- S2933
-
-
- S3903
-
-
- S3904
-
-
- S2934
-
-
- S6422
-
-
- S110
-
-
- max
- 5
-
-
-
-
- S2068
-
-
- credentialWords
- password, passwd, pwd, passphrase
-
-
-
-
- S5332
-
-
- S112
-
-
- S6424
-
-
- S2187
-
-
- S3397
-
-
- S4487
-
-
- S2184
-
-
- S6420
-
-
- S2183
-
-
- S5693
-
-
- fileUploadSizeLimit
- 8000000
-
-
-
-
- S107
-
-
- max
- 7
-
-
-
-
- S108
-
-
- S3169
-
-
- S4019
-
-
- S3168
-
-
- S4015
-
-
- S4136
-
-
- S2077
-
-
- S2190
-
-
- S1199
-
-
- S3376
-
-
- S3011
-
-
- S3256
-
-
- S1075
-
-
- S4581
-
-
- S4586
-
-
- S3010
-
-
- S3251
-
-
- S4220
-
-
- S4583
-
-
- S2178
-
-
- S3264
-
-
- S3267
-
-
- S5443
-
-
- S101
-
-
- S3265
-
-
- S5445
-
-
- S3262
-
-
- S6419
-
-
- S2053
-
-
- S3263
-
-
- S2292
-
-
- S3260
-
-
- S3261
-
-
- S2290
-
-
- S2291
-
-
- S4144
-
-
- S6444
-
-
- S3172
-
-
- S4143
-
-
- S4159
-
-
- S4260
-
-
- S4036
-
-
- S4158
-
-
- S4277
-
-
- S4035
-
-
- S4275
-
-
- S2092
-
-
- S3060
-
-
- S5122
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/RuleWithBooleanParameter/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithBooleanParameter/SonarLint.xml
similarity index 100%
rename from analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/RuleWithBooleanParameter/SonarLint.xml
rename to analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithBooleanParameter/SonarLint.xml
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/RuleWithStringParameter/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithStringParameter/SonarLint.xml
similarity index 100%
rename from analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/RuleWithStringParameter/SonarLint.xml
rename to analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithStringParameter/SonarLint.xml
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/StringInsteadOfBoolean/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfBoolean/SonarLint.xml
similarity index 100%
rename from analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/StringInsteadOfBoolean/SonarLint.xml
rename to analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfBoolean/SonarLint.xml
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/StringInsteadOfInt/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfInt/SonarLint.xml
similarity index 100%
rename from analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/StringInsteadOfInt/SonarLint.xml
rename to analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfInt/SonarLint.xml
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/ToChange/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/ToChange/SonarLint.xml
deleted file mode 100644
index b99df9c60f6..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/ToChange/SonarLint.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
- sonar.cs.analyzeGeneratedCode
- false
-
-
- sonar.cs.file.suffixes
- .cs
-
-
-
-
- S1067
-
-
- max
- 1
-
-
-
-
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/Utilities/UtilityAnalyzerBaseTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/Utilities/UtilityAnalyzerBaseTest.cs
index 8f03a14688f..d1e6b4e61b2 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/Utilities/UtilityAnalyzerBaseTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/Utilities/UtilityAnalyzerBaseTest.cs
@@ -34,6 +34,7 @@ public class UtilityAnalyzerBaseTest
{
private const string DefaultSonarProjectConfig = @"ResourceTests\SonarProjectConfig\Path_Windows\SonarProjectConfig.xml";
private const string DefaultProjectOutFolderPath = @"ResourceTests\ProjectOutFolderPath.txt";
+ public TestContext TestContext { get; set; }
[DataTestMethod]
[DataRow(LanguageNames.CSharp, DefaultProjectOutFolderPath, @"path\output-cs")]
@@ -43,7 +44,7 @@ public class UtilityAnalyzerBaseTest
public void ReadConfig_OutPath(string language, string additionalPath, string expectedOutPath)
{
// We do not test what is read from the SonarLint file, but we need it
- var utilityAnalyzer = new TestUtilityAnalyzer(language, @"ResourceTests\SonarLint.xml", additionalPath);
+ var utilityAnalyzer = new TestUtilityAnalyzer(language, @"ResourceTests\SonarLintXml\All_properties_cs\SonarLint.xml", additionalPath);
utilityAnalyzer.TestOutPath.Should().Be(expectedOutPath);
utilityAnalyzer.TestIsAnalyzerEnabled.Should().BeTrue();
@@ -55,35 +56,37 @@ public void ReadConfig_OutPath(string language, string additionalPath, string ex
public void ReadConfig_OutPath_FromSonarProjectConfig_HasPriority(string firstFile, string secondFile)
{
// We do not test what is read from the SonarLint file, but we need it
- var utilityAnalyzer = new TestUtilityAnalyzer(LanguageNames.CSharp, @"ResourceTests\SonarLint.xml", firstFile, secondFile);
+ var utilityAnalyzer = new TestUtilityAnalyzer(LanguageNames.CSharp, @"ResourceTests\SonarLintXml\All_properties_cs\SonarLint.xml", firstFile, secondFile);
utilityAnalyzer.TestOutPath.Should().Be(@"C:\foo\bar\.sonarqube\out\0\output-cs");
utilityAnalyzer.TestIsAnalyzerEnabled.Should().BeTrue();
}
[DataTestMethod]
- [DataRow(LanguageNames.CSharp, @"ResourceTests\AnalyzeGeneratedTrue\SonarLint.xml", true)]
- [DataRow(LanguageNames.CSharp, @"ResourceTests\AnalyzeGeneratedFalse\SonarLint.xml", false)]
- [DataRow(LanguageNames.VisualBasic, @"ResourceTests\AnalyzeGeneratedTrueVbnet\SonarLint.xml", true)]
- [DataRow(LanguageNames.VisualBasic, @"ResourceTests\AnalyzeGeneratedFalseVbnet\SonarLint.xml", false)]
- public void ReadsSettings_AnalyzeGenerated(string language, string sonarLintXmlPath, bool expectedAnalyzeGeneratedCodeValue)
+ [DataRow(LanguageNames.CSharp, true)]
+ [DataRow(LanguageNames.CSharp, false)]
+ [DataRow(LanguageNames.VisualBasic, true)]
+ [DataRow(LanguageNames.VisualBasic, false)]
+ public void ReadsSettings_AnalyzeGenerated(string language, bool analyzeGenerated)
{
+ var sonarLintXmlPath = AnalysisScaffolding.CreateSonarLintXml(TestContext, language: language, analyzeGeneratedCode: analyzeGenerated);
var utilityAnalyzer = new TestUtilityAnalyzer(language, sonarLintXmlPath, DefaultSonarProjectConfig);
- utilityAnalyzer.TestAnalyzeGeneratedCode.Should().Be(expectedAnalyzeGeneratedCodeValue);
+ utilityAnalyzer.TestAnalyzeGeneratedCode.Should().Be(analyzeGenerated);
utilityAnalyzer.TestIsAnalyzerEnabled.Should().BeTrue();
}
[DataTestMethod]
- [DataRow(LanguageNames.CSharp, @"ResourceTests\IgnoreHeaderCommentsTrueCSharp\SonarLint.xml", true)]
- [DataRow(LanguageNames.CSharp, @"ResourceTests\IgnoreHeaderCommentsFalseCSharp\SonarLint.xml", false)]
- [DataRow(LanguageNames.VisualBasic, @"ResourceTests\IgnoreHeaderCommentsTrueVbnet\SonarLint.xml", true)]
- [DataRow(LanguageNames.VisualBasic, @"ResourceTests\IgnoreHeaderCommentsFalseVbnet\SonarLint.xml", false)]
- public void ReadsSettings_IgnoreHeaderComments(string language, string sonarLintXmlPath, bool expectedIgnoreHeaderComments)
+ [DataRow(LanguageNames.CSharp, true)]
+ [DataRow(LanguageNames.CSharp, false)]
+ [DataRow(LanguageNames.VisualBasic, true)]
+ [DataRow(LanguageNames.VisualBasic, false)]
+ public void ReadsSettings_IgnoreHeaderComments(string language, bool ignoreHeaderComments)
{
+ var sonarLintXmlPath = AnalysisScaffolding.CreateSonarLintXml(TestContext, language: language, ignoreHeaderComments: ignoreHeaderComments);
var utilityAnalyzer = new TestUtilityAnalyzer(language, sonarLintXmlPath, DefaultSonarProjectConfig);
- utilityAnalyzer.TestIgnoreHeaderComments.Should().Be(expectedIgnoreHeaderComments);
+ utilityAnalyzer.TestIgnoreHeaderComments.Should().Be(ignoreHeaderComments);
utilityAnalyzer.TestIsAnalyzerEnabled.Should().BeTrue();
}
@@ -96,7 +99,7 @@ public void NoSonarLintXml_AnalyzerNotEnabled()
[TestMethod]
public void NoOutputPath_AnalyzerNotEnabled() =>
- new TestUtilityAnalyzer(LanguageNames.CSharp, @"ResourceTests\AnalyzeGeneratedTrue\SonarLint.xml").TestIsAnalyzerEnabled.Should().BeFalse();
+ new TestUtilityAnalyzer(LanguageNames.CSharp, AnalysisScaffolding.CreateSonarLintXml(TestContext, analyzeGeneratedCode: true)).TestIsAnalyzerEnabled.Should().BeFalse();
[TestMethod]
public void GetTextRange()
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs
index aa476e1131e..6c6b8ef5e42 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestFramework/AnalysisScaffolding.cs
@@ -86,6 +86,7 @@ public static string CreateSonarProjectConfigWithFilesToAnalyze(TestContext cont
TestContext context,
string language = LanguageNames.CSharp,
bool analyzeGeneratedCode = false,
+ bool ignoreHeaderComments = false,
string[] exclusions = null,
string[] inclusions = null,
string[] globalExclusions = null,
@@ -93,11 +94,12 @@ public static string CreateSonarProjectConfigWithFilesToAnalyze(TestContext cont
string[] testInclusions = null,
string[] globalTestExclusions = null,
List rulesParameters = null) =>
- TestHelper.WriteFile(context, "SonarLint.xml", GenerateSonarLintXmlContent(language, analyzeGeneratedCode, exclusions, inclusions, globalExclusions, testExclusions, testInclusions, globalTestExclusions, rulesParameters));
+ TestHelper.WriteFile(context, "SonarLint.xml", GenerateSonarLintXmlContent(language, analyzeGeneratedCode, ignoreHeaderComments, exclusions, inclusions, globalExclusions, testExclusions, testInclusions, globalTestExclusions, rulesParameters));
public static string GenerateSonarLintXmlContent(
string language = LanguageNames.CSharp,
bool analyzeGeneratedCode = false,
+ bool ignoreHeaderComments = false,
string[] exclusions = null,
string[] inclusions = null,
string[] globalExclusions = null,
@@ -110,6 +112,7 @@ public static string CreateSonarProjectConfigWithFilesToAnalyze(TestContext cont
new XElement("AnalysisInput",
new XElement("Settings",
CreateSetting($"sonar.{(language == LanguageNames.CSharp ? "cs" : "vbnet")}.analyzeGeneratedCode", analyzeGeneratedCode.ToString()),
+ CreateSetting($"sonar.{(language == LanguageNames.CSharp ? "cs" : "vbnet")}.ignoreHeaderComments", ignoreHeaderComments.ToString()),
CreateSetting("sonar.exclusions", ConcatenateStringArray(exclusions)),
CreateSetting("sonar.inclusions", ConcatenateStringArray(inclusions)),
CreateSetting("sonar.global.exclusions", ConcatenateStringArray(globalExclusions)),
From e841ab63a549b4c61761107dbb1e97f2d0f6f74e Mon Sep 17 00:00:00 2001
From: Cristian Ambrosini
<114916336+cristian-ambrosini-sonarsource@users.noreply.github.com>
Date: Mon, 13 Mar 2023 15:48:00 +0100
Subject: [PATCH 09/14] UTs: Cleanup ResourceTest folder 2/2 (#6907)
---
.../sources/AnalyzeGenerated.CS/SonarLint.xml | 30 ----------
.../sources/SkipGenerated.CS/SonarLint.xml | 30 ----------
.../Helpers/ParameterLoaderTest.cs | 56 ++++++++++++++-----
.../RuleWithBooleanParameter/SonarLint.xml | 30 ----------
.../RuleWithStringParameter/SonarLint.xml | 30 ----------
.../StringInsteadOfBoolean/SonarLint.xml | 30 ----------
.../StringInsteadOfInt/SonarLint.xml | 30 ----------
7 files changed, 42 insertions(+), 194 deletions(-)
delete mode 100644 analyzers/its/sources/AnalyzeGenerated.CS/SonarLint.xml
delete mode 100644 analyzers/its/sources/SkipGenerated.CS/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithBooleanParameter/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithStringParameter/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfBoolean/SonarLint.xml
delete mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfInt/SonarLint.xml
diff --git a/analyzers/its/sources/AnalyzeGenerated.CS/SonarLint.xml b/analyzers/its/sources/AnalyzeGenerated.CS/SonarLint.xml
deleted file mode 100644
index 15dbb76706c..00000000000
--- a/analyzers/its/sources/AnalyzeGenerated.CS/SonarLint.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
- sonar.cs.analyzeGeneratedCode
- true
-
-
- sonar.cs.file.suffixes
- .cs
-
-
-
-
- S1067
-
-
- max
- 1
-
-
-
-
-
-
-
diff --git a/analyzers/its/sources/SkipGenerated.CS/SonarLint.xml b/analyzers/its/sources/SkipGenerated.CS/SonarLint.xml
deleted file mode 100644
index b99df9c60f6..00000000000
--- a/analyzers/its/sources/SkipGenerated.CS/SonarLint.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
- sonar.cs.analyzeGeneratedCode
- false
-
-
- sonar.cs.file.suffixes
- .cs
-
-
-
-
- S1067
-
-
- max
- 1
-
-
-
-
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
index 5ed1026cd73..fb9a2ff026c 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
@@ -34,7 +34,7 @@ public class ParameterLoaderTest
[TestMethod]
[DataRow("path//aSonarLint.xml")] // different name
[DataRow("path//SonarLint.xmla")] // different extension
- public void SetParameterValues_WhenNoSonarLintIsGiven_DoesNotPopulateParameters(string filePath)
+ public void SetParameterValues_WithInvalidSonarLintPath_DoesNotPopulateParameters(string filePath)
{
// Arrange
var compilation = CreateCompilationWithOption(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml")));
@@ -50,7 +50,7 @@ public void SetParameterValues_WhenNoSonarLintIsGiven_DoesNotPopulateParameters(
[TestMethod]
[DataRow("a/SonarLint.xml")] // unix path
[DataRow("a\\SonarLint.xml")]
- public void SetParameterValues_WhenGivenValidSonarLintFilePath_PopulatesProperties(string filePath)
+ public void SetParameterValues_WithValidSonarLintPath_PopulatesProperties(string filePath)
{
// Arrange
var compilation = CreateCompilationWithOption(filePath, SourceText.From(File.ReadAllText("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml")));
@@ -64,7 +64,7 @@ public void SetParameterValues_WhenGivenValidSonarLintFilePath_PopulatesProperti
}
[TestMethod]
- public void SetParameterValues_WhenGivenSonarLintFileHasIntParameterType_PopulatesProperties()
+ public void SetParameterValues_SonarLintFileWithIntParameterType_PopulatesProperties()
{
// Arrange
var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
@@ -78,35 +78,39 @@ public void SetParameterValues_WhenGivenSonarLintFileHasIntParameterType_Populat
}
[TestMethod]
- public void SetParameterValues_WhenGivenSonarLintFileHasStringParameterType_OnlyOneParameter_PopulatesProperty()
+ public void SetParameterValues_SonarLintFileWithStringParameterType_PopulatesProperty()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\RuleWithStringParameter\\SonarLint.xml");
+ var parameterValue = "1";
+ var filePath = GenerateSonarLintXmlWithParametrizedRule("S2342", "flagsAttributeFormat", parameterValue);
+ var compilation = CreateCompilationWithOption(filePath);
var analyzer = new EnumNameShouldFollowRegex(); // Cannot use mock because we use reflection to find properties.
// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
- analyzer.FlagsEnumNamePattern.Should().Be("1"); // value from XML file
+ analyzer.FlagsEnumNamePattern.Should().Be(parameterValue); // value from XML file
}
[TestMethod]
- public void SetParameterValues_WhenGivenSonarLintFileHasBooleanParameterType_OnlyOneParameter_PopulatesProperty()
+ public void SetParameterValues_SonarLintFileWithBooleanParameterType_PopulatesProperty()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\RuleWithBooleanParameter\\SonarLint.xml");
+ var parameterValue = true;
+ var filePath = GenerateSonarLintXmlWithParametrizedRule("S1451", "isRegularExpression", parameterValue.ToString());
+ var compilation = CreateCompilationWithOption(filePath);
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.
// Act
ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
// Assert
- analyzer.IsRegularExpression.Should().BeTrue(); // value from XML file
+ analyzer.IsRegularExpression.Should().Be(parameterValue); // value from XML file
}
[TestMethod]
- public void SetParameterValues_WhenGivenValidSonarLintFileAndDoesNotContainAnalyzerParameters_DoesNotPopulateProperties()
+ public void SetParameterValues_SonarLintFileWithoutRuleParameters_DoesNotPopulateProperties()
{
// Arrange
var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
@@ -177,10 +181,12 @@ public void SetParameterValues_WithMalformedXml_DoesNotPopulateProperties(string
}
[TestMethod]
- public void SetParameterValues_WithWrongPropertyType_StringInsteadOfInt_DoesNotPopulateProperties()
+ public void SetParameterValues_SonarLintFileWithStringInsteadOfIntParameterType_PopulatesProperty()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\StringInsteadOfInt\\SonarLint.xml");
+ var parameterValue = "fooBar";
+ var filePath = GenerateSonarLintXmlWithParametrizedRule("S1067", "max", parameterValue);
+ var compilation = CreateCompilationWithOption(filePath);
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
@@ -191,10 +197,12 @@ public void SetParameterValues_WithWrongPropertyType_StringInsteadOfInt_DoesNotP
}
[TestMethod]
- public void SetParameterValues_WithWrongPropertyType_StringInsteadOfBoolean_DoesNotPopulateProperties()
+ public void SetParameterValues_SonarLintFileWithStringInsteadOfBooleanParameterType_PopulatesProperty()
{
// Arrange
- var compilation = CreateCompilationWithOption("ResourceTests\\SonarLintXml\\StringInsteadOfBoolean\\SonarLint.xml");
+ var parameterValue = "fooBar";
+ var filePath = GenerateSonarLintXmlWithParametrizedRule("S1451", "isRegularExpression", parameterValue);
+ var compilation = CreateCompilationWithOption(filePath);
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.
// Act
@@ -213,5 +221,25 @@ private static SonarCompilationReportingContext CreateCompilationWithOption(stri
var compilationContext = new CompilationAnalysisContext(compilation, options, _ => { }, _ => true, default);
return new(AnalysisScaffolding.CreateSonarAnalysisContext(), compilationContext);
}
+
+ private string GenerateSonarLintXmlWithParametrizedRule(string ruleId, string key, string value)
+ {
+ var ruleParameters = new List()
+ {
+ new SonarLintXmlRule()
+ {
+ Key = ruleId,
+ Parameters = new List()
+ {
+ new SonarLintXmlKeyValuePair()
+ {
+ Key = key,
+ Value = value
+ }
+ }
+ }
+ };
+ return AnalysisScaffolding.CreateSonarLintXml(TestContext, rulesParameters: ruleParameters);
+ }
}
}
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithBooleanParameter/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithBooleanParameter/SonarLint.xml
deleted file mode 100644
index 4170e60a90a..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithBooleanParameter/SonarLint.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
- sonar.cs.analyzeGeneratedCode
- false
-
-
- sonar.cs.file.suffixes
- .cs
-
-
-
-
- S1451
-
-
- isRegularExpression
- true
-
-
-
-
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithStringParameter/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithStringParameter/SonarLint.xml
deleted file mode 100644
index d45ac7addb5..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/RuleWithStringParameter/SonarLint.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
- sonar.cs.analyzeGeneratedCode
- false
-
-
- sonar.cs.file.suffixes
- .cs
-
-
-
-
- S2342
-
-
- flagsAttributeFormat
- 1
-
-
-
-
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfBoolean/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfBoolean/SonarLint.xml
deleted file mode 100644
index 913b8886a2d..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfBoolean/SonarLint.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
- sonar.cs.analyzeGeneratedCode
- false
-
-
- sonar.cs.file.suffixes
- .cs
-
-
-
-
- S1451
-
-
- isRegularExpression
- fooBar
-
-
-
-
-
-
-
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfInt/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfInt/SonarLint.xml
deleted file mode 100644
index 4596b44be4b..00000000000
--- a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/StringInsteadOfInt/SonarLint.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- sonar.cs.ignoreHeaderComments
- true
-
-
- sonar.cs.analyzeGeneratedCode
- false
-
-
- sonar.cs.file.suffixes
- .cs
-
-
-
-
- S1067
-
-
- max
- fooBar
-
-
-
-
-
-
-
From 7f128129148486bd614efc2e7fb9dfcc9138d662 Mon Sep 17 00:00:00 2001
From: Cristian Ambrosini
<114916336+cristian-ambrosini-sonarsource@users.noreply.github.com>
Date: Wed, 15 Mar 2023 11:49:48 +0100
Subject: [PATCH 10/14] Fix SL feature branch ITs (#6927)
---
.../SonarLintExclusions--net7.0-S1451.json | 17 +++++++++++
.../sources/AnalyzeGenerated.CS/SonarLint.xml | 30 +++++++++++++++++++
.../sources/SkipGenerated.CS/SonarLint.xml | 30 +++++++++++++++++++
3 files changed, 77 insertions(+)
create mode 100644 analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S1451.json
create mode 100644 analyzers/its/sources/AnalyzeGenerated.CS/SonarLint.xml
create mode 100644 analyzers/its/sources/SkipGenerated.CS/SonarLint.xml
diff --git a/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S1451.json b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S1451.json
new file mode 100644
index 00000000000..d4028681cc7
--- /dev/null
+++ b/analyzers/its/expected/SonarLintExclusions/SonarLintExclusions--net7.0-S1451.json
@@ -0,0 +1,17 @@
+{
+"issues": [
+{
+"id": "S1451",
+"message": "Add or update the header of this file.",
+"location": {
+"uri": "sources\SonarLintExclusions\SonarLintExclusions\Included\Included.cs",
+"region": {
+"startLine": 1,
+"startColumn": 1,
+"endLine": 1,
+"endColumn": 1
+}
+}
+}
+]
+}
diff --git a/analyzers/its/sources/AnalyzeGenerated.CS/SonarLint.xml b/analyzers/its/sources/AnalyzeGenerated.CS/SonarLint.xml
new file mode 100644
index 00000000000..637fabc2996
--- /dev/null
+++ b/analyzers/its/sources/AnalyzeGenerated.CS/SonarLint.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ sonar.cs.ignoreHeaderComments
+ true
+
+
+ sonar.cs.analyzeGeneratedCode
+ true
+
+
+ sonar.cs.file.suffixes
+ .cs
+
+
+
+
+ S1067
+
+
+ max
+ 1
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/analyzers/its/sources/SkipGenerated.CS/SonarLint.xml b/analyzers/its/sources/SkipGenerated.CS/SonarLint.xml
new file mode 100644
index 00000000000..b11b39f3e3c
--- /dev/null
+++ b/analyzers/its/sources/SkipGenerated.CS/SonarLint.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ sonar.cs.ignoreHeaderComments
+ true
+
+
+ sonar.cs.analyzeGeneratedCode
+ false
+
+
+ sonar.cs.file.suffixes
+ .cs
+
+
+
+
+ S1067
+
+
+ max
+ 1
+
+
+
+
+
+
+
\ No newline at end of file
From f0553a746a05ed054f6612b8dabab5b528340a62 Mon Sep 17 00:00:00 2001
From: Mary Georgiou
<89914005+mary-georgiou-sonarsource@users.noreply.github.com>
Date: Wed, 15 Mar 2023 16:10:49 +0100
Subject: [PATCH 11/14] Remove language property from SonarLintXmlReader
(#6905)
---
.../SonarAnalysisContextBase.cs | 10 ++---
.../Common/UnexpectedLanguageException.cs | 4 +-
.../Helpers/SonarLintXmlReader.cs | 32 ++++++++++-----
.../Rules/Utilities/UtilityAnalyzerBase.cs | 4 +-
.../SonarAnalysisContextBaseTest.cs | 8 ++--
.../Common/UnexpectedLanguageExceptionTest.cs | 4 ++
.../Helpers/SonarLintXmlReaderTest.cs | 41 ++++++++++++++-----
.../SonarLint.xml | 21 ++++++++++
8 files changed, 88 insertions(+), 36 deletions(-)
create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/PropertiesCSharpTrueVbnetFalse/SonarLint.xml
diff --git a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
index 70fd96b25ee..e6f2ff25f68 100644
--- a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
+++ b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
@@ -30,13 +30,9 @@ public class SonarAnalysisContextBase
protected static readonly ConditionalWeakTable> FileInclusionCache = new();
protected static readonly ConditionalWeakTable> UnchangedFilesCache = new();
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));
+ protected static readonly SourceTextValueProvider SonarLintXmlProvider = new(x => new SonarLintXmlReader(x));
protected SonarAnalysisContextBase() { }
-
- protected static SourceTextValueProvider SonarLintXmlReader(string language) =>
- language == LanguageNames.CSharp ? SonarLintXmlProviderCS : SonarLintXmlProviderVB;
}
public abstract class SonarAnalysisContextBase : SonarAnalysisContextBase
@@ -58,7 +54,7 @@ protected SonarAnalysisContextBase(SonarAnalysisContext analysisContext, TContex
/// When set, generated trees are analyzed only when language-specific 'analyzeGeneratedCode' configuration property is also set.
public bool ShouldAnalyzeTree(SyntaxTree tree, GeneratedCodeRecognizer generatedCodeRecognizer) =>
SonarLintFile() is var sonarLintReader
- && (generatedCodeRecognizer is null || sonarLintReader.AnalyzeGeneratedCode || !tree.IsGenerated(generatedCodeRecognizer, Compilation))
+ && (generatedCodeRecognizer is null || sonarLintReader.AnalyzeGeneratedCode(Compilation.Language) || !tree.IsGenerated(generatedCodeRecognizer, Compilation))
&& (tree is null || (!IsUnchanged(tree) && ShouldAnalyzeFile(sonarLintReader, tree.FilePath)));
///
@@ -88,7 +84,7 @@ public SonarLintXmlReader SonarLintFile()
if (Options.SonarLintXml() is { } sonarLintXml)
{
return sonarLintXml.GetText() is { } sourceText
- && AnalysisContext.TryGetValue(sourceText, SonarLintXmlReader(Compilation.Language), out var sonarLintXmlReader)
+ && AnalysisContext.TryGetValue(sourceText, SonarLintXmlProvider, out var sonarLintXmlReader)
? sonarLintXmlReader
: throw new InvalidOperationException($"File '{Path.GetFileName(sonarLintXml.Path)}' has been added as an AdditionalFile but could not be read and parsed.");
}
diff --git a/analyzers/src/SonarAnalyzer.Common/Common/UnexpectedLanguageException.cs b/analyzers/src/SonarAnalyzer.Common/Common/UnexpectedLanguageException.cs
index c71a99fca52..5585b04b6ad 100644
--- a/analyzers/src/SonarAnalyzer.Common/Common/UnexpectedLanguageException.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Common/UnexpectedLanguageException.cs
@@ -22,6 +22,8 @@ namespace SonarAnalyzer.Common
{
public sealed class UnexpectedLanguageException : Exception
{
- public UnexpectedLanguageException(AnalyzerLanguage language) : base($"Unexpected language: {language}") { }
+ public UnexpectedLanguageException(AnalyzerLanguage language) : this(language.LanguageName) { }
+
+ public UnexpectedLanguageException(string language) : base($"Unexpected language: {language}") { }
}
}
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
index 83fb3a13080..77cfddc9c1e 100644
--- a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
@@ -28,16 +28,29 @@ namespace SonarAnalyzer.Helpers;
public class SonarLintXmlReader
{
- public static readonly SonarLintXmlReader Empty = new(null, LanguageNames.CSharp);
+ public static readonly SonarLintXmlReader Empty = new(null);
private readonly SonarLintXml sonarLintXml;
- private readonly string propertyLanguage;
- private bool? ignoreHeaderComments;
- public bool IgnoreHeaderComments => ignoreHeaderComments ??= ReadBoolean(ReadSettingsProperty($"sonar.{propertyLanguage}.ignoreHeaderComments"));
-
- private bool? analyzeGeneratedCode;
- public bool AnalyzeGeneratedCode => analyzeGeneratedCode ??= ReadBoolean(ReadSettingsProperty($"sonar.{propertyLanguage}.analyzeGeneratedCode"));
+ private bool? ignoreHeaderCommentsCS;
+ private bool? ignoreHeaderCommentsVB;
+ public bool IgnoreHeaderComments(string language) =>
+ language switch
+ {
+ LanguageNames.CSharp => ignoreHeaderCommentsCS ??= ReadBoolean(ReadSettingsProperty("sonar.cs.ignoreHeaderComments")),
+ LanguageNames.VisualBasic => ignoreHeaderCommentsVB ??= ReadBoolean(ReadSettingsProperty("sonar.vbnet.ignoreHeaderComments")),
+ _ => throw new UnexpectedLanguageException(language)
+ };
+
+ private bool? analyzeGeneratedCodeCS;
+ private bool? analyzeGeneratedCodeVB;
+ public bool AnalyzeGeneratedCode(string language) =>
+ language switch
+ {
+ LanguageNames.CSharp => analyzeGeneratedCodeCS ??= ReadBoolean(ReadSettingsProperty("sonar.cs.analyzeGeneratedCode")),
+ LanguageNames.VisualBasic => analyzeGeneratedCodeVB ??= ReadBoolean(ReadSettingsProperty("sonar.vbnet.analyzeGeneratedCode")),
+ _ => throw new UnexpectedLanguageException(language)
+ };
private string[] exclusions;
public string[] Exclusions => exclusions ??= ReadCommaSeparatedArray(ReadSettingsProperty("sonar.exclusions"));
@@ -60,11 +73,8 @@ public class SonarLintXmlReader
private List parametrizedRules;
public List ParametrizedRules => parametrizedRules ??= ReadRuleParameters();
- public SonarLintXmlReader(SourceText sonarLintXml, string language = LanguageNames.CSharp)
- {
+ public SonarLintXmlReader(SourceText sonarLintXml) =>
this.sonarLintXml = sonarLintXml == null ? SonarLintXml.Empty : ParseContent(sonarLintXml);
- propertyLanguage = language == LanguageNames.CSharp ? "cs" : "vbnet";
- }
private static SonarLintXml ParseContent(SourceText sonarLintXml)
{
diff --git a/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs b/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs
index 6df9b93a53e..65627b91f2f 100644
--- a/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs
@@ -61,8 +61,8 @@ protected void ReadParameters(SonarCompilationStartAnalysisContext context)
if (context.Options.SonarLintXml() != null && !string.IsNullOrEmpty(outPath))
{
var sonarLintXml = context.SonarLintFile();
- IgnoreHeaderComments = sonarLintXml.IgnoreHeaderComments;
- AnalyzeGeneratedCode = sonarLintXml.AnalyzeGeneratedCode;
+ IgnoreHeaderComments = sonarLintXml.IgnoreHeaderComments(context.Compilation.Language);
+ AnalyzeGeneratedCode = sonarLintXml.AnalyzeGeneratedCode(context.Compilation.Language);
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 e0c98dd49aa..f527dd092a9 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs
@@ -181,8 +181,8 @@ public void SonarLintFile_LoadsExpectedValues(string language)
var options = AnalysisScaffolding.CreateOptions($"ResourceTests\\SonarLintXml\\All_properties_{language}\\SonarLint.xml");
var sut = CreateSut(compilation, options).SonarLintFile();
- sut.IgnoreHeaderComments.Should().BeTrue();
- sut.AnalyzeGeneratedCode.Should().BeFalse();
+ sut.IgnoreHeaderComments(analyzerLanguage.LanguageName).Should().BeTrue();
+ sut.AnalyzeGeneratedCode(analyzerLanguage.LanguageName).Should().BeFalse();
AssertArrayContent(sut.Exclusions, nameof(sut.Exclusions));
AssertArrayContent(sut.Inclusions, nameof(sut.Inclusions));
AssertArrayContent(sut.GlobalExclusions, nameof(sut.GlobalExclusions));
@@ -253,8 +253,8 @@ public void SonarLintFile_WhenFileIsMissing_ThrowException()
private static void CheckSonarLintXmlDefaultValues(SonarLintXmlReader sut)
{
- sut.AnalyzeGeneratedCode.Should().BeFalse();
- sut.IgnoreHeaderComments.Should().BeFalse();
+ sut.AnalyzeGeneratedCode(LanguageNames.CSharp).Should().BeFalse();
+ sut.IgnoreHeaderComments(LanguageNames.CSharp).Should().BeFalse();
sut.Exclusions.Should().NotBeNull().And.HaveCount(0);
sut.Inclusions.Should().NotBeNull().And.HaveCount(0);
sut.GlobalExclusions.Should().NotBeNull().And.HaveCount(0);
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Common/UnexpectedLanguageExceptionTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Common/UnexpectedLanguageExceptionTest.cs
index 99c548a1acf..166d08a855c 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Common/UnexpectedLanguageExceptionTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Common/UnexpectedLanguageExceptionTest.cs
@@ -25,6 +25,10 @@ namespace SonarAnalyzer.UnitTest.Common
[TestClass]
public class UnexpectedLanguageExceptionTest
{
+ [TestMethod]
+ public void Message_String_Ctor() =>
+ new UnexpectedLanguageException("F#").Message.Should().Be("Unexpected language: F#");
+
[TestMethod]
public void Message_CS() =>
new UnexpectedLanguageException(AnalyzerLanguage.CSharp).Message.Should().Be("Unexpected language: C#");
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
index 009508344c2..5caa7a84e9e 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/SonarLintXmlReaderTest.cs
@@ -20,6 +20,7 @@
using System.IO;
using Microsoft.CodeAnalysis.Text;
+using SonarAnalyzer.Common;
namespace SonarAnalyzer.UnitTest.Helpers;
@@ -29,11 +30,11 @@ public class SonarLintXmlReaderTest
[DataTestMethod]
[DataRow(LanguageNames.CSharp, "cs")]
[DataRow(LanguageNames.VisualBasic, "vbnet")]
- public void SonarLintXmlReader_WhenAllValuesAreSet_ExpectedValues(string language, string propertyLanguage)
+ public void SonarLintXmlReader_WhenAllValuesAreSet_ExpectedValues(string language, string xmlLanguageName)
{
- var sut = CreateSonarLintXmlReader($"ResourceTests\\SonarLintXml\\All_Properties_{propertyLanguage}\\SonarLint.xml", language);
- sut.IgnoreHeaderComments.Should().BeTrue();
- sut.AnalyzeGeneratedCode.Should().BeFalse();
+ var sut = CreateSonarLintXmlReader($"ResourceTests\\SonarLintXml\\All_Properties_{xmlLanguageName}\\SonarLint.xml");
+ sut.IgnoreHeaderComments(language).Should().BeTrue();
+ sut.AnalyzeGeneratedCode(language).Should().BeFalse();
AssertArrayContent(sut.Exclusions, nameof(sut.Exclusions));
AssertArrayContent(sut.Inclusions, nameof(sut.Inclusions));
AssertArrayContent(sut.GlobalExclusions, nameof(sut.GlobalExclusions));
@@ -60,8 +61,8 @@ static void AssertArrayContent(string[] array, string folder)
public void SonarLintXmlReader_PartiallyMissingProperties_ExpectedAndDefaultValues()
{
var sut = CreateSonarLintXmlReader("ResourceTests\\SonarLintXml\\Partially_missing_properties\\SonarLint.xml");
- sut.IgnoreHeaderComments.Should().BeFalse();
- sut.AnalyzeGeneratedCode.Should().BeTrue();
+ sut.IgnoreHeaderComments(LanguageNames.CSharp).Should().BeFalse();
+ sut.AnalyzeGeneratedCode(LanguageNames.CSharp).Should().BeTrue();
AssertArrayContent(sut.Exclusions, nameof(sut.Exclusions));
AssertArrayContent(sut.Inclusions, nameof(sut.Inclusions));
sut.GlobalExclusions.Should().NotBeNull().And.HaveCount(0);
@@ -71,12 +72,22 @@ public void SonarLintXmlReader_PartiallyMissingProperties_ExpectedAndDefaultValu
sut.ParametrizedRules.Should().NotBeNull().And.HaveCount(0);
}
+ [TestMethod]
+ public void SonarLintXmlReader_PropertiesCSharpTrueVBNetFalse_ExpectedValues()
+ {
+ var sut = CreateSonarLintXmlReader("ResourceTests\\SonarLintXml\\PropertiesCSharpTrueVbnetFalse\\SonarLint.xml");
+ sut.IgnoreHeaderComments(LanguageNames.CSharp).Should().BeTrue();
+ sut.IgnoreHeaderComments(LanguageNames.VisualBasic).Should().BeFalse();
+ sut.AnalyzeGeneratedCode(LanguageNames.CSharp).Should().BeTrue();
+ sut.AnalyzeGeneratedCode(LanguageNames.VisualBasic).Should().BeFalse();
+ }
+
[DataTestMethod]
[DataRow("")]
[DataRow("this is not an xml")]
[DataRow(@"")]
public void SonarLintXmlReader_WithMalformedXml_DefaultBehaviour(string sonarLintXmlContent) =>
- CheckSonarLintXmlReaderDefaultValues(new SonarLintXmlReader(SourceText.From(sonarLintXmlContent), LanguageNames.CSharp));
+ CheckSonarLintXmlReaderDefaultValues(new SonarLintXmlReader(SourceText.From(sonarLintXmlContent)));
[TestMethod]
public void SonarLintXmlReader_MissingProperties_DefaultBehaviour() =>
@@ -90,10 +101,18 @@ public void SonarLintXmlReader_PartiallyMissingProperties_ExpectedAndDefaultValu
public void SonarLintXmlReader_CheckEmpty_DefaultBehaviour() =>
CheckSonarLintXmlReaderDefaultValues(SonarLintXmlReader.Empty);
+ [TestMethod]
+ public void SonarLintXmlReader_LanguageDoesNotExist_Throws()
+ {
+ var sut = CreateSonarLintXmlReader($"ResourceTests\\SonarLintXml\\All_Properties_cs\\SonarLint.xml");
+ sut.Invoking(x => x.IgnoreHeaderComments(LanguageNames.FSharp)).Should().Throw().WithMessage("Unexpected language: F#");
+ sut.Invoking(x => x.AnalyzeGeneratedCode(LanguageNames.FSharp)).Should().Throw().WithMessage("Unexpected language: F#");
+ }
+
private static void CheckSonarLintXmlReaderDefaultValues(SonarLintXmlReader sut)
{
- sut.AnalyzeGeneratedCode.Should().BeFalse();
- sut.IgnoreHeaderComments.Should().BeFalse();
+ sut.AnalyzeGeneratedCode(LanguageNames.CSharp).Should().BeFalse();
+ sut.IgnoreHeaderComments(LanguageNames.CSharp).Should().BeFalse();
sut.Exclusions.Should().NotBeNull().And.HaveCount(0);
sut.Inclusions.Should().NotBeNull().And.HaveCount(0);
sut.GlobalExclusions.Should().NotBeNull().And.HaveCount(0);
@@ -110,6 +129,6 @@ private static void AssertArrayContent(string[] array, string folder)
array[1].Should().BeEquivalentTo($"Fake/{folder}/Second*/**/*");
}
- private static SonarLintXmlReader CreateSonarLintXmlReader(string relativePath, string language = LanguageNames.CSharp) =>
- new(SourceText.From(File.ReadAllText(relativePath)), language);
+ private static SonarLintXmlReader CreateSonarLintXmlReader(string relativePath) =>
+ new(SourceText.From(File.ReadAllText(relativePath)));
}
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/PropertiesCSharpTrueVbnetFalse/SonarLint.xml b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/PropertiesCSharpTrueVbnetFalse/SonarLint.xml
new file mode 100644
index 00000000000..39ddbc9a84e
--- /dev/null
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/ResourceTests/SonarLintXml/PropertiesCSharpTrueVbnetFalse/SonarLint.xml
@@ -0,0 +1,21 @@
+
+
+
+
+ sonar.cs.ignoreHeaderComments
+ true
+
+
+ sonar.vbnet.ignoreHeaderComments
+ false
+
+
+ sonar.cs.analyzeGeneratedCode
+ true
+
+
+ sonar.vbnet.analyzeGeneratedCode
+ false
+
+
+
\ No newline at end of file
From 62efe30fb421c75abf053ea9a63842b23df8a5ff Mon Sep 17 00:00:00 2001
From: Mary Georgiou
<89914005+mary-georgiou-sonarsource@users.noreply.github.com>
Date: Wed, 15 Mar 2023 16:53:23 +0100
Subject: [PATCH 12/14] SonarAnalysisContextBase refactoring (#6915)
---
.../SonarAnalysisContextBase.cs | 18 ++++++++-------
.../ParametrizedDiagnosticAnalyzer.cs | 2 +-
.../Helpers/SonarLintXmlReader.cs | 4 ++--
.../Rules/Utilities/UtilityAnalyzerBase.cs | 2 +-
.../SonarAnalysisContextBaseTest.cs | 16 +++++++-------
.../Helpers/ParameterLoaderTest.cs | 22 +++++++++----------
6 files changed, 33 insertions(+), 31 deletions(-)
diff --git a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
index e6f2ff25f68..90889c8ffd0 100644
--- a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
+++ b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
@@ -53,9 +53,9 @@ 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) =>
- SonarLintFile() is var sonarLintReader
- && (generatedCodeRecognizer is null || sonarLintReader.AnalyzeGeneratedCode(Compilation.Language) || !tree.IsGenerated(generatedCodeRecognizer, Compilation))
- && (tree is null || (!IsUnchanged(tree) && ShouldAnalyzeFile(sonarLintReader, tree.FilePath)));
+ SonarLintXml() is var sonarLintXml
+ && (generatedCodeRecognizer is null || sonarLintXml.AnalyzeGeneratedCode(Compilation.Language) || !tree.IsGenerated(generatedCodeRecognizer, Compilation))
+ && (tree is null || (!IsUnchanged(tree) && !IsExcluded(sonarLintXml, tree.FilePath)));
///
/// Reads configuration from SonarProjectConfig.xml file and caches the result for scope of this analysis.
@@ -79,7 +79,7 @@ public ProjectConfigReader ProjectConfiguration()
///
/// Reads the properties from the SonarLint.xml file and caches the result for the scope of this analysis.
///
- public SonarLintXmlReader SonarLintFile()
+ public SonarLintXmlReader SonarLintXml()
{
if (Options.SonarLintXml() is { } sonarLintXml)
{
@@ -121,10 +121,12 @@ public bool HasMatchingScope(DiagnosticDescriptor descriptor)
descriptor.CustomTags.Contains(tag);
}
- private bool ShouldAnalyzeFile(SonarLintXmlReader sonarLintXml, string filePath) =>
- ProjectConfiguration().ProjectType != ProjectType.Unknown // Not SonarLint context, NuGet or Scanner <= 5.0
- || (FileInclusionCache.GetValue(Compilation, _ => new()) is var cache
- && cache.GetOrAdd(filePath, _ => IsFileIncluded(sonarLintXml, filePath)));
+ private bool IsExcluded(SonarLintXmlReader sonarLintXml, string filePath) =>
+ // If ProjectType is not 'Unknown' it means we are in S4NET context and all files are analyzed.
+ // If ProjectType is 'Unknown' then we are in SonarLint or NuGet context and we need to check if the file has been excluded from analysis through SonarLint.xml.
+ ProjectConfiguration().ProjectType == ProjectType.Unknown
+ && FileInclusionCache.GetValue(Compilation, _ => new()) is var cache
+ && !cache.GetOrAdd(filePath, _ => IsFileIncluded(sonarLintXml, filePath));
private ImmutableHashSet CreateUnchangedFilesHashSet() =>
ImmutableHashSet.Create(StringComparer.OrdinalIgnoreCase, ProjectConfiguration().AnalysisConfig?.UnchangedFiles() ?? Array.Empty());
diff --git a/analyzers/src/SonarAnalyzer.Common/DiagnosticAnalyzer/ParametrizedDiagnosticAnalyzer.cs b/analyzers/src/SonarAnalyzer.Common/DiagnosticAnalyzer/ParametrizedDiagnosticAnalyzer.cs
index cb3d06010dd..46f7ea5533a 100644
--- a/analyzers/src/SonarAnalyzer.Common/DiagnosticAnalyzer/ParametrizedDiagnosticAnalyzer.cs
+++ b/analyzers/src/SonarAnalyzer.Common/DiagnosticAnalyzer/ParametrizedDiagnosticAnalyzer.cs
@@ -32,7 +32,7 @@ protected sealed override void Initialize(SonarAnalysisContext context)
context.RegisterCompilationStartAction(
c =>
{
- ParameterLoader.SetParameterValues(this, c.SonarLintFile());
+ ParameterLoader.SetParameterValues(this, c.SonarLintXml());
parameterContext.ExecutePostponedActions(c);
});
}
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
index 77cfddc9c1e..3f9af7d7d45 100644
--- a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
@@ -100,8 +100,8 @@ private static SonarLintXml ParseContent(SourceText sonarLintXml)
private string ReadSettingsProperty(string property) =>
sonarLintXml is { Settings: { } settings }
- ? settings.Where(x => x.Key.Equals(property)).Select(x => x.Value).FirstOrDefault()
- : string.Empty;
+ ? settings.Where(x => x.Key.Equals(property)).Select(x => x.Value).FirstOrDefault()
+ : null;
private static string[] ReadCommaSeparatedArray(string str) =>
string.IsNullOrEmpty(str) ? Array.Empty() : str.Split(',');
diff --git a/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs b/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs
index 65627b91f2f..c2508a645c2 100644
--- a/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Rules/Utilities/UtilityAnalyzerBase.cs
@@ -60,7 +60,7 @@ protected void ReadParameters(SonarCompilationStartAnalysisContext context)
}
if (context.Options.SonarLintXml() != null && !string.IsNullOrEmpty(outPath))
{
- var sonarLintXml = context.SonarLintFile();
+ var sonarLintXml = context.SonarLintXml();
IgnoreHeaderComments = sonarLintXml.IgnoreHeaderComments(context.Compilation.Language);
AnalyzeGeneratedCode = sonarLintXml.AnalyzeGeneratedCode(context.Compilation.Language);
OutPath = Path.Combine(outPath, context.Compilation.Language == LanguageNames.CSharp ? "output-cs" : "output-vbnet");
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs
index f527dd092a9..bc44a11477e 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/AnalysisContext/SonarAnalysisContextBaseTest.cs
@@ -179,7 +179,7 @@ public void SonarLintFile_LoadsExpectedValues(string language)
var analyzerLanguage = language == "cs" ? AnalyzerLanguage.CSharp : AnalyzerLanguage.VisualBasic;
var (compilation, _) = CreateDummyCompilation(analyzerLanguage, "ExtraEmptyFile");
var options = AnalysisScaffolding.CreateOptions($"ResourceTests\\SonarLintXml\\All_properties_{language}\\SonarLint.xml");
- var sut = CreateSut(compilation, options).SonarLintFile();
+ var sut = CreateSut(compilation, options).SonarLintXml();
sut.IgnoreHeaderComments(analyzerLanguage.LanguageName).Should().BeTrue();
sut.AnalyzeGeneratedCode(analyzerLanguage.LanguageName).Should().BeFalse();
@@ -204,8 +204,8 @@ public void SonarLintFile_UsesCachedValue()
var options = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
var firstSut = CreateSut(options);
var secondSut = CreateSut(options);
- var firstFile = firstSut.SonarLintFile();
- var secondFile = secondSut.SonarLintFile();
+ var firstFile = firstSut.SonarLintXml();
+ var secondFile = secondSut.SonarLintXml();
secondFile.Should().BeSameAs(firstFile);
}
@@ -215,8 +215,8 @@ public void SonarLintFile_WhenFileChanges_RebuildsCache()
{
var firstOptions = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\All_properties_cs\\SonarLint.xml");
var secondOptions = AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\All_properties_vbnet\\SonarLint.xml");
- var firstFile = CreateSut(firstOptions).SonarLintFile();
- var secondFile = CreateSut(secondOptions).SonarLintFile();
+ var firstFile = CreateSut(firstOptions).SonarLintXml();
+ var secondFile = CreateSut(secondOptions).SonarLintXml();
secondFile.Should().NotBeSameAs(firstFile);
}
@@ -229,14 +229,14 @@ public void SonarLintFile_WhenFileChanges_RebuildsCache()
[DataRow("path//SonarLint.xmla")] // different extension
public void SonarLintFile_WhenAdditionalFileNotPresent_ReturnsDefaultValues(string folder)
{
- var sut = CreateSut(AnalysisScaffolding.CreateOptions(folder)).SonarLintFile();
+ var sut = CreateSut(AnalysisScaffolding.CreateOptions(folder)).SonarLintXml();
CheckSonarLintXmlDefaultValues(sut);
}
[TestMethod]
public void SonarLintFile_WhenInvalidXml_ReturnsDefaultValues()
{
- var sut = CreateSut(AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\Invalid_Xml\\SonarLint.xml")).SonarLintFile();
+ var sut = CreateSut(AnalysisScaffolding.CreateOptions("ResourceTests\\SonarLintXml\\Invalid_Xml\\SonarLint.xml")).SonarLintXml();
CheckSonarLintXmlDefaultValues(sut);
}
@@ -245,7 +245,7 @@ public void SonarLintFile_WhenFileIsMissing_ThrowException()
{
var sut = CreateSut(AnalysisScaffolding.CreateOptions("ThisPathDoesNotExist\\SonarLint.xml"));
- sut.Invoking(x => x.SonarLintFile())
+ sut.Invoking(x => x.SonarLintXml())
.Should()
.Throw()
.WithMessage("File 'SonarLint.xml' has been added as an AdditionalFile but could not be read and parsed.");
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
index fb9a2ff026c..5d599cd21c9 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/ParameterLoaderTest.cs
@@ -41,7 +41,7 @@ public void SetParameterValues_WithInvalidSonarLintPath_DoesNotPopulateParameter
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
// Assert
analyzer.Maximum.Should().Be(3); // Default value
@@ -57,7 +57,7 @@ public void SetParameterValues_WithValidSonarLintPath_PopulatesProperties(string
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
// Assert
analyzer.Maximum.Should().Be(1); // Value from the xml file
@@ -71,7 +71,7 @@ public void SetParameterValues_SonarLintFileWithIntParameterType_PopulatesProper
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
// Assert
analyzer.Maximum.Should().Be(1); // Value from the xml file
@@ -87,7 +87,7 @@ public void SetParameterValues_SonarLintFileWithStringParameterType_PopulatesPro
var analyzer = new EnumNameShouldFollowRegex(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
// Assert
analyzer.FlagsEnumNamePattern.Should().Be(parameterValue); // value from XML file
@@ -103,7 +103,7 @@ public void SetParameterValues_SonarLintFileWithBooleanParameterType_PopulatesPr
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
// Assert
analyzer.IsRegularExpression.Should().Be(parameterValue); // value from XML file
@@ -117,7 +117,7 @@ public void SetParameterValues_SonarLintFileWithoutRuleParameters_DoesNotPopulat
var analyzer = new LineLength(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
// Assert
analyzer.Maximum.Should().Be(200); // Default value
@@ -149,7 +149,7 @@ public void SetParameterValues_CalledTwiceAfterChangeInConfigFile_UpdatesPropert
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
analyzer.Maximum.Should().Be(maxValue);
// Modify the in-memory additional file
@@ -159,7 +159,7 @@ public void SetParameterValues_CalledTwiceAfterChangeInConfigFile_UpdatesPropert
var modifiedFilePath = TestHelper.WriteFile(TestContext, "SonarLint.xml", modifiedSonarLintXml);
compilation = CreateCompilationWithOption(modifiedFilePath);
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
analyzer.Maximum.Should().Be(maxValue);
}
@@ -174,7 +174,7 @@ public void SetParameterValues_WithMalformedXml_DoesNotPopulateProperties(string
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
// Assert
analyzer.Maximum.Should().Be(3); // Default value
@@ -190,7 +190,7 @@ public void SetParameterValues_SonarLintFileWithStringInsteadOfIntParameterType_
var analyzer = new ExpressionComplexity(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
// Assert
analyzer.Maximum.Should().Be(3); // Default value
@@ -206,7 +206,7 @@ public void SetParameterValues_SonarLintFileWithStringInsteadOfBooleanParameterT
var analyzer = new CheckFileLicense(); // Cannot use mock because we use reflection to find properties.
// Act
- ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintFile());
+ ParameterLoader.SetParameterValues(analyzer, compilation.SonarLintXml());
// Assert
analyzer.IsRegularExpression.Should().BeFalse(); // Default value
From a60ea62ae62df3a6854ced9e33849436a4f5b7c0 Mon Sep 17 00:00:00 2001
From: Cristian Ambrosini
<114916336+cristian-ambrosini-sonarsource@users.noreply.github.com>
Date: Thu, 16 Mar 2023 08:32:35 +0100
Subject: [PATCH 13/14] WildcardPatternMatcher improvement (#6919)
---
.../SonarAnalysisContextBase.cs | 4 +-
.../Helpers/WildcardPatternMatcher.cs | 134 +++++++-----------
.../Helpers/WildcardPatternMatcherTest.cs | 65 +++------
3 files changed, 75 insertions(+), 128 deletions(-)
diff --git a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
index 90889c8ffd0..cc9dedd3618 100644
--- a/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
+++ b/analyzers/src/SonarAnalyzer.Common/AnalysisContext/SonarAnalysisContextBase.cs
@@ -142,8 +142,8 @@ public bool HasMatchingScope(DiagnosticDescriptor descriptor)
&& !IsExcluded(globalExclusions, filePath);
private static bool IsIncluded(string[] inclusions, string filePath) =>
- inclusions is { Length: 0 } || inclusions.Any(x => WildcardPatternMatcher.IsMatch(x, filePath));
+ inclusions is { Length: 0 } || inclusions.Any(x => WildcardPatternMatcher.IsMatch(x, filePath, true));
private static bool IsExcluded(string[] exclusions, string filePath) =>
- exclusions.Any(x => WildcardPatternMatcher.IsMatch(x, filePath));
+ exclusions.Any(x => WildcardPatternMatcher.IsMatch(x, filePath, false));
}
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/WildcardPatternMatcher.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/WildcardPatternMatcher.cs
index b72a702d8e9..1054d7d867b 100644
--- a/analyzers/src/SonarAnalyzer.Common/Helpers/WildcardPatternMatcher.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/WildcardPatternMatcher.cs
@@ -27,108 +27,76 @@ namespace SonarAnalyzer.Helpers;
internal static class WildcardPatternMatcher
{
- public static bool IsMatch(string pattern, string input) =>
+ private static readonly ConcurrentDictionary Cache = new();
+
+ public static bool IsMatch(string pattern, string input, bool timeoutFallbackResult) =>
!(string.IsNullOrWhiteSpace(pattern) || string.IsNullOrWhiteSpace(input))
- && WildcardPattern.Create(pattern).Match(input);
+ && Cache.GetOrAdd(pattern, _ => new Regex(ToRegex(pattern), RegexOptions.None, RegexConstants.DefaultTimeout)) is var regex
+ && IsMatch(regex, input, timeoutFallbackResult);
- ///
- /// Copied from https://github.com/SonarSource/sonar-plugin-api/blob/a9bd7ff48f0f77811ed909070030678c443c975a/sonar-plugin-api/src/main/java/org/sonar/api/utils/WildcardPattern.java.
- ///
- private sealed class WildcardPattern
+ private static bool IsMatch(Regex regex, string value, bool timeoutFallbackResult)
{
- private const string SpecialChars = "()[]^$.{}+|";
- private static readonly ConcurrentDictionary Cache = new();
- private readonly Regex pattern;
-
- private WildcardPattern(string pattern, string directorySeparator) =>
- this.pattern = new Regex(ToRegexp(pattern, directorySeparator), RegexOptions.Compiled, RegexConstants.DefaultTimeout);
-
- public bool Match(string value)
+ try
{
- value = value.TrimStart('/');
- value = value.TrimEnd('/');
- try
- {
- return pattern.IsMatch(value);
- }
- catch (RegexMatchTimeoutException)
- {
- return false;
- }
+ return regex.IsMatch(value.Trim('/'));
}
-
- public static WildcardPattern Create(string pattern) =>
- Create(pattern, Path.DirectorySeparatorChar.ToString());
-
- private static WildcardPattern Create(string pattern, string directorySeparator) =>
- Cache.GetOrAdd(pattern + directorySeparator, _ => new WildcardPattern(pattern, directorySeparator));
-
- private static string ToRegexp(string wildcardPattern, string directorySeparator)
+ catch (RegexMatchTimeoutException)
{
- var escapedDirectorySeparator = '\\' + directorySeparator;
- var sb = new StringBuilder(wildcardPattern.Length);
-
- sb.Append('^');
+ return timeoutFallbackResult;
+ }
+ }
- var i = wildcardPattern.StartsWith("/") || wildcardPattern.StartsWith("\\") ? 1 : 0;
- while (i < wildcardPattern.Length)
+ ///
+ /// Copied from https://github.com/SonarSource/sonar-plugin-api/blob/a9bd7ff48f0f77811ed909070030678c443c975a/sonar-plugin-api/src/main/java/org/sonar/api/utils/WildcardPattern.java.
+ ///
+ private static string ToRegex(string wildcardPattern)
+ {
+ var escapedDirectorySeparator = Regex.Escape(Path.DirectorySeparatorChar.ToString());
+ var sb = new StringBuilder("^", wildcardPattern.Length);
+ var i = IsSlash(wildcardPattern[0]) ? 1 : 0;
+ while (i < wildcardPattern.Length)
+ {
+ var ch = wildcardPattern[i];
+ if (ch == '*')
{
- var ch = wildcardPattern[i];
-
- if (SpecialChars.IndexOf(ch) != -1)
+ if (i + 1 < wildcardPattern.Length && wildcardPattern[i + 1] == '*')
{
- // Escape regexp-specific characters
- sb.Append('\\').Append(ch);
- }
- else if (ch == '*')
- {
- if (i + 1 < wildcardPattern.Length && wildcardPattern[i + 1] == '*')
+ // Double asterisk - Zero or more directories
+ if (i + 2 < wildcardPattern.Length && IsSlash(wildcardPattern[i + 2]))
{
- // Double asterisk
- // Zero or more directories
- if (i + 2 < wildcardPattern.Length && IsSlash(wildcardPattern[i + 2]))
- {
- sb.Append("(?:.*").Append(escapedDirectorySeparator).Append("|)");
- i += 2;
- }
- else
- {
- sb.Append(".*");
- i += 1;
- }
+ sb.Append($"(.*{escapedDirectorySeparator}|)");
+ i += 2;
}
else
{
- // Single asterisk
- // Zero or more characters excluding directory separator
- sb.Append("[^").Append(escapedDirectorySeparator).Append("]*?");
+ sb.Append(".*");
+ i += 1;
}
}
- else if (ch == '?')
- {
- // Any single character excluding directory separator
- sb.Append("[^").Append(escapedDirectorySeparator).Append("]");
- }
- else if (IsSlash(ch))
- {
- // Directory separator
- sb.Append(escapedDirectorySeparator);
- }
else
{
- // Single character
- sb.Append(ch);
+ // Single asterisk - Zero or more characters excluding directory separator
+ sb.Append($"[^{escapedDirectorySeparator}]*?");
}
-
- i++;
}
-
- sb.Append('$');
-
- return sb.ToString();
+ else if (ch == '?')
+ {
+ // Any single character excluding directory separator
+ sb.Append($"[^{escapedDirectorySeparator}]");
+ }
+ else if (IsSlash(ch))
+ {
+ sb.Append(escapedDirectorySeparator);
+ }
+ else
+ {
+ sb.Append(Regex.Escape(ch.ToString()));
+ }
+ i++;
}
-
- private static bool IsSlash(char ch) =>
- ch == '/' || ch == '\\';
+ return sb.Append('$').ToString();
}
+
+ private static bool IsSlash(char ch) =>
+ ch == '/' || ch == '\\';
}
diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/WildcardPatternMatcherTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/WildcardPatternMatcherTest.cs
index f8b02ce4aa8..79273d566d2 100644
--- a/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/WildcardPatternMatcherTest.cs
+++ b/analyzers/tests/SonarAnalyzer.UnitTest/Helpers/WildcardPatternMatcherTest.cs
@@ -29,87 +29,66 @@ public class WildcardPatternMatcherTest
/// Based on https://github.com/SonarSource/sonar-plugin-api/blob/master/plugin-api/src/test/java/org/sonar/api/utils/WildcardPatternTest.java.
///
[DataTestMethod]
-
[DataRow("Foo", "Foo", true)]
[DataRow("foo", "FOO", false)]
[DataRow("Foo", "Foot", false)]
[DataRow("Foo", "Bar", false)]
-
- [DataRow("org/T?st.java", "org/Test.java", true)]
- [DataRow("org/T?st.java", "org/Tost.java", true)]
- [DataRow("org/T?st.java", "org/Teeest.java", false)]
-
- [DataRow("org/*.java", "org/Foo.java", true)]
- [DataRow("org/*.java", "org/Bar.java", true)]
-
- [DataRow("org/**", "org/Foo.java", true)]
+ [DataRow("org/T?st.cs", "org/Test.cs", true)]
+ [DataRow("org/T?st.cs", "org/Tost.cs", true)]
+ [DataRow("org/T?st.cs", "org/Teeest.cs", false)]
+ [DataRow("org/*.cs", "org/Foo.cs", true)]
+ [DataRow("org/*.cs", "org/Bar.cs", true)]
+ [DataRow("org/**", "org/Foo.cs", true)]
[DataRow("org/**", "org/foo/bar.jsp", true)]
-
- [DataRow("org/**/Test.java", "org/Test.java", true)]
- [DataRow("org/**/Test.java", "org/foo/Test.java", true)]
- [DataRow("org/**/Test.java", "org/foo/bar/Test.java", true)]
-
- [DataRow("org/**/*.java", "org/Foo.java", true)]
- [DataRow("org/**/*.java", "org/foo/Bar.java", true)]
- [DataRow("org/**/*.java", "org/foo/bar/Baz.java", true)]
-
- [DataRow("o?/**/*.java", "org/test.java", false)]
- [DataRow("o?/**/*.java", "o/test.java", false)]
- [DataRow("o?/**/*.java", "og/test.java", true)]
- [DataRow("o?/**/*.java", "og/foo/bar/test.java", true)]
- [DataRow("o?/**/*.java", "og/foo/bar/test.jav", false)]
-
+ [DataRow("org/**/Test.cs", "org/Test.cs", true)]
+ [DataRow("org/**/Test.cs", "org/foo/Test.cs", true)]
+ [DataRow("org/**/Test.cs", "org/foo/bar/Test.cs", true)]
+ [DataRow("org/**/*.cs", "org/Foo.cs", true)]
+ [DataRow("org/**/*.cs", "org/foo/Bar.cs", true)]
+ [DataRow("org/**/*.cs", "org/foo/bar/Baz.cs", true)]
+ [DataRow("o?/**/*.cs", "org/test.cs", false)]
+ [DataRow("o?/**/*.cs", "o/test.cs", false)]
+ [DataRow("o?/**/*.cs", "og/test.cs", true)]
+ [DataRow("o?/**/*.cs", "og/foo/bar/test.cs", true)]
+ [DataRow("o?/**/*.cs", "og/foo/bar/test.c", false)]
[DataRow("org/sonar/**", "org/sonar/commons/Foo", true)]
- [DataRow("org/sonar/**", "org/sonar/Foo.java", true)]
-
+ [DataRow("org/sonar/**", "org/sonar/Foo.cs", true)]
[DataRow("xxx/org/sonar/**", "org/sonar/Foo", false)]
-
[DataRow("org/sonar/**/**", "org/sonar/commons/Foo", true)]
- [DataRow("org/sonar/**/**", "org/sonar/commons/sub/Foo.java", true)]
-
+ [DataRow("org/sonar/**/**", "org/sonar/commons/sub/Foo.cs", true)]
[DataRow("org/sonar/**/Foo", "org/sonar/commons/sub/Foo", true)]
[DataRow("org/sonar/**/Foo", "org/sonar/Foo", true)]
-
[DataRow("*/foo/*", "org/foo/Bar", true)]
[DataRow("*/foo/*", "foo/Bar", false)]
[DataRow("*/foo/*", "foo", false)]
[DataRow("*/foo/*", "org/foo/bar/Hello", false)]
-
[DataRow("hell?", "hell", false)]
[DataRow("hell?", "hello", true)]
[DataRow("hell?", "helloworld", false)]
-
[DataRow("**/Reader", "java/io/Reader", true)]
[DataRow("**/Reader", "org/sonar/channel/CodeReader", false)]
-
[DataRow("**", "java/io/Reader", true)]
-
[DataRow("**/app/**", "com/app/Utils", true)]
[DataRow("**/app/**", "com/application/MyService", false)]
-
[DataRow("**/*$*", "foo/bar", false)]
[DataRow("**/*$*", "foo/bar$baz", true)]
[DataRow("a+", "aa", false)]
[DataRow("a+", "a+", true)]
[DataRow("[ab]", "a", false)]
[DataRow("[ab]", "[ab]", true)]
-
[DataRow("\\n", "\n", false)]
[DataRow("foo\\bar", "foo/bar", true)]
-
[DataRow("/foo", "foo", true)]
[DataRow("\\foo", "foo", true)]
-
[DataRow("foo\\bar", "foo\\bar", true)]
[DataRow("foo/bar", "foo\\bar", true)]
[DataRow("foo\\bar/baz", "foo\\bar\\baz", true)]
-
public void IsMatch_MatchesPatternsAsExpected(string pattern, string input, bool expectedResult)
{
// The test cases are copied from the plugin-api and the directory separators need replacing as Roslyn will not give us the paths with '/'.
input = input.Replace("/", Path.DirectorySeparatorChar.ToString());
- WildcardPatternMatcher.IsMatch(pattern, input).Should().Be(expectedResult);
+ WildcardPatternMatcher.IsMatch(pattern, input, false).Should().Be(expectedResult);
}
[DataTestMethod]
@@ -118,12 +97,12 @@ public void IsMatch_MatchesPatternsAsExpected(string pattern, string input, bool
[DataRow("/")]
[DataRow("\\")]
public void IsMatch_InvalidPattern_ReturnsFalse(string pattern) =>
- WildcardPatternMatcher.IsMatch(pattern, "foo").Should().BeFalse();
+ WildcardPatternMatcher.IsMatch(pattern, "foo", false).Should().BeFalse();
[DataTestMethod]
[DataRow(null, "foo")]
[DataRow("foo", null)]
public void IsMatch_InputParametersArenull_DoesNotThrow(string pattern, string input) =>
- WildcardPatternMatcher.IsMatch(pattern, input).Should().BeFalse();
+ WildcardPatternMatcher.IsMatch(pattern, input, false).Should().BeFalse();
}
}
From a1797220dc443e848fc1a8b73f2bf1e0417df104 Mon Sep 17 00:00:00 2001
From: Cristian Ambrosini
<114916336+cristian-ambrosini-sonarsource@users.noreply.github.com>
Date: Thu, 16 Mar 2023 13:47:08 +0100
Subject: [PATCH 14/14] SonarLintXmlReader revert to previous ReadContent
implementation (#6939)
---
.../src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
index 3f9af7d7d45..ec69d9c96a3 100644
--- a/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
+++ b/analyzers/src/SonarAnalyzer.Common/Helpers/SonarLintXmlReader.cs
@@ -81,11 +81,8 @@ private static SonarLintXml ParseContent(SourceText sonarLintXml)
try
{
var serializer = new XmlSerializer(typeof(SonarLintXml));
- var byteArray = Encoding.UTF8.GetBytes(sonarLintXml.ToString());
- var stream = new MemoryStream(byteArray);
- using var sr = new StreamReader(stream, Encoding.UTF8, false);
- using var reader = XmlReader.Create(sr);
- return (SonarLintXml)serializer.Deserialize(reader);
+ using var sr = new StringReader(sonarLintXml.ToString());
+ return (SonarLintXml)serializer.Deserialize(sr);
}
catch
{