readability-suspicious-call-argument

查找函数调用中参数传递顺序与函数参数名不一致的情况,该判断依据是参数名与函数参数名之间的差异。

给定一个函数调用 f(foo, bar); 和一个函数签名 void f(T tvar, U uvar),如果 foo(参数名)与 uvar(另一个参数)的相似度比与 tvar(当前传递给它的参数)的相似度更高,并且 bartvar 的相似度比与 uvar 的相似度更高,则认为参数 foobar 被交换了。

警告可能表明参数被交换了,也可能表明名称之间的交叉相似性会阻碍代码理解。

启发式方法

检查中实现了以下启发式方法。如果任何一个启用的启发式方法认为参数传递顺序不正确,就会发出警告。

启发式方法本身是通过考虑字符串对来实现的,并且是对称的,所以在下面的内容中,没有区分哪个字符串是参数名,哪个字符串是参数名。

相等性

最简单的启发式方法,它比较两个字符串是否不区分大小写地相等。

缩写

可以指定常见的缩写,如果缩写和缩写形式在一起,就会认为这两个字符串相似。例如,如果将 src 注册为 source 的缩写,那么以下代码示例将收到警告。

void foo(int source, int x);

foo(b, src);

要识别的缩写可以通过 Abbreviations 检查选项进行配置。此启发式方法不区分大小写。

前缀

前缀 启发式方法报告如果其中一个字符串是另一个字符串的足够长的前缀,例如 targettargetPtr。相似度百分比是前缀长度与较长字符串长度之比,在上面的例子中,它将是 6 / 9 = 66.66…%。

此启发式方法可以使用 bounds 进行配置。默认边界是:低于 25% 不相似,高于 30% 相似。此启发式方法不区分大小写。

后缀

Prefix 启发式方法类似。在比较 oldValuevalue 的情况下,相似度百分比是 8 / 5 = 62.5%。

此启发式方法可以使用 bounds 进行配置。默认边界是:低于 25% 不相似,高于 30% 相似。此启发式方法不区分大小写。

子字符串

子字符串启发式方法结合了前缀和后缀启发式方法,并尝试在提供的两个字符串中找到最长公共子字符串。相似度百分比是找到的最长公共子字符串长度与两个输入字符串中较长一个的长度之比。例如,给定 valrvalue,相似度是 3 / 6 = 50%。如果两个字符串没有共同字符,则为 0%。

此启发式方法可以使用 bounds 进行配置。默认边界是:低于 40% 不相似,高于 50% 相似。此启发式方法不区分大小写。

莱文斯坦距离(作为 Levenshtein

莱文斯坦距离 描述了将一个字符串转换为另一个字符串需要进行多少个单字符更改(添加、更改或删除)。

莱文斯坦距离通过将其除以较长字符串的长度,并取其关于 100% 的补码来转换为相似度百分比。例如,给定 somethinganything,距离为 4 个编辑,相似度百分比为 100% - 4 / 9 = 55.55…%。

此启发式方法可以使用 bounds 进行配置。默认边界是:低于 50% 不相似,高于 66% 相似。此启发式方法区分大小写。

Jaro-Winkler 距离(作为 JaroWinkler

Jaro-Winkler 距离 是一个类似于莱文斯坦距离的编辑距离。它是根据足够接近位置的公共字符数量以及要更改的字符数量来计算的。Jaro 的原始定义被 Winkler 扩展为更多地权衡前缀相似性。相似度百分比表示为公共和非公共字符的平均值与两个字符串长度的比值。

此启发式方法可以使用 bounds 进行配置。默认边界是:低于 75% 不相似,高于 85% 相似。此启发式方法不区分大小写。

Sørensen-Dice 系数(作为 Dice

Sørensen-Dice 系数 最初被定义为测量两个集合的相似度。形式上,该系数是通过将 2 * #(intersection) 除以 #(set1) + #(set2) 来计算的,其中 #() 是集合的基数函数。该度量是通过创建两个字符串的双字母组(长度为 2 的子字符串序列)并将两个字符串的双字母组集合用作两个集合来应用于字符串的。

此启发式方法可以使用 bounds 进行配置。默认边界是:低于 60% 不相似,高于 70% 相似。此启发式方法不区分大小写。

选项

MinimumIdentifierNameLength

设置参数名和参数名所需的最小长度。长度小于此值的名称将被忽略。默认为 3

Abbreviations

对于Abbreviation 启发式方法 (请参见此处),此选项配置 “abbreviation=abbreviated_value” 格式的缩写。该选项是一个字符串,每个值用 “;” 连接。

默认情况下,将设置以下缩写

  • addr=address

  • arr=array

  • attr=attribute

  • buf=buffer

  • cl=client

  • cnt=count

  • col=column

  • cpy=copy

  • dest=destination

  • dist=distance

  • dst=distance

  • elem=element

  • hght=height

  • i=index

  • idx=index

  • len=length

  • ln=line

  • lst=list

  • nr=number

  • num=number

  • pos=position

  • ptr=pointer

  • ref=reference

  • src=source

  • srv=server

  • stmt=statement

  • str=string

  • val=value

  • var=variable

  • vec=vector

  • wdth=width

每个已实现的启发式方法的配置选项(见上文)都是动态生成的。在下面的内容中,<HeuristicName> 代表已实现的启发式方法中的一个键。

<HeuristicName>

TrueFalse,表示某个特定启发式方法是否启用,例如 EqualityLevenshtein

对于每个启发式方法,默认值为 True

<HeuristicName>DissimilarBelow, <HeuristicName>SimilarAbove

一个介于 0100 之间的值,表示一个百分比。边界设置启发式方法必须推断出的相似度百分比,以便检查认为两个标识符相似或不相似。

给定传递给 param1param2 的参数 arg1arg2,边界检查按以下方式执行:如果当前传递的参数顺序 (arg1param1) 的相似度低于 DissimilarBelow 阈值,并且建议交换顺序 (arg1param2) 的相似度高于 SimilarAbove 阈值,则会报告交换。

有关每个启发式方法的默认值,请参见上文

名称合成

比较参数名和参数名时,使用以下逻辑来收集用于比较的名称

参数名是源代码中写入的标识符。

参数名是

  • 如果传递的是变量,则为变量的名称。

  • 如果使用后续函数调用的返回值作为参数,则为被调用函数的名称。

  • 否则,为空字符串。

启发式方法会忽略空参数名或参数名。