From 34758610db46d37ad685d4f0be4fa7f8646e7001 Mon Sep 17 00:00:00 2001 From: Martin Strecker <103252490+martin-strecker-sonarsource@users.noreply.github.com> Date: Tue, 20 Jun 2023 11:45:47 +0200 Subject: [PATCH] Fix S2077 FN: Add support for Mono.Data.Sqlite (#7466) --- .../SonarAnalyzer.Common/Helpers/KnownType.cs | 2 + .../Rules/Hotspots/ExecutingSqlQueriesBase.cs | 2 + .../NuGetMetadataReference.cs | 1 + .../Rules/Hotspots/ExecutingSqlQueriesTest.cs | 16 ++++++++ .../ExecutingSqlQueries.Net46.MonoSqlLite.cs | 38 +++++++++++++++++++ .../ExecutingSqlQueries.Net46.MonoSqlLite.vb | 21 ++++++++++ 6 files changed, 80 insertions(+) create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/TestCases/Hotspots/ExecutingSqlQueries.Net46.MonoSqlLite.cs create mode 100644 analyzers/tests/SonarAnalyzer.UnitTest/TestCases/Hotspots/ExecutingSqlQueries.Net46.MonoSqlLite.vb diff --git a/analyzers/src/SonarAnalyzer.Common/Helpers/KnownType.cs b/analyzers/src/SonarAnalyzer.Common/Helpers/KnownType.cs index 86233899504..fffb6c2186c 100644 --- a/analyzers/src/SonarAnalyzer.Common/Helpers/KnownType.cs +++ b/analyzers/src/SonarAnalyzer.Common/Helpers/KnownType.cs @@ -124,6 +124,8 @@ public sealed partial class KnownType public static readonly KnownType Microsoft_VisualStudio_TestTools_UnitTesting_TestInitializeAttribute = new("Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute"); public static readonly KnownType Microsoft_Web_XmlTransform_XmlFileInfoDocument = new("Microsoft.Web.XmlTransform.XmlFileInfoDocument"); public static readonly KnownType Microsoft_Web_XmlTransform_XmlTransformableDocument = new("Microsoft.Web.XmlTransform.XmlTransformableDocument"); + public static readonly KnownType Mono_Data_Sqlite_SqliteCommand = new("Mono.Data.Sqlite.SqliteCommand"); + public static readonly KnownType Mono_Data_Sqlite_SqliteDataAdapter = new("Mono.Data.Sqlite.SqliteDataAdapter"); public static readonly KnownType Mono_Unix_FileAccessPermissions = new("Mono.Unix.FileAccessPermissions"); public static readonly KnownType MySql_Data_MySqlClient_MySqlDataAdapter = new("MySql.Data.MySqlClient.MySqlDataAdapter"); public static readonly KnownType MySql_Data_MySqlClient_MySqlCommand = new("MySql.Data.MySqlClient.MySqlCommand"); diff --git a/analyzers/src/SonarAnalyzer.Common/Rules/Hotspots/ExecutingSqlQueriesBase.cs b/analyzers/src/SonarAnalyzer.Common/Rules/Hotspots/ExecutingSqlQueriesBase.cs index 24291ea7d4f..68c1b955a14 100644 --- a/analyzers/src/SonarAnalyzer.Common/Rules/Hotspots/ExecutingSqlQueriesBase.cs +++ b/analyzers/src/SonarAnalyzer.Common/Rules/Hotspots/ExecutingSqlQueriesBase.cs @@ -48,6 +48,8 @@ public abstract class ExecutingSqlQueriesBase Create("Microsoft.SqlServer.Compact", packageVersion); public static References MicrosoftWebXdt(string packageVersion = "3.0.0") => Create("Microsoft.Web.Xdt", packageVersion); public static References MonoPosixNetStandard(string packageVersion = "1.0.0") => Create("Mono.Posix.NETStandard", packageVersion, "linux-x64"); + public static References MonoDataSqlite(string packageVersion = Constants.NuGetLatestVersion) => Create("Mono.Data.Sqlite", packageVersion); public static References Moq(string packageVersion) => Create("Moq", packageVersion); public static References MSTestTestFramework(string packageVersion) => Create("MSTest.TestFramework", packageVersion); public static References MvvmLightLibs(string packageVersion) => Create("MvvmLightLibs", packageVersion); diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/Hotspots/ExecutingSqlQueriesTest.cs b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/Hotspots/ExecutingSqlQueriesTest.cs index f131553da1e..824f54b685e 100644 --- a/analyzers/tests/SonarAnalyzer.UnitTest/Rules/Hotspots/ExecutingSqlQueriesTest.cs +++ b/analyzers/tests/SonarAnalyzer.UnitTest/Rules/Hotspots/ExecutingSqlQueriesTest.cs @@ -46,6 +46,22 @@ public void ExecutingSqlQueries_VB_Net46() => .AddReferences(GetReferencesNet46(Constants.NuGetLatestVersion)) .Verify(); + [TestMethod] + public void ExecutingSqlQueries_MonoSqlLite_Net46_CS() => + builderCS + .AddPaths(@"ExecutingSqlQueries.Net46.MonoSqlLite.cs") + .AddReferences(FrameworkMetadataReference.SystemData) + .AddReferences(NuGetMetadataReference.MonoDataSqlite()) + .Verify(); + + [TestMethod] + public void ExecutingSqlQueries_MonoSqlLite_Net46_VB() => + builderVB + .AddPaths(@"ExecutingSqlQueries.Net46.MonoSqlLite.vb") + .AddReferences(FrameworkMetadataReference.SystemData) + .AddReferences(NuGetMetadataReference.MonoDataSqlite()) + .Verify(); + internal static IEnumerable GetReferencesNet46(string sqlServerCeVersion) => NetStandardMetadataReference.Netstandard .Concat(FrameworkMetadataReference.SystemData) diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/Hotspots/ExecutingSqlQueries.Net46.MonoSqlLite.cs b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/Hotspots/ExecutingSqlQueries.Net46.MonoSqlLite.cs new file mode 100644 index 00000000000..c7eab21e4ab --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/Hotspots/ExecutingSqlQueries.Net46.MonoSqlLite.cs @@ -0,0 +1,38 @@ +using System; +using System.Linq; +using Mono.Data.Sqlite; + +public class Sample +{ + string ConstQuery = ""; + + void Compliant(SqliteConnection connection) + { + var command = new SqliteCommand(); // Compliant + command = new SqliteCommand(connection); // Compliant + var adapter = new SqliteDataAdapter(); // Compliant + } + + void Foo(SqliteConnection connection, string query, SqliteTransaction transaction, params object[] parameters) + { + var command = new SqliteCommand($"SELECT * FROM mytable WHERE mycol={query}", connection); // Noncompliant + command = new SqliteCommand($"SELECT * FROM mytable WHERE mycol={query}"); // Noncompliant + command = new SqliteCommand($"SELECT * FROM mytable WHERE mycol={query}", connection, transaction); // Noncompliant + var adapter = new SqliteDataAdapter(string.Concat(query, parameters), connection); // Noncompliant + adapter = new SqliteDataAdapter(string.Concat(query, parameters), "connection"); // Noncompliant + } + + // https://github.com/SonarSource/sonar-dotnet/issues/7261 + void Reproduce_7261(string connectionString, string query) + { + string sql = "select * from table where query = '" + query + "';"; // Secondary [adapter, command] + + using (SqliteConnection connection = new SqliteConnection(connectionString)) + { + connection.Open(); + + var adapter = new SqliteDataAdapter(sql, connection); // Noncompliant [adapter] + var command = new SqliteCommand(sql, connection); // Noncompliant [command] + } + } +} diff --git a/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/Hotspots/ExecutingSqlQueries.Net46.MonoSqlLite.vb b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/Hotspots/ExecutingSqlQueries.Net46.MonoSqlLite.vb new file mode 100644 index 00000000000..a6d86245c1e --- /dev/null +++ b/analyzers/tests/SonarAnalyzer.UnitTest/TestCases/Hotspots/ExecutingSqlQueries.Net46.MonoSqlLite.vb @@ -0,0 +1,21 @@ +Imports System +Imports System.Linq +Imports Mono.Data.Sqlite + +Public Class Sample + Private ConstQuery As String = "" + + Private Sub Compliant(ByVal connection As SqliteConnection) + Dim command = New SqliteCommand() ' Compliant + command = New SqliteCommand(connection) ' Compliant + Dim adapter = New SqliteDataAdapter() ' Compliant + End Sub + + Private Sub Foo(ByVal connection As SqliteConnection, transaction As SqliteTransaction, ByVal query As String, ParamArray parameters As Object()) + Dim command = New SqliteCommand($"SELECT * FROM mytable WHERE mycol={query}", connection) ' Noncompliant + command = New SqliteCommand($"SELECT * FROM mytable WHERE mycol={query}") ' Noncompliant + command = New SqliteCommand($"SELECT * FROM mytable WHERE mycol={query}", connection, transaction) ' Noncompliant + Dim adapter = New SqliteDataAdapter(String.Concat(query, parameters), connection) ' Noncompliant + adapter = New SqliteDataAdapter(String.Concat(query, parameters), "connection") ' Noncompliant + End Sub +End Class