如何在检查器框架中使用行号等显示完整的编译错误消息信息



我刚开始使用Checker框架,遇到了一个问题,这个问题在这个框架作者的一个示例项目上完全可以重现。此项目可在此处获得: https://github.com/typetools/checker-framework/tree/master/docs/examples/GradleExamples

当我从 root 运行此命令时:

>gradle compileJava

我收到此编译输出:

public static /*@Nullable*/ Object nullable = null;
^
required: @Initialized @NonNull Object
list.add(null); // error on this line
^
required: @Initialized @NonNull String
2 errors
:compileJava FAILED

如您所见,没有任何关于错误发生位置的信息,例如类名,代码中的行号等。 我在他们的官方手册中没有找到任何关于可以适当更改输出格式的编译器参数的信息。我希望错误消息如下所示:

~GradleExample.java:33 error: ';' expected

更新:

我在 3 台机器上实现了此行为:

    • 操作系统: Microsoft 视窗 7 x64 旗舰版 SP1 [版本 6.1.7601];
    • 爪哇: 1.8.0_73;
    • 格拉德尔:2.14。
    • 操作系统: Microsoft 视窗 10 x64 专业版 [版本 10.0.14393];
    • 爪哇: 1.8.0_121;
    • 格拉德尔:3.4.1。
    • 操作系统: Microsoft 视窗 7 x64 旗舰版 SP1 [版本 6.1.7601];
    • 爪哇: 1.8.0_121;
    • 格拉德尔:3.4.1。

只有在使用 Gradle 运行时才会遇到缺少行号和类名的情况。我还尝试从命令行使用 Maven 和 Javac 运行检查器,它运行得很好。
要使用 Gradle 配置检查器框架,我遵循了手册中的步骤。有 3 个步骤:

  1. 下载框架;
  2. 解压缩它以创建一个检查器框架目录;
  3. 配置 Gradle 以在类路径中包含检查器框架。

据我了解,Gradle 在通过依赖关系管理提供所需的检查器框架的 jar 时会自动执行步骤 1 和 2。尽管如此,我还是尝试了两种选择:

  1. 依赖管理:
    我只是简单地下载了示例项目并从root执行了"gradle compileJava" 的 GradleJava7Example 项目。
  2. 在 gradle 构建文件中手动写入路径:
allprojects {
tasks.withType(JavaCompile).all { JavaCompile compile ->
compile.options.compilerArgs = [
'-processor', 'org.checkerframework.checker.nullness.NullnessChecker',
'-processorpath', "C:\checker-framework-2.1.10\checker\dist\checker.jar",
"-Xbootclasspath/p:C:\checker-framework-2.1.10\checker\dist\jdk8.jar",
'-classpath', 'C:\checker-framework-2.1.10\checker\dist\checker.jar;C:\checker-framework-2.1.10\checker\dist\javac.jar'
]
}
}

我找到了解决方法。我稍后会解释它,但现在如果有人有同样的问题,请将此行添加到您的 JavaCompile 任务配置中:

allprojects {
tasks.withType(JavaCompile).all { JavaCompile compile ->
System.setProperty("line.separator", "n")  // <<<<<< add this line
compile.options.compilerArgs = [
'-processor', 'org.checkerframework.checker.nullness.NullnessChecker',
'-processorpath', "${configurations.checkerFramework.asPath}",
"-Xbootclasspath/p:${configurations.checkerFrameworkAnnotatedJDK.asPath}"
]
}
}

首先,我必须说问题根本不在检查器框架中。我设法在没有检查器框架的情况下重现了与相关内容相同的行为。我创建了一个小的自定义注释处理器。这是代码:

@SupportedSourceVersion(value = SourceVersion.RELEASE_8)
@SupportedAnnotationTypes(value = {"*"})
public class MyProcessor extends AbstractProcessor{
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
String sepr = System.getProperty("line.separator");
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "[error code] " + sepr + " catched!!!");
return true;
}
}

如您所见,它所做的只是从一开始就立即打印消息。请注意,我使用了类提供的行分隔符java.lang.System来拆分消息。当我注册这个处理器并尝试从gradle项目运行"gradle compileJava"时,它产生了以下输出:

:compileJava
catched!!!
1 error
:compileJava FAILED

Windows 操作系统的属性 "line.separator" 返回 CR+LF: "\r"。我不知道为什么Messager.printMessage(Diagnostic.Kind kind, CharSequence msg)会有这种行为,因为当我输入System.err.print("[error code] " + sepr + " catched!!!")时,一切正常(另请注意,只有当我使用 Gradle 时才会出现此问题,如果我使用所有参数手动运行 javac 或使用 Maven 一切都很好)。
我发现如果我用简单的""符号编译器替换系统分隔符提供的错误消息,则会正确显示。 现在,我选择此解决方案作为解决方法。

相关内容

最新更新