diff --git a/src/SLCore.UnitTests/Service/Rules/GetEffectiveRuleDetailsResponseTests.cs b/src/SLCore.UnitTests/Service/Rules/GetEffectiveRuleDetailsResponseTests.cs
new file mode 100644
index 0000000000..ef00526dc0
--- /dev/null
+++ b/src/SLCore.UnitTests/Service/Rules/GetEffectiveRuleDetailsResponseTests.cs
@@ -0,0 +1,114 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info 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.Generic;
+using FluentAssertions.Equivalency;
+using Newtonsoft.Json;
+using SonarLint.VisualStudio.SLCore.Common.Models;
+using SonarLint.VisualStudio.SLCore.Protocol;
+using SonarLint.VisualStudio.SLCore.Service.Rules;
+using SonarLint.VisualStudio.SLCore.Service.Rules.Models;
+
+namespace SonarLint.VisualStudio.SLCore.UnitTests.Service.Rules;
+
+[TestClass]
+public class GetEffectiveRuleDetailsResponseTests
+{
+ [TestMethod]
+ public void DeserializeSlcoreResponse_AsExpected()
+ {
+ const string slcoreResponse = """
+ {
+ "details": {
+ "description": {
+ "introductionHtmlContent": "
This rule raises an issue when the code cognitive complexity of a function is above a certain threshold.
",
+ "tabs": [
+ {
+ "title": "Why is this an issue?",
+ "content": {
+ "htmlContent": "
Cognitive Complexity is a measure of how hard it is to understand the control flow of a unit of code. Code with high cognitive complexity is hard\nto read, understand, test, and modify.
\n
As a rule of thumb, high cognitive complexity is a sign that the code should be refactored into smaller, easier-to-manage pieces.
\n
Which syntax in code does impact cognitive complexity score?
\n
Here are the core concepts:
\n
\n
Cognitive complexity is incremented each time the code breaks the normal linear reading flow. This concerns, for example:\n Loop structures, Conditionals, Catches, Switches, Jumps to label and mixed operators in condition.
\n
Each nesting level adds a malus to the breaking call. During code reading, the deeper you go through nested layers, the\n harder it becomes to keep the context in mind.
\n
Method calls are free A well-picked method name is a summary of multiple lines of code. A reader can first explore a\n high-level view of what the code is performing then go deeper and deeper by looking at called functions content. Note: This does not\n apply to recursive calls, those will increment cognitive score.
\n
\n
The method of computation is fully detailed in the pdf linked in the resources.
\n
What is the potential impact?
\n
Developers spend more time reading and understanding code than writing it. High cognitive complexity slows down changes and increases the cost of\nmaintenance.
"
+ }
+ },
+ {
+ "title": "How can I fix it?",
+ "content": {
+ "htmlContent": "
Reducing cognitive complexity can be challenging. Here are a few suggestions:
\n
\n
Extract complex conditions in a new function. Mixed operators in condition will increase complexity. Extracting the\n condition in a new function with an appropriate name will reduce cognitive load.
\n
Break down large functions. Large functions can be hard to understand and maintain. If a function is doing too many\n things, consider breaking it down into smaller, more manageable functions. Each function should have a single responsibility.
\n
Avoid deep nesting by returning early. To avoid the nesting of conditions, process exceptional cases first and return\n early.
\n
Use null-safe operations (if available in the language). When available the .? or ?? operator\n replaces multiple tests and simplifies the flow.
\n
\n\n
Extraction of a complex condition in a new function.
\n
Noncompliant code example
\n
The code is using a complex condition and has a cognitive cost of 3.
\n
\nfunction calculateFinalPrice(user, cart) {\n let total = calculateTotal(cart);\n if (user.hasMembership // +1 (if)\n && user.orders > 10 // +1 (more than one condition)\n && user.accountActive\n && !user.hasDiscount\n || user.orders === 1) { // +1 (change of operator in condition)\n total = applyDiscount(user, total);\n }\n return total;\n}\n
\n
Compliant solution
\n
Even if the cognitive complexity of the whole program did not change, it is easier for a reader to understand the code of the\ncalculateFinalPrice function, which now only has a cognitive cost of 1.
\n
\nfunction calculateFinalPrice(user, cart) {\n let total = calculateTotal(cart);\n if (isEligibleForDiscount(user)) { // +1 (if)\n total = applyDiscount(user, total);\n }\n return total;\n}\n\nfunction isEligibleForDiscount(user) {\n return user.hasMembership\n && user.orders > 10 // +1 (more than one condition)\n && user.accountActive\n && !user.hasDiscount\n || user.orders === 1 // +1 (change of operator in condition)\n}\n
\n
Break down large functions.
\n
Noncompliant code example
\n
For example, consider a function that calculates the total price of a shopping cart, including sales tax and shipping. Note: The code\nis simplified here, to illustrate the purpose. Please imagine there is more happening in the for loops.
\n
\nfunction calculateTotal(cart) {\n let total = 0;\n for (let i = 0; i < cart.length; i++) { // +1 (for)\n total += cart[i].price;\n }\n\n // calculateSalesTax\n for (let i = 0; i < cart.length; i++) { // +1 (for)\n total += 0.2 * cart[i].price;\n }\n\n //calculateShipping\n total += 5 * cart.length;\n\n return total;\n}\n
\n
This function could be refactored into smaller functions: The complexity is spread over multiple functions and the complex\ncalculateTotal has now a complexity score of zero.
\n
Compliant solution
\n
\nfunction calculateTotal(cart) {\n let total = calculateSubtotal(cart);\n total += calculateSalesTax(cart);\n total += calculateShipping(cart);\n return total;\n}\n\nfunction calculateSubtotal(cart) {\n let subTotal = 0;\n for (const item of cart) { // +1 (for)\n subTotal += item.price;\n }\n return subTotal;\n}\n\nfunction calculateSalesTax(cart) {\n let salesTax = 0;\n for (const item of cart) { // +1 (for)\n salesTax += 0.2 * item.price;\n }\n return salesTax;\n}\n\nfunction calculateShipping(cart) {\n return 5 * cart.length;\n}\n
Checking for the edge case first flattens the if statements and reduces the cognitive complexity to 3.
\n
\nfunction calculateDiscount(price, user) {\n if (!isEligibleForDiscount(user)) { // +1 ( if )\n return price;\n }\n if (user?.hasMembership) { // +1 ( if )\n return price * 0.9;\n }\n if (user?.orders === 1) { // +1 ( if )\n return price * 0.95;\n }\n return price;\n}\n
\n
Use the optional chaining operator to access data.
\n
In the below code, the cognitive complexity is increased due to the multiple checks required to access the manufacturer’s name. This can be\nsimplified using the optional chaining operator.
dsfsfsd"
+ }
+ }
+ ]
+ },
+ "params": [],
+ "key": "javascript:S3776",
+ "name": "Cognitive Complexity of functions should not be too high",
+ "severity": "CRITICAL",
+ "type": "CODE_SMELL",
+ "cleanCodeAttribute": "FOCUSED",
+ "cleanCodeAttributeCategory": "ADAPTABLE",
+ "defaultImpacts": [
+ {
+ "softwareQuality": "MAINTAINABILITY",
+ "impactSeverity": "HIGH"
+ }
+ ],
+ "language": "JS"
+ }
+ }
+ """;
+ var ruleDetailsResponse = JsonConvert.DeserializeObject(slcoreResponse);
+
+ var expectedRuleDetails = new GetEffectiveRuleDetailsResponse(new EffectiveRuleDetailsDto(
+ key:"javascript:S3776",
+ name:"Cognitive Complexity of functions should not be too high",
+ severity:IssueSeverity.CRITICAL,
+ type:RuleType.CODE_SMELL,
+ cleanCodeAttribute:CleanCodeAttribute.FOCUSED,
+ cleanCodeAttributeCategory:CleanCodeAttributeCategory.ADAPTABLE,
+ defaultImpacts:new List
+ {
+ new(SoftwareQuality.MAINTAINABILITY, ImpactSeverity.HIGH)
+ },
+ Language.JS,
+ null,
+ Either.CreateRight(
+ new RuleSplitDescriptionDto(
+ "
This rule raises an issue when the code cognitive complexity of a function is above a certain threshold.
",
+ new List
+ {
+ new("Why is this an issue?", Either.CreateLeft(new RuleNonContextualSectionDto(""))),
+ new("How can I fix it?", Either.CreateLeft(new RuleNonContextualSectionDto(""))),
+ new("More Info", Either.CreateLeft(new RuleNonContextualSectionDto("")))
+ })),
+ new List()));
+
+ ruleDetailsResponse
+ .Should()
+ .BeEquivalentTo(expectedRuleDetails,
+ options => options
+ .WithStrictOrdering()
+ .RespectingDeclaredTypes()
+ .Excluding((IMemberInfo info) => info.RuntimeType == typeof(string) && info.SelectedMemberPath.EndsWith(".content.Left.htmlContent")));
+ }
+}
diff --git a/src/SLCore/Common/Models/CleanCodeAttribute.cs b/src/SLCore/Common/Models/CleanCodeAttribute.cs
new file mode 100644
index 0000000000..9c17903f18
--- /dev/null
+++ b/src/SLCore/Common/Models/CleanCodeAttribute.cs
@@ -0,0 +1,43 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info 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.
+ */
+
+namespace SonarLint.VisualStudio.SLCore.Common.Models
+{
+ public enum CleanCodeAttribute
+ {
+ CONVENTIONAL,
+ FORMATTED,
+ IDENTIFIABLE,
+
+ CLEAR,
+ COMPLETE,
+ EFFICIENT,
+ LOGICAL,
+
+ DISTINCT,
+ FOCUSED,
+ MODULAR,
+ TESTED,
+
+ LAWFUL,
+ RESPECTFUL,
+ TRUSTWORTHY
+ }
+}
diff --git a/src/SLCore/Common/Models/CleanCodeAttributeCategory.cs b/src/SLCore/Common/Models/CleanCodeAttributeCategory.cs
new file mode 100644
index 0000000000..ef44be511e
--- /dev/null
+++ b/src/SLCore/Common/Models/CleanCodeAttributeCategory.cs
@@ -0,0 +1,30 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info 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.
+ */
+
+namespace SonarLint.VisualStudio.SLCore.Common.Models
+{
+ public enum CleanCodeAttributeCategory
+ {
+ ADAPTABLE,
+ CONSISTENT,
+ INTENTIONAL,
+ RESPONSIBLE
+ }
+}
diff --git a/src/SLCore/Common/Models/ImpactSeverity.cs b/src/SLCore/Common/Models/ImpactSeverity.cs
new file mode 100644
index 0000000000..c4a7932e99
--- /dev/null
+++ b/src/SLCore/Common/Models/ImpactSeverity.cs
@@ -0,0 +1,28 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info 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.
+ */
+
+namespace SonarLint.VisualStudio.SLCore.Common.Models
+{
+ public enum ImpactSeverity {
+ LOW,
+ MEDIUM,
+ HIGH
+ }
+}
diff --git a/src/SLCore/Common/Models/IssueSeverity.cs b/src/SLCore/Common/Models/IssueSeverity.cs
new file mode 100644
index 0000000000..95ac54f9e4
--- /dev/null
+++ b/src/SLCore/Common/Models/IssueSeverity.cs
@@ -0,0 +1,31 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info 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.
+ */
+
+namespace SonarLint.VisualStudio.SLCore.Common.Models
+{
+ public enum IssueSeverity
+ {
+ INFO,
+ MINOR,
+ MAJOR,
+ CRITICAL,
+ BLOCKER
+ }
+}
diff --git a/src/SLCore/Common/Models/RuleType.cs b/src/SLCore/Common/Models/RuleType.cs
new file mode 100644
index 0000000000..06deb3e9de
--- /dev/null
+++ b/src/SLCore/Common/Models/RuleType.cs
@@ -0,0 +1,30 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info 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.
+ */
+
+namespace SonarLint.VisualStudio.SLCore.Common.Models
+{
+ public enum RuleType
+ {
+ CODE_SMELL,
+ BUG,
+ VULNERABILITY,
+ SECURITY_HOTSPOT
+ }
+}
diff --git a/src/SLCore/Common/Models/SoftwareQuality.cs b/src/SLCore/Common/Models/SoftwareQuality.cs
new file mode 100644
index 0000000000..c82c02bdaa
--- /dev/null
+++ b/src/SLCore/Common/Models/SoftwareQuality.cs
@@ -0,0 +1,29 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info 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.
+ */
+
+namespace SonarLint.VisualStudio.SLCore.Common.Models
+{
+ public enum SoftwareQuality {
+ MAINTAINABILITY,
+ RELIABILITY,
+ SECURITY
+
+ }
+}
diff --git a/src/SLCore/Service/Rules/GetEffectiveRuleDetailsParams.cs b/src/SLCore/Service/Rules/GetEffectiveRuleDetailsParams.cs
new file mode 100644
index 0000000000..28ab536702
--- /dev/null
+++ b/src/SLCore/Service/Rules/GetEffectiveRuleDetailsParams.cs
@@ -0,0 +1,37 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info 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.Diagnostics.CodeAnalysis;
+
+namespace SonarLint.VisualStudio.SLCore.Service.Rules
+{
+ [ExcludeFromCodeCoverage]
+ public class GetEffectiveRuleDetailsParams
+ {
+ public string configurationScopeId { get; }
+ public string ruleKey { get; }
+
+ public GetEffectiveRuleDetailsParams(string configurationScopeId, string ruleKey)
+ {
+ this.configurationScopeId = configurationScopeId;
+ this.ruleKey = ruleKey;
+ }
+ }
+}
diff --git a/src/SLCore/Service/Rules/GetEffectiveRuleDetailsResponse.cs b/src/SLCore/Service/Rules/GetEffectiveRuleDetailsResponse.cs
new file mode 100644
index 0000000000..29ca9eaf04
--- /dev/null
+++ b/src/SLCore/Service/Rules/GetEffectiveRuleDetailsResponse.cs
@@ -0,0 +1,34 @@
+/*
+ * SonarLint for Visual Studio
+ * Copyright (C) 2016-2024 SonarSource SA
+ * mailto:info 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 SonarLint.VisualStudio.SLCore.Service.Rules.Models;
+
+namespace SonarLint.VisualStudio.SLCore.Service.Rules
+{
+ public class GetEffectiveRuleDetailsResponse
+ {
+ public GetEffectiveRuleDetailsResponse(EffectiveRuleDetailsDto details)
+ {
+ this.details = details;
+ }
+
+ public EffectiveRuleDetailsDto details { get; }
+ }
+}
diff --git a/src/SLCore/Service/Rules/IRulesRpcService.cs b/src/SLCore/Service/Rules/IRulesRpcService.cs
index 29165db396..9a1c401a77 100644
--- a/src/SLCore/Service/Rules/IRulesRpcService.cs
+++ b/src/SLCore/Service/Rules/IRulesRpcService.cs
@@ -18,7 +18,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;
using SonarLint.VisualStudio.SLCore.Core;
using SonarLint.VisualStudio.SLCore.Protocol;
@@ -31,20 +30,6 @@ public interface IRulesRpcService : ISLCoreService
///
/// Gets Rule Meta Data from SLCORE
///
- ///
- Task