SonarLint - 关于VB.NET的一些规则的问题

时间:2016-10-15 18:08:25

标签: vb.net sonarlint sonarlint-vs

我在Java中遇到的绝大多数SonarLint规则似乎都是合情合理的。但是,自从我开始使用SonarLint用于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
    

    如果我想遵循这个声纳规则并仍然使代码行为相同,我必须将每个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
    

    在交换机中使用最后一个案例不应该有任何问题。是的,我可以预先将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扩展方法和lambdas解决几乎所有循环问题的假设之上?
  • 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)。但无论如何我很好奇。

1 个答案:

答案 0 :(得分:1)

感谢您提出这些观点。请注意,并非每次都适用所有规则。有些情况下,我们需要在误报/漏报/真实案例之间取得平衡。例如,在运算符规则的两侧使用相同的表达式。拥有相同的操作数是一个错误吗?不,不是。如果是,则编译器将报告它。这是难闻的气味,通常是一个错误吗?在许多情况下是的。例如,在Roslyn中查看此内容。我们应该调整此规则以排除某些情况吗?是的,我们应该2 << 2没有错。因此,需要进行大量的平衡,我们会尝试为用户带来最大价值的实施。

对于你提出的观点:

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

这条规则通常规定两个代码块完全匹配是一个坏兆头。应该避免使用复制粘贴代码,原因有多种,例如,如果您需要在一个地方修复代码,那么您也需要在另一个地方修复代码。你是对的,添加否定条件会很麻烦,但是如果你用适当的名称将每个条件提取到它自己的方法中(并在其中调用否定的方法),那么它可能会提高代码的可读性。

对于Select Case,再次复制粘贴代码始终是一个不好的迹象。在这种情况下,你可以这样做:

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

或者只是删除0-40个案例。

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

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

  • &#34;退出&#34;不应使用语句

几乎总是如此,通过选择其他类型的循环或更改停止条件,您可以在不使用任何&#34;退出&#34;声明。从循环中获得单个退出点是一种很好的做法。

  • 签名类型应优先于未签名类型

这是SonarQube VB.NET的遗留规则,我同意你的看法,默认情况下不应该在SonarLint中启用它。我在JIRA中创建了以下票证:https://jira.sonarsource.com/browse/SLVS-1074

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

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