diff --git a/sonaranalyzer-dotnet/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S1135.json b/sonaranalyzer-dotnet/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S1135.json
new file mode 100644
index 00000000000..93f3c774e31
--- /dev/null
+++ b/sonaranalyzer-dotnet/its/expected/Ember-MM/EmberAPI-{208AA35E-C6AE-4D2D-A9DD-B6EFD19A4279}-S1135.json
@@ -0,0 +1,30 @@
+{
+"issues": [
+{
+"id": "S1135",
+"message": "Complete the task associated to this 'TODO' comment.",
+"location": {
+"uri": "sources\Ember-MM\EmberAPI\clsAPIImages.vb",
+"region": {
+"startLine": 458,
+"startColumn": 7,
+"endLine": 458,
+"endColumn": 11
+}
+}
+},
+{
+"id": "S1135",
+"message": "Complete the task associated to this 'TODO' comment.",
+"location": {
+"uri": "sources\Ember-MM\EmberAPI\clsAPIModules.vb",
+"region": {
+"startLine": 781,
+"startColumn": 40,
+"endLine": 781,
+"endColumn": 44
+}
+}
+}
+]
+}
diff --git a/sonaranalyzer-dotnet/its/expected/Ember-MM/generic.EmberCore.MediaFileManager-{F6CACA89-E8E4-45D9-B942-97FBD4ADD106}-S1135.json b/sonaranalyzer-dotnet/its/expected/Ember-MM/generic.EmberCore.MediaFileManager-{F6CACA89-E8E4-45D9-B942-97FBD4ADD106}-S1135.json
new file mode 100644
index 00000000000..74891856322
--- /dev/null
+++ b/sonaranalyzer-dotnet/its/expected/Ember-MM/generic.EmberCore.MediaFileManager-{F6CACA89-E8E4-45D9-B942-97FBD4ADD106}-S1135.json
@@ -0,0 +1,30 @@
+{
+"issues": [
+{
+"id": "S1135",
+"message": "Complete the task associated to this 'TODO' comment.",
+"location": {
+"uri": "sources\Ember-MM\Addons\generic.EmberCore.MediaFileManager\Module.MediaFileManagerModule.vb",
+"region": {
+"startLine": 231,
+"startColumn": 38,
+"endLine": 231,
+"endColumn": 42
+}
+}
+},
+{
+"id": "S1135",
+"message": "Complete the task associated to this 'TODO' comment.",
+"location": {
+"uri": "sources\Ember-MM\Addons\generic.EmberCore.MediaFileManager\Module.MediaFileManagerModule.vb",
+"region": {
+"startLine": 239,
+"startColumn": 38,
+"endLine": 239,
+"endColumn": 42
+}
+}
+}
+]
+}
diff --git a/sonaranalyzer-dotnet/its/expected/Ember-MM/generic.EmberCore.NMT-{84B2143A-D04F-4262-923D-21AEDF86E2B7}-S1135.json b/sonaranalyzer-dotnet/its/expected/Ember-MM/generic.EmberCore.NMT-{84B2143A-D04F-4262-923D-21AEDF86E2B7}-S1135.json
new file mode 100644
index 00000000000..11d480ee15a
--- /dev/null
+++ b/sonaranalyzer-dotnet/its/expected/Ember-MM/generic.EmberCore.NMT-{84B2143A-D04F-4262-923D-21AEDF86E2B7}-S1135.json
@@ -0,0 +1,30 @@
+{
+"issues": [
+{
+"id": "S1135",
+"message": "Complete the task associated to this 'TODO' comment.",
+"location": {
+"uri": "sources\Ember-MM\Addons\generic.EmberCore.NMT\dlgNMTMovies.vb",
+"region": {
+"startLine": 1634,
+"startColumn": 27,
+"endLine": 1634,
+"endColumn": 31
+}
+}
+},
+{
+"id": "S1135",
+"message": "Complete the task associated to this 'TODO' comment.",
+"location": {
+"uri": "sources\Ember-MM\Addons\generic.EmberCore.NMT\Module.NMT.vb",
+"region": {
+"startLine": 97,
+"startColumn": 23,
+"endLine": 97,
+"endColumn": 27
+}
+}
+}
+]
+}
diff --git a/sonaranalyzer-dotnet/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S1135.json b/sonaranalyzer-dotnet/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S1135.json
new file mode 100644
index 00000000000..11a062e6551
--- /dev/null
+++ b/sonaranalyzer-dotnet/its/expected/Ember-MM/scraper.EmberCore-{EF6A550E-DD76-4F4D-8250-8598140F828B}-S1135.json
@@ -0,0 +1,30 @@
+{
+"issues": [
+{
+"id": "S1135",
+"message": "Complete the task associated to this 'TODO' comment.",
+"location": {
+"uri": "sources\Ember-MM\Addons\scraper.EmberCore\TVScraper\dlgTVImageSelect.vb",
+"region": {
+"startLine": 21,
+"startColumn": 2,
+"endLine": 21,
+"endColumn": 6
+}
+}
+},
+{
+"id": "S1135",
+"message": "Complete the task associated to this 'TODO' comment.",
+"location": {
+"uri": "sources\Ember-MM\Addons\scraper.EmberCore\TVScraper\dlgTVImageSelect.vb",
+"region": {
+"startLine": 22,
+"startColumn": 2,
+"endLine": 22,
+"endColumn": 6
+}
+}
+}
+]
+}
diff --git a/sonaranalyzer-dotnet/rspec/vbnet/S1134_vb.net.html b/sonaranalyzer-dotnet/rspec/vbnet/S1134_vb.net.html
new file mode 100644
index 00000000000..f9913bf53d4
--- /dev/null
+++ b/sonaranalyzer-dotnet/rspec/vbnet/S1134_vb.net.html
@@ -0,0 +1,14 @@
+
FIXME
tags are commonly used to mark places where a bug is suspected, but which the developer wants to deal with later.
+Sometimes the developer will not have the time or will simply forget to get back to that tag.
+This rule is meant to track those tags and to ensure that they do not go unnoticed.
+Noncompliant Code Example
+
+Function Divide(ByVal numerator As Integer, ByVal denominator As Integer) As Integer
+ Return numerator / denominator ' FIXME denominator value might be 0
+End Function
+
+See
+
+
diff --git a/sonaranalyzer-dotnet/rspec/vbnet/S1134_vb.net.json b/sonaranalyzer-dotnet/rspec/vbnet/S1134_vb.net.json
new file mode 100644
index 00000000000..1436329b833
--- /dev/null
+++ b/sonaranalyzer-dotnet/rspec/vbnet/S1134_vb.net.json
@@ -0,0 +1,20 @@
+{
+ "title": "Track uses of \"FIXME\" tags",
+ "type": "CODE_SMELL",
+ "status": "ready",
+ "tags": [
+ "cwe"
+ ],
+ "standards": [
+ "CWE"
+ ],
+ "defaultSeverity": "Major",
+ "ruleSpecification": "RSPEC-1134",
+ "sqKey": "S1134",
+ "scope": "All",
+ "securityStandards": {
+ "CWE": [
+ 546
+ ]
+ }
+}
diff --git a/sonaranalyzer-dotnet/rspec/vbnet/S1135_vb.net.html b/sonaranalyzer-dotnet/rspec/vbnet/S1135_vb.net.html
new file mode 100644
index 00000000000..ceda945988a
--- /dev/null
+++ b/sonaranalyzer-dotnet/rspec/vbnet/S1135_vb.net.html
@@ -0,0 +1,14 @@
+TODO
tags are commonly used to mark places where some more code is required, but which the developer wants to implement later.
+Sometimes the developer will not have the time or will simply forget to get back to that tag.
+This rule is meant to track those tags and to ensure that they do not go unnoticed.
+Noncompliant Code Example
+
+Sub DoSomething()
+ ' TODO
+End Sub
+
+See
+
+
diff --git a/sonaranalyzer-dotnet/rspec/vbnet/S1135_vb.net.json b/sonaranalyzer-dotnet/rspec/vbnet/S1135_vb.net.json
new file mode 100644
index 00000000000..fefb44a0cda
--- /dev/null
+++ b/sonaranalyzer-dotnet/rspec/vbnet/S1135_vb.net.json
@@ -0,0 +1,20 @@
+{
+ "title": "Track uses of \"TODO\" tags",
+ "type": "CODE_SMELL",
+ "status": "ready",
+ "tags": [
+ "cwe"
+ ],
+ "standards": [
+ "CWE"
+ ],
+ "defaultSeverity": "Info",
+ "ruleSpecification": "RSPEC-1135",
+ "sqKey": "S1135",
+ "scope": "All",
+ "securityStandards": {
+ "CWE": [
+ 546
+ ]
+ }
+}
diff --git a/sonaranalyzer-dotnet/rspec/vbnet/Sonar_way_profile.json b/sonaranalyzer-dotnet/rspec/vbnet/Sonar_way_profile.json
index f04cfd4cc73..ebd9f51bc60 100644
--- a/sonaranalyzer-dotnet/rspec/vbnet/Sonar_way_profile.json
+++ b/sonaranalyzer-dotnet/rspec/vbnet/Sonar_way_profile.json
@@ -7,6 +7,8 @@
"S117",
"S1048",
"S1075",
+ "S1134",
+ "S1135",
"S1186",
"S1197",
"S1313",
diff --git a/sonaranalyzer-dotnet/rspec/vbnet/Sonar_way_profile_no_hotspot.json b/sonaranalyzer-dotnet/rspec/vbnet/Sonar_way_profile_no_hotspot.json
index 6bfe798077b..bf4c7667720 100644
--- a/sonaranalyzer-dotnet/rspec/vbnet/Sonar_way_profile_no_hotspot.json
+++ b/sonaranalyzer-dotnet/rspec/vbnet/Sonar_way_profile_no_hotspot.json
@@ -7,6 +7,8 @@
"S117",
"S1048",
"S1075",
+ "S1134",
+ "S1135",
"S1186",
"S1197",
"S1479",
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Helpers/CSharpSyntaxHelper.cs b/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Helpers/CSharpSyntaxHelper.cs
index 00a32826b0e..050b75a3d74 100644
--- a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Helpers/CSharpSyntaxHelper.cs
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Helpers/CSharpSyntaxHelper.cs
@@ -346,5 +346,20 @@ public static bool IsLeftSideOfAssignment(this ExpressionSyntax expression)
topParenthesizedExpression.Parent is AssignmentExpressionSyntax assignment &&
assignment.Left == topParenthesizedExpression;
}
+
+ public static bool IsComment(this SyntaxTrivia trivia)
+ {
+ switch (trivia.Kind())
+ {
+ case SyntaxKind.SingleLineCommentTrivia:
+ case SyntaxKind.MultiLineCommentTrivia:
+ case SyntaxKind.SingleLineDocumentationCommentTrivia:
+ case SyntaxKind.MultiLineDocumentationCommentTrivia:
+ return true;
+
+ default:
+ return false;
+ }
+ }
}
}
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Metrics/CSharpMetrics.cs b/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Metrics/CSharpMetrics.cs
index df8035a8212..ffb57e380d7 100644
--- a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Metrics/CSharpMetrics.cs
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Metrics/CSharpMetrics.cs
@@ -74,20 +74,7 @@ protected override bool IsClass(SyntaxNode node)
}
}
- protected override bool IsCommentTrivia(SyntaxTrivia trivia)
- {
- switch (trivia.Kind())
- {
- case SyntaxKind.SingleLineCommentTrivia:
- case SyntaxKind.MultiLineCommentTrivia:
- case SyntaxKind.SingleLineDocumentationCommentTrivia:
- case SyntaxKind.MultiLineDocumentationCommentTrivia:
- return true;
-
- default:
- return false;
- }
- }
+ protected override bool IsCommentTrivia(SyntaxTrivia trivia) => trivia.IsComment();
protected override bool IsDocumentationCommentTrivia(SyntaxTrivia trivia)
{
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentFixme.cs b/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentKeyword.cs
similarity index 53%
rename from sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentFixme.cs
rename to sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentKeyword.cs
index 44f1a3e3b03..de3c9953b0e 100644
--- a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentFixme.cs
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentKeyword.cs
@@ -1,43 +1,47 @@
-/*
- * SonarAnalyzer for .NET
- * Copyright (C) 2015-2019 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.Immutable;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Diagnostics;
-using SonarAnalyzer.Common;
-using SonarAnalyzer.Helpers;
-
-namespace SonarAnalyzer.Rules.CSharp
-{
- [DiagnosticAnalyzer(LanguageNames.CSharp)]
- [Rule(DiagnosticId)]
- public sealed class CommentFixme : CommentWordBase
- {
- protected override string Word => "FIXME";
-
- internal const string DiagnosticId = "S1134";
- private const string MessageFormat =
- "Take the required action to fix the issue indicated by this 'FIXME' comment.";
-
- private static readonly DiagnosticDescriptor rule =
- DiagnosticDescriptorBuilder.GetDescriptor(DiagnosticId, MessageFormat, RspecStrings.ResourceManager);
- public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(rule);
- }
-}
+/*
+ * SonarAnalyzer for .NET
+ * Copyright (C) 2015-2019 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 Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using SonarAnalyzer.Common;
+using SonarAnalyzer.Helpers;
+using SonarAnalyzer.Helpers.CSharp;
+
+namespace SonarAnalyzer.Rules.CSharp
+{
+ [DiagnosticAnalyzer(LanguageNames.CSharp)]
+ [Rule(FixMeDiagnosticId)]
+ [Rule(TodoDiagnosticId)]
+ public sealed class CommentKeyword : CommentKeywordBase
+ {
+ internal static readonly DiagnosticDescriptor TODO_Descriptor =
+ DiagnosticDescriptorBuilder.GetDescriptor(TodoDiagnosticId, TodoMessageFormat, RspecStrings.ResourceManager);
+ protected override DiagnosticDescriptor TodoDiagnostic { get; } = TODO_Descriptor;
+
+ internal static readonly DiagnosticDescriptor FIXME_Descriptor =
+ DiagnosticDescriptorBuilder.GetDescriptor(FixMeDiagnosticId, FixMeMessageFormat, RspecStrings.ResourceManager);
+ protected override DiagnosticDescriptor FixMeDiagnostic { get; } = FIXME_Descriptor;
+
+ protected override GeneratedCodeRecognizer GeneratedCodeRecognizer
+ => CSharpGeneratedCodeRecognizer.Instance;
+
+ protected override bool IsComment(SyntaxTrivia trivia) => trivia.IsComment();
+ }
+}
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentTodo.cs b/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentTodo.cs
deleted file mode 100644
index cc1e7a56073..00000000000
--- a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentTodo.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * SonarAnalyzer for .NET
- * Copyright (C) 2015-2019 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.Immutable;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.Diagnostics;
-using SonarAnalyzer.Common;
-using SonarAnalyzer.Helpers;
-
-namespace SonarAnalyzer.Rules.CSharp
-{
- [DiagnosticAnalyzer(LanguageNames.CSharp)]
- [Rule(DiagnosticId)]
- public sealed class CommentTodo : CommentWordBase
- {
- protected override string Word => "TODO";
-
- internal const string DiagnosticId = "S1135";
- private const string MessageFormat =
- "Complete the task associated to this 'TODO' comment.";
-
- internal static readonly DiagnosticDescriptor rule =
- DiagnosticDescriptorBuilder.GetDescriptor(DiagnosticId, MessageFormat, RspecStrings.ResourceManager);
- public override ImmutableArray SupportedDiagnostics { get; } = ImmutableArray.Create(rule);
- }
-}
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentWordBase.cs b/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentWordBase.cs
deleted file mode 100644
index 98ed3f53628..00000000000
--- a/sonaranalyzer-dotnet/src/SonarAnalyzer.CSharp/Rules/CommentWordBase.cs
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarAnalyzer for .NET
- * Copyright (C) 2015-2019 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.Generic;
-using System.Linq;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.Text;
-using SonarAnalyzer.Helpers;
-
-namespace SonarAnalyzer.Rules.CSharp
-{
- public abstract class CommentWordBase : SonarDiagnosticAnalyzer
- {
- protected abstract string Word { get; }
-
- protected sealed override void Initialize(SonarAnalysisContext context)
- {
- context.RegisterSyntaxTreeActionInNonGenerated(
- c =>
- {
- var comments = c.Tree.GetCompilationUnitRoot().DescendantTrivia()
- .Where(trivia => IsComment(trivia));
-
- foreach (var comment in comments)
- {
- var text = comment.ToString();
-
- foreach (var i in AllCaseInsensitiveIndexesOf(text, Word).Where(i => IsWordAt(text, i, Word.Length)))
- {
- var startLocation = comment.SpanStart + i;
- var location = Location.Create(
- c.Tree,
- TextSpan.FromBounds(startLocation, startLocation + Word.Length));
-
- c.ReportDiagnosticWhenActive(Diagnostic.Create(SupportedDiagnostics[0], location));
- }
- }
- });
- }
-
- private static bool IsComment(SyntaxTrivia trivia)
- {
- return trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) ||
- trivia.IsKind(SyntaxKind.MultiLineCommentTrivia) ||
- trivia.IsKind(SyntaxKind.SingleLineDocumentationCommentTrivia) ||
- trivia.IsKind(SyntaxKind.MultiLineDocumentationCommentTrivia);
- }
-
- private static IEnumerable AllCaseInsensitiveIndexesOf(string str, string value)
- {
- var index = 0;
- while ((index = str.IndexOf(value, index, str.Length - index, System.StringComparison.OrdinalIgnoreCase)) != -1)
- {
- yield return index;
- index += value.Length;
- }
- }
-
- private static bool IsWordAt(string str, int index, int count)
- {
- var leftBoundary = true;
- if (index > 0)
- {
- leftBoundary = !char.IsLetterOrDigit(str[index - 1]);
- }
-
- var rightBoundary = true;
- var rightOffset = index + count;
- if (rightOffset < str.Length)
- {
- rightBoundary = !char.IsLetterOrDigit(str[rightOffset]);
- }
-
- return leftBoundary && rightBoundary;
- }
- }
-}
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.Common/Rules/CommentKeywordBase.cs b/sonaranalyzer-dotnet/src/SonarAnalyzer.Common/Rules/CommentKeywordBase.cs
new file mode 100644
index 00000000000..319d71a5b74
--- /dev/null
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.Common/Rules/CommentKeywordBase.cs
@@ -0,0 +1,122 @@
+/*
+ * SonarAnalyzer for .NET
+ * Copyright (C) 2015-2019 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;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Text;
+using SonarAnalyzer.Helpers;
+
+namespace SonarAnalyzer.Rules
+{
+ public abstract class CommentKeywordBase : SonarDiagnosticAnalyzer
+ {
+ private const string TodoKeyword = "TODO";
+ protected const string TodoDiagnosticId = "S1135";
+ protected const string TodoMessageFormat = "Complete the task associated to this '" + TodoKeyword + "' comment.";
+
+ private const string FixMeKeyword = "FIXME";
+ protected const string FixMeDiagnosticId = "S1134";
+ protected const string FixMeMessageFormat = "Take the required action to fix the issue indicated by this '" + FixMeKeyword + "' comment.";
+
+ protected abstract DiagnosticDescriptor TodoDiagnostic { get; }
+ protected abstract DiagnosticDescriptor FixMeDiagnostic { get; }
+ protected abstract GeneratedCodeRecognizer GeneratedCodeRecognizer { get; }
+
+ public sealed override ImmutableArray SupportedDiagnostics { get; }
+
+ protected CommentKeywordBase()
+ {
+ SupportedDiagnostics = ImmutableArray.Create(TodoDiagnostic, FixMeDiagnostic);
+ }
+
+ protected sealed override void Initialize(SonarAnalysisContext context)
+ {
+ context.RegisterSyntaxTreeActionInNonGenerated(
+ GeneratedCodeRecognizer,
+ c =>
+ {
+ var comments = c.Tree.GetRoot().DescendantTrivia()
+ .Where(trivia => IsComment(trivia));
+
+ foreach (var comment in comments)
+ {
+ foreach (var location in GetKeywordLocations(c.Tree, comment, TodoKeyword))
+ {
+ c.ReportDiagnosticWhenActive(Diagnostic.Create(TodoDiagnostic, location));
+ }
+
+ foreach (var location in GetKeywordLocations(c.Tree, comment, FixMeKeyword))
+ {
+ c.ReportDiagnosticWhenActive(Diagnostic.Create(FixMeDiagnostic, location));
+ }
+ }
+ });
+ }
+
+ protected abstract bool IsComment(SyntaxTrivia trivia);
+
+ private static IEnumerable GetKeywordLocations(SyntaxTree tree, SyntaxTrivia comment, string word)
+ {
+ var text = comment.ToString();
+
+ return AllIndexesOf(text, word)
+ .Where(i => IsWordAt(text, i, word.Length))
+ .Select(
+ i =>
+ {
+ var startLocation = comment.SpanStart + i;
+ var location = Location.Create(tree, TextSpan.FromBounds(startLocation, startLocation + word.Length));
+
+ return location;
+ });
+ }
+
+ private static IEnumerable AllIndexesOf(string text, string value, StringComparison comparisonType = StringComparison.OrdinalIgnoreCase)
+ {
+ var index = 0;
+ while ((index = text.IndexOf(value, index, text.Length - index, comparisonType)) != -1)
+ {
+ yield return index;
+ index += value.Length;
+ }
+ }
+
+ private static bool IsWordAt(string text, int index, int count)
+ {
+ var leftBoundary = true;
+ if (index > 0)
+ {
+ leftBoundary = !char.IsLetterOrDigit(text[index - 1]);
+ }
+
+ var rightBoundary = true;
+ var rightOffset = index + count;
+ if (rightOffset < text.Length)
+ {
+ rightBoundary = !char.IsLetterOrDigit(text[rightOffset]);
+ }
+
+ return leftBoundary && rightBoundary;
+ }
+ }
+}
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1134.html b/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1134_cs.html
similarity index 99%
rename from sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1134.html
rename to sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1134_cs.html
index 8e877afd34e..f772e2285ea 100644
--- a/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1134.html
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1134_cs.html
@@ -12,4 +12,4 @@ See
-
+
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1134_vb.html b/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1134_vb.html
new file mode 100644
index 00000000000..f9913bf53d4
--- /dev/null
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1134_vb.html
@@ -0,0 +1,14 @@
+FIXME
tags are commonly used to mark places where a bug is suspected, but which the developer wants to deal with later.
+Sometimes the developer will not have the time or will simply forget to get back to that tag.
+This rule is meant to track those tags and to ensure that they do not go unnoticed.
+Noncompliant Code Example
+
+Function Divide(ByVal numerator As Integer, ByVal denominator As Integer) As Integer
+ Return numerator / denominator ' FIXME denominator value might be 0
+End Function
+
+See
+
+
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1135.html b/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1135_cs.html
similarity index 99%
rename from sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1135.html
rename to sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1135_cs.html
index 6223daf3606..a80dd0ea821 100644
--- a/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1135.html
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1135_cs.html
@@ -12,4 +12,4 @@ See
-
+
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1135_vb.html b/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1135_vb.html
new file mode 100644
index 00000000000..ceda945988a
--- /dev/null
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.Utilities/Rules.Description/S1135_vb.html
@@ -0,0 +1,14 @@
+TODO
tags are commonly used to mark places where some more code is required, but which the developer wants to implement later.
+Sometimes the developer will not have the time or will simply forget to get back to that tag.
+This rule is meant to track those tags and to ensure that they do not go unnoticed.
+Noncompliant Code Example
+
+Sub DoSomething()
+ ' TODO
+End Sub
+
+See
+
+
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Helpers/VisualBasicSyntaxHelper.cs b/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Helpers/VisualBasicSyntaxHelper.cs
index 3b94da60d44..f8e51855c66 100644
--- a/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Helpers/VisualBasicSyntaxHelper.cs
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Helpers/VisualBasicSyntaxHelper.cs
@@ -182,5 +182,19 @@ public static bool IsLeftSideOfAssignment(this ExpressionSyntax expression)
topParenthesizedExpression.Parent is AssignmentStatementSyntax assignment &&
assignment.Left == topParenthesizedExpression;
}
+
+ public static bool IsComment(this SyntaxTrivia trivia)
+ {
+ switch (trivia.Kind())
+ {
+ case SyntaxKind.CommentTrivia:
+ case SyntaxKind.DocumentationCommentExteriorTrivia:
+ case SyntaxKind.DocumentationCommentTrivia:
+ return true;
+
+ default:
+ return false;
+ }
+ }
}
}
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Metrics/VisualBasicMetrics.cs b/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Metrics/VisualBasicMetrics.cs
index a63c6756d85..a0d64ba251c 100644
--- a/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Metrics/VisualBasicMetrics.cs
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Metrics/VisualBasicMetrics.cs
@@ -26,6 +26,7 @@
using Microsoft.CodeAnalysis.VisualBasic;
using Microsoft.CodeAnalysis.VisualBasic.Syntax;
using SonarAnalyzer.Common;
+using SonarAnalyzer.Helpers.VisualBasic;
namespace SonarAnalyzer.Metrics.VisualBasic
{
@@ -105,19 +106,7 @@ protected override bool IsClass(SyntaxNode node)
}
}
- protected override bool IsCommentTrivia(SyntaxTrivia trivia)
- {
- switch (trivia.Kind())
- {
- case SyntaxKind.CommentTrivia:
- case SyntaxKind.DocumentationCommentExteriorTrivia:
- case SyntaxKind.DocumentationCommentTrivia:
- return true;
-
- default:
- return false;
- }
- }
+ protected override bool IsCommentTrivia(SyntaxTrivia trivia) => trivia.IsComment();
protected override bool IsDocumentationCommentTrivia(SyntaxTrivia trivia)
{
diff --git a/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Rules/CommentKeyword.cs b/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Rules/CommentKeyword.cs
new file mode 100644
index 00000000000..263000cff59
--- /dev/null
+++ b/sonaranalyzer-dotnet/src/SonarAnalyzer.VisualBasic/Rules/CommentKeyword.cs
@@ -0,0 +1,47 @@
+/*
+ * SonarAnalyzer for .NET
+ * Copyright (C) 2015-2019 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 Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using SonarAnalyzer.Common;
+using SonarAnalyzer.Helpers;
+using SonarAnalyzer.Helpers.VisualBasic;
+
+namespace SonarAnalyzer.Rules.VisualBasic
+{
+ [DiagnosticAnalyzer(LanguageNames.VisualBasic)]
+ [Rule(FixMeDiagnosticId)]
+ [Rule(TodoDiagnosticId)]
+ public sealed class CommentKeyword : CommentKeywordBase
+ {
+ internal static readonly DiagnosticDescriptor TODO_Descriptor =
+ DiagnosticDescriptorBuilder.GetDescriptor(TodoDiagnosticId, TodoMessageFormat, RspecStrings.ResourceManager);
+ protected override DiagnosticDescriptor TodoDiagnostic { get; } = TODO_Descriptor;
+
+ internal static readonly DiagnosticDescriptor FIXME_Descriptor =
+ DiagnosticDescriptorBuilder.GetDescriptor(FixMeDiagnosticId, FixMeMessageFormat, RspecStrings.ResourceManager);
+ protected override DiagnosticDescriptor FixMeDiagnostic { get; } = FIXME_Descriptor;
+
+ protected override GeneratedCodeRecognizer GeneratedCodeRecognizer
+ => VisualBasicGeneratedCodeRecognizer.Instance;
+
+ protected override bool IsComment(SyntaxTrivia trivia) => trivia.IsComment();
+ }
+}
diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/PackagingTests/VbRuleTypeMapping.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/PackagingTests/VbRuleTypeMapping.cs
index 6934891aaba..3ec16dcd53e 100644
--- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/PackagingTests/VbRuleTypeMapping.cs
+++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/PackagingTests/VbRuleTypeMapping.cs
@@ -1131,8 +1131,8 @@ internal static class VbRuleTypeMapping
//["1131"],
//["1132"],
//["1133"],
- //["1134"],
- //["1135"],
+ ["1134"] = "CODE_SMELL",
+ ["1135"] = "CODE_SMELL",
//["1136"],
//["1137"],
//["1138"],
diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/CommentFixmeTest.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/CommentFixmeTest.cs
deleted file mode 100644
index 9632af3caad..00000000000
--- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/CommentFixmeTest.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * SonarAnalyzer for .NET
- * Copyright (C) 2015-2019 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.
- */
-
-extern alias csharp;
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using csharp::SonarAnalyzer.Rules.CSharp;
-
-namespace SonarAnalyzer.UnitTest.Rules
-{
- [TestClass]
- public class CommentFixmeTest
- {
- [TestMethod]
- [TestCategory("Rule")]
- public void CommentFixme()
- {
- Verifier.VerifyAnalyzer(@"TestCases\CommentFixme.cs", new CommentFixme());
- }
- }
-}
diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/CommentTodoTest.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/CommentKeywordTest.cs
similarity index 55%
rename from sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/CommentTodoTest.cs
rename to sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/CommentKeywordTest.cs
index 59357216b71..160f8b68eca 100644
--- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/CommentTodoTest.cs
+++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/Rules/CommentKeywordTest.cs
@@ -19,19 +19,46 @@
*/
extern alias csharp;
+extern alias vbnet;
using Microsoft.VisualStudio.TestTools.UnitTesting;
-using csharp::SonarAnalyzer.Rules.CSharp;
+using CSharp = csharp::SonarAnalyzer.Rules.CSharp;
+using VisualBasic = vbnet::SonarAnalyzer.Rules.VisualBasic;
namespace SonarAnalyzer.UnitTest.Rules
{
[TestClass]
- public class CommentTodoTest
+ public class CommentKeywordTest
{
[TestMethod]
[TestCategory("Rule")]
- public void CommentTodo()
+ public void CommentTodo_CS()
{
- Verifier.VerifyAnalyzer(@"TestCases\CommentTodo.cs", new CommentTodo());
+ Verifier.VerifyAnalyzer(@"TestCases\CommentTodo.cs",
+ new CSharp.CommentKeyword());
+ }
+
+ [TestMethod]
+ [TestCategory("Rule")]
+ public void CommentFixme_CS()
+ {
+ Verifier.VerifyAnalyzer(@"TestCases\CommentFixme.cs",
+ new CSharp.CommentKeyword());
+ }
+
+ [TestMethod]
+ [TestCategory("Rule")]
+ public void CommentTodo_VB()
+ {
+ Verifier.VerifyAnalyzer(@"TestCases\CommentTodo.vb",
+ new VisualBasic.CommentKeyword());
+ }
+
+ [TestMethod]
+ [TestCategory("Rule")]
+ public void CommentFixme_VB()
+ {
+ Verifier.VerifyAnalyzer(@"TestCases\CommentFixme.vb",
+ new VisualBasic.CommentKeyword());
}
}
}
diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentFixme.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentFixme.cs
index 29a826f8f22..a11d9998aac 100644
--- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentFixme.cs
+++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentFixme.cs
@@ -31,4 +31,10 @@
*/
namespace Tests.Diagnostics
{
+ class FixMe
+ {
+ public FixMe()
+ {
+ }
+ }
}
diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentFixme.vb b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentFixme.vb
new file mode 100644
index 00000000000..f387a1978ec
--- /dev/null
+++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentFixme.vb
@@ -0,0 +1,22 @@
+Imports System
+Imports System.Collections.Generic
+Imports System.Linq
+Imports System.Text
+
+Namespace Tests.TestCases
+ '''
+ ''' FIXME: Do something ' Noncompliant
+ '''
+ Class Foo
+ Public Sub Test() ' FIXME
+' ^^^^^
+
+ End Sub
+ End Class
+
+ Class FixMe
+ Sub FixMe()
+
+ End Sub
+ End Class
+End Namespace 'fixme ' Noncompliant
diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentTodo.cs b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentTodo.cs
index bec6c5244b8..50b5899f8ee 100644
--- a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentTodo.cs
+++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentTodo.cs
@@ -31,4 +31,10 @@
*/
namespace Tests.Diagnostics
{
-}
\ No newline at end of file
+ class Todo
+ {
+ public Todo()
+ {
+ }
+ }
+}
diff --git a/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentTodo.vb b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentTodo.vb
new file mode 100644
index 00000000000..9cbecea6e91
--- /dev/null
+++ b/sonaranalyzer-dotnet/tests/SonarAnalyzer.UnitTest/TestCases/CommentTodo.vb
@@ -0,0 +1,21 @@
+Imports System
+Imports System.Collections.Generic
+Imports System.Linq
+Imports System.Text
+
+Namespace Tests.TestCases
+ '''
+ ''' TODO: Do something ' Noncompliant
+ '''
+ Class Foo
+ Public Sub Test() ' TODO ' Noncompliant
+' ^^^^
+
+ End Sub
+ End Class
+
+ Class Todo
+ Sub Todo() ' this is not a ctor
+ End Sub
+ End Class
+End Namespace 'todo ' Noncompliant