验证方法体中是否使用了方法参数
Verify whether a method parameter is used in the method body
我的界面如下所示
interface Evaluator {
boolean requiresP2();
EvalResult evaluate(Param1 p1, Param2 p2, Param3 p3);
// some more methods
}
这个接口是由几个类实现的。 evaluate 方法的参数 p2
被一些人使用,而另一些人没有使用。方法 requiresP2
基本上 return 是一个布尔值,表示评估方法是否使用 p2
。
现在,脱离上下文,这个问题可能显得有点奇怪,但请相信我,这在我们的用例中是有意义的。另外,重构所有代码以消除对 requiresP2
方法的需要将需要大量时间,因此如果我们讨论除了代码库的自上而下重构之外的解决方案,我将不胜感激。
问题是方法requiresP2
的return值是基于evaluate
方法的实现方式。所以大家在改evaluate
方法的时候一定要保证更新requiresP2
方法。
我正在寻找方法,以便 compiler/unit-tests/linters 可以强制执行此操作,而不是将其留给开发人员记忆。
编辑:我仍在探索模拟框架对这个问题的适用性。
我想我可以在单元测试中反思,在单元测试中检查 evaluate
的主体,检查它是否引用 p2
,然后确保它与值匹配return由 requiresP2
方法编辑,但似乎无法使用反射检查方法主体。
我正在寻找有关如何执行此操作的建议。欢迎任何意见。
还有一个您没有提到的选项:静态代码分析工具。
您可以使用 SonarQube + SonarLint 组合来获得您想要的强制执行:
使用 SonarQube 服务器创建新的静态代码分析规则,该规则将基于您使用的界面和您的独特用例。
然后在您的 IDE/IDEs 上安装 SonarLint(支持 Eclipse 和 IntelliJ),并将其连接到 SonarQube 服务器。
这样,静态代码分析扫描将检测到您的界面使用不当,并在 IDE 中的相关代码行(这实际上是对您的代码进行 linting)中的视觉标记进行指示。
您可以使用ASM检查参数是否被使用
使用例如将其添加到您的项目中Apache Ivy,您可以将其添加到 ivy.xml
:
<dependency org="org.ow2.asm" name="asm" rev="6.1.1" />
或者为 Maven 做等价的事情,Gradle,等等。然后你可以通过以下方式检查参数:
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
// . . .
public static boolean usesP2(Evaluator evaluator) {
AtomicBoolean usesP2 = new AtomicBoolean(false);
String internalName = evaluator.getClass().getName().replace('.', '/');
String classFileResource = "/" + internalName + ".class";
ClassVisitor visitor = new ClassVisitor(Opcodes.ASM6) {
@Override
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
if ("evaluate".equals(name)) {
return new MethodVisitor(Opcodes.ASM6) {
@Override
public void visitVarInsn(final int insn, final int slot) {
if (slot == 2) usesP2.set(true);
}
};
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
};
try (InputStream is = Evaluator.class.getResourceAsStream(classFileResource)) {
ClassReader reader = new ClassReader(is);
reader.accept(visitor, 0);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return usesP2.get();
}
public static void assertCorrectlyDocumentsP2(Evaluator evaluator) {
boolean usesP2 = usesP2(evaluator);
if (usesP2 && !evaluator.requiresP2()) {
throw new AssertionError(evaluator.getClass().getName() +
" uses P2 without documenting it");
}
if (!usesP2 && evaluator.requiresP2()) {
throw new AssertionError(evaluator.getClass().getName() +
" says it uses P2 but does not");
}
}
单元测试:
@Test
public void testFalsePositive() {
assertCorrectlyDocumentsP2(new FalsePositive());
}
@Test
public static void testFalseNegative() {
assertCorrectlyDocumentsP2(new FalseNegative());
}
(这假设有两个错误的 Evaluator
s,FalsePositive
和 FalseNegative
,其中一个文档使用 P2 但没有使用,另一个文档没有' t 记录它使用 P2,即使它分别使用。)
注意:在usesP2
中,我们检查堆栈帧的槽2中的变量指令(访问局部变量的指令)。槽位从0开始编号,第一个是this
。 P2 位于插槽 2 中只是因为 Evaluator::evaluate
是一个 实例方法 。如果它是一个静态方法,我们将不得不检查是否使用了slot 1以检测是否使用了参数P2。 读者注意。
我的界面如下所示
interface Evaluator {
boolean requiresP2();
EvalResult evaluate(Param1 p1, Param2 p2, Param3 p3);
// some more methods
}
这个接口是由几个类实现的。 evaluate 方法的参数 p2
被一些人使用,而另一些人没有使用。方法 requiresP2
基本上 return 是一个布尔值,表示评估方法是否使用 p2
。
现在,脱离上下文,这个问题可能显得有点奇怪,但请相信我,这在我们的用例中是有意义的。另外,重构所有代码以消除对 requiresP2
方法的需要将需要大量时间,因此如果我们讨论除了代码库的自上而下重构之外的解决方案,我将不胜感激。
问题是方法requiresP2
的return值是基于evaluate
方法的实现方式。所以大家在改evaluate
方法的时候一定要保证更新requiresP2
方法。
我正在寻找方法,以便 compiler/unit-tests/linters 可以强制执行此操作,而不是将其留给开发人员记忆。
编辑:我仍在探索模拟框架对这个问题的适用性。
我想我可以在单元测试中反思,在单元测试中检查 evaluate
的主体,检查它是否引用 p2
,然后确保它与值匹配return由 requiresP2
方法编辑,但似乎无法使用反射检查方法主体。
我正在寻找有关如何执行此操作的建议。欢迎任何意见。
还有一个您没有提到的选项:静态代码分析工具。
您可以使用 SonarQube + SonarLint 组合来获得您想要的强制执行:
使用 SonarQube 服务器创建新的静态代码分析规则,该规则将基于您使用的界面和您的独特用例。
然后在您的 IDE/IDEs 上安装 SonarLint(支持 Eclipse 和 IntelliJ),并将其连接到 SonarQube 服务器。
这样,静态代码分析扫描将检测到您的界面使用不当,并在 IDE 中的相关代码行(这实际上是对您的代码进行 linting)中的视觉标记进行指示。
您可以使用ASM检查参数是否被使用
使用例如将其添加到您的项目中Apache Ivy,您可以将其添加到 ivy.xml
:
<dependency org="org.ow2.asm" name="asm" rev="6.1.1" />
或者为 Maven 做等价的事情,Gradle,等等。然后你可以通过以下方式检查参数:
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.concurrent.atomic.AtomicBoolean;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
// . . .
public static boolean usesP2(Evaluator evaluator) {
AtomicBoolean usesP2 = new AtomicBoolean(false);
String internalName = evaluator.getClass().getName().replace('.', '/');
String classFileResource = "/" + internalName + ".class";
ClassVisitor visitor = new ClassVisitor(Opcodes.ASM6) {
@Override
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
if ("evaluate".equals(name)) {
return new MethodVisitor(Opcodes.ASM6) {
@Override
public void visitVarInsn(final int insn, final int slot) {
if (slot == 2) usesP2.set(true);
}
};
}
return super.visitMethod(access, name, desc, signature, exceptions);
}
};
try (InputStream is = Evaluator.class.getResourceAsStream(classFileResource)) {
ClassReader reader = new ClassReader(is);
reader.accept(visitor, 0);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return usesP2.get();
}
public static void assertCorrectlyDocumentsP2(Evaluator evaluator) {
boolean usesP2 = usesP2(evaluator);
if (usesP2 && !evaluator.requiresP2()) {
throw new AssertionError(evaluator.getClass().getName() +
" uses P2 without documenting it");
}
if (!usesP2 && evaluator.requiresP2()) {
throw new AssertionError(evaluator.getClass().getName() +
" says it uses P2 but does not");
}
}
单元测试:
@Test
public void testFalsePositive() {
assertCorrectlyDocumentsP2(new FalsePositive());
}
@Test
public static void testFalseNegative() {
assertCorrectlyDocumentsP2(new FalseNegative());
}
(这假设有两个错误的 Evaluator
s,FalsePositive
和 FalseNegative
,其中一个文档使用 P2 但没有使用,另一个文档没有' t 记录它使用 P2,即使它分别使用。)
注意:在usesP2
中,我们检查堆栈帧的槽2中的变量指令(访问局部变量的指令)。槽位从0开始编号,第一个是this
。 P2 位于插槽 2 中只是因为 Evaluator::evaluate
是一个 实例方法 。如果它是一个静态方法,我们将不得不检查是否使用了slot 1以检测是否使用了参数P2。 读者注意。