【问题标题】:SonarLint - questions about some of the rules for VB.NETSonarLint - 关于 VB.NET 的一些规则的问题
【发布时间】:2017-02-25 00:38:57
【问题描述】:

我在 Java 中遇到的绝大多数 SonarLint 规则似乎都是合理且合理的。然而,自从我开始使用 SonarLint for VB.NET 以来,我遇到了一些规则,这些规则让我质疑它们的实用性,甚至怀疑它们是否正常工作。

我想知道这是否只是我以次优方式使用某些 VB.NET 构造的问题,或者该规则是否真的有缺陷。 (抱歉,如果这个问题有点长。我不知道是否应该为每个单独的规则创建一个单独的问题。)

我发现以下规则忽略了一些实际上会出现误报的情况:

  • S1871:同一个条件结构中的两个分支不应该有完全相同的实现
    我发现这个给我带来了很多误报,因为有时检查条件的顺序确实很重要。以下面的伪代码为例:

    If conditionA() Then
        doSomething()
    ElseIf conditionB() AndAlso conditionC() Then
        doSomethingElse()
    ElseIf conditionD() OrElse conditionE() Then
        doYetAnotherThing()
    '... feel free to have even more cases in between here
    Else Then
        doSomething() 'Non-compliant
    End If
    

    如果我想遵循这个 Sonar 规则并且仍然使代码的行为方式相同,我必须将每个 ElseIf 条件的否定版本添加到第一个 If 条件中。
    另一个示例是以下开关:

    Select Case i
        Case 0 To 40
            value = 0
        Case 41 To 60
            value = 1
        Case 61 To 80
            value = 3
        Case 81 To 100
            value = 5
        Case Else
            value = 0 'Non-compliant
    

    在 switch 中使用最后一个 case 应该没有什么问题。没错,我本可以事先将value 初始化为 0 并忽略最后一种情况,但随后我会进行一次不必要的赋值操作。 Java 规则集使我总是在每个开关中放置 default 大小写。

  • S1764:二元运算符的两边不应使用相同的表达式
    这条规则似乎没有考虑到某些函数在每次调用它们时可能返回不同的值,例如在集合中访问元素会将其从集合中移除:

    stack.Push(stack.Pop() / stack.Pop()) 'Non-compliant
    

    不过,我知道这是否过于极端,无法为其设置特殊例外。

以下规则我不太确定:

  • S3385:不应使用“退出”语句
    虽然我同意ReturnExit Sub 更具可读性,但使用单个Exit For 来打破ForFor Each 循环真的很糟糕吗? Java 的 SonarLint 规则允许在将其标记为问题之前在循环中使用单个 break;。 VB.NET 中的默认设置在这方面更加严格,这是有原因的吗?还是该规则是建立在您可以使用 LINQ 扩展方法和 lambda 解决几乎所有循环问题的假设之上的?
  • S2374: 有符号类型应该优先于无符号类型
    这条规则基本上规定根本不应该使用无符号类型,因为它们“具有与有符号运算符不同的算术运算符 - 很少有开发人员理解的运算符”。在我的代码中,我只将 UInteger 用于 ID 值(因为我不需要负值,而且 Long 在我的情况下会浪费内存)。它们存储在 List(Of UInteger) 中,并且仅与其他 UInteger 进行比较。这条规则是否与我的案例相关(比较是规则提到的这些“算术运算符”的一部分),究竟会有什么陷阱?如果不是,那么将该规则应用于涉及无符号类型的算术运算而不是它们的声明不是更好吗?
  • S2355: 应该使用数组字面量而不是数组创建表达式
    也许我不太了解 VB.NET,但是在以下情况下,我想创建一个只有在运行时才知道初始化长度的固定大小数组,我该如何满足这个规则?这是误报吗?

    Dim myObjects As Object() = New Object(someOtherList.Count - 3) {} 'Non-compliant
    

    当然,我可能只使用 List(Of Object)。但我还是很好奇。

【问题讨论】:

  • 每个帖子有多个问题不被接受;就像您或多或少地要求编码教程一样。对于第一个 sn-p,您需要做的就是摆脱 If conditionA() Then 以使机器人快乐。虽然该规则通常可能是一个好主意,但保留conditionA 可能是有价值的:a)您一眼就可以看到它的含义 b)它可能是不断变化的需求的占位符。与 case 语句相同。 Exit Sub/Return 和 Exit For 之间也有区别。如果机器人不知道,那就摆脱它。
  • If conditionA() 排除在外会改变结果。假设条件A()、条件B() 和条件C() 都评估为true。正如我所说,顺序很重要。如果您取出第一个案例,您实际上必须将 conditionA() 的否定版本添加到所有 ElseIf 构造以获得相同的结果。很抱歉有多个问题。这篇文章实际上更多的是针对 SonarLint 开发人员本身,因为他们的网站指向 Stackoverlow 的问题。因此,我只是试图将多个潜在问题合并到一篇文章中。

标签: vb.net sonarlint sonarlint-vs


【解决方案1】:

感谢您提出这些观点。请注意,并非所有规则每次都适用。在某些情况下,我们需要在误报/误报/真实情况之间取得平衡。例如,在运算符规则的两侧具有相同的表达式。具有相同的操作数是错误吗?不,这不对。如果是,那么编译器会报告它。是不是难闻的气味,通常是错误的吗?在很多情况下是的。例如,请参见 Roslyn。我们是否应该调整此规则以排除某些情况?是的,我们应该这样做,2 << 2 没有任何问题。因此,需要进行大量的平衡,我们努力满足于为用户带来最大价值的实现。

对于你提出的观点:

  • 同一条件结构中的两个分支不应具有完全相同的实现

此规则通常指出,两个代码块完全匹配是一个不好的信号。出于多种原因,应避免复制粘贴代码,例如,如果您需要在一个地方修复代码,那么您也需要在另一个地方修复它。没错,添加否定条件会很麻烦,但是如果您将每个条件提取到其自己的方法中(并调用其中的否定方法)并使用正确的名称,那么它可能会提高代码的可读性。

对于Select Case,同样,复制粘贴的代码总是一个不好的迹象。在这种情况下,您可以这样做:

Select Case i
  ...
  Case 0 To 40
  Case Else
    value = 0 ' Compliant
End Select

或者干脆去掉 0-40 的大小写。

  • 二元运算符的两边不应使用相同的表达式

我认为这是一个极端案例。请参阅答案的第一段。

  • 不应使用“退出”语句

几乎总是这样,通过选择另一种循环类型或更改停止条件,您可以在不使用任何“退出”语句的情况下摆脱困境。最好从循环中设置一个退出点。

  • 有符号类型应优先于无符号类型

这是来自 SonarQube VB.NET 的旧规则,我同意您的观点,即默认情况下不应在 SonarLint 中启用它。我在我们的 JIRA 中创建了以下票证:https://jira.sonarsource.com/browse/SLVS-1074

  • 应使用数组字面量而不是数组创建表达式

是的,这似乎是一个误报,当明确指定大小时,我们不应该报告数组创建。 https://jira.sonarsource.com/browse/SLVS-1075

【讨论】:

    猜你喜欢
    • 2017-05-24
    • 1970-01-01
    • 1970-01-01
    • 2018-05-24
    • 2013-07-07
    • 2013-05-10
    • 2012-03-18
    • 2023-03-09
    • 2021-07-01
    相关资源
    最近更新 更多