Sonar 的 TryStatementTree#resourceList return 什么时候不是 VariableTree 的树?

When does Sonar's TryStatementTree#resourceList return a Tree that isn't a VariableTree?

我在检查 SonarQube 插件的一些代码时遇到了 org.sonar.plugins.java.api.tree.TryStatementTree 界面。实施的规则之一遍及 try-with-resources 块中定义的变量。

查看 TryStatementTree#resourceList,我可以看到它 returns 一个 ListTree<Tree>。这可以通过多种方式迭代。在一种情况下,插件会检查声明的变量的名称。发生这种情况时,Tree 将转换为 VariableTree,因为 Tree 是一个更通用的接口,不提供通过 IdentifierTree.

访问变量名的权限

这是我正在查看的代码中的转换位置,一个扩展 BaseTreeVisitor 并实现 JavaFileScanner.

的 class
@Override
public void visitTryStatement(TryStatementTree tree) {
  // ...
  tree.resourceList().stream()
     .filter(resource -> resource instanceof VariableTree) // Is it possible for this condition to evaluate to false? 
     .map(VariableTree.class::cast)
     .map(resource -> resource.simpleName().name())
     .forEach(SomeClass::handleThisCase);
  // ...
}

查看 Java Language Standard,我想不出 try 语句会用不是标识符列表的内容代替资源声明的情况。

我认为这与表示不存在的资源定义或类似内容的需要有关,所以我向它添加了一些单元测试用例。

try { // No resource declaration here
  // ...
} catch (SomeException ex) {
  // ...
}

但在这种情况下根本没有调用该方法,我猜它是由 BaseTreeVisitor 处理的。

我一直在尝试想出一些例子来使转换变得不可能,但我想出的所有东西要么不编译,要么从不遵循这个执行路径。

我是否缺少编写 try 语句的方法,使更通用的 Tree 成为更好的选择?还是这种选择源于库中接口的结构方式?它似乎没有被任何超级接口强制执行(TryStatementTree -> StatementTree -> Tree)。 resourceListTryStatementTree 本身定义。

讽刺的是,我在发布问题 SonarQube documentation 分钟后偶然发现了答案。

事实证明,有一种方法完全符合我的预期,TryStatementTree#resource已弃用,然后被删除,取而代之的是 TryStatementTree#resourceList ,这正是我的代码使用的。

Deprecated method org.sonar.plugins.java.api.tree.TryStatementTree.resources() has been removed, in favor of org.sonar.plugins.java.api.tree.TryStatementTree.resourceList(), as Java 9 allows other trees than VariableTree to be placed as resources in try-with-resources statements.

这是一个例子:

SomeAutoCloseableClass myResource = obtainOneSomehow();
try (myResurce) { // No resource declaration here, just an identifier
  // ...
} catch (SomeException ex) {
  // ...
}

我的项目是在源级别设置为Java 8兼容性的情况下编译的,应该修改并添加一个新的单元测试用例以确保新的可能的方式来编写try-with-resources块被处理。