0

我刚开始使用 Checker Framework,并且遇到了一个问题,该问题完全可以在该框架作者的示例项目之一上重现。该项目可在此处获得: 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 Windows 7 x64 Ultimate SP1 [版本 6.1.7601];
    • 爪哇:1.8.0_73;
    • 梯度:2.14。
    • 操作系统:Microsoft Windows 10 x64 Pro [版本 10.0.14393];
    • 爪哇:1.8.0_121;
    • 摇篮:3.4.1。
    • 操作系统:Microsoft Windows 7 x64 Ultimate SP1 [版本 6.1.7601];
    • 爪哇:1.8.0_121;
    • 摇篮:3.4.1。

只有在使用 Gradle 运行时才会出现行号和类名的缺失。我还尝试使用 Maven 和 Javac 从命令行运行检查器,它运行良好。
要使用 Gradle 配置 Checker Framework,我按照手册中的步骤操作。有3个步骤:

  1. 下载框架;
  2. 解压后创建一个 checker-framework 目录;
  3. 将 Gradle 配置为在类路径中包含 Checker Framework。

据我了解,Gradle 在通过依赖管理提供所需的 Checker Framework 的 jar 时会自动执行第 1 步和第 2 步。尽管如此,我尝试了两种选择:

  1. 依赖管理:
    我只是下载了示例项目并从 GradleJava7Example 项目的根目录执行“gradle compileJava”。
  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'
            ]
        }
    }
4

1 回答 1

0

我找到了解决方法。我稍后会解释,但现在如果有人遇到同样的问题,请将此行添加到 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}"
        ]
    }
}

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

@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\n”。我不知道为什么Messager.printMessage(Diagnostic.Kind kind, CharSequence msg)会有这种行为,因为当我键入时System.err.print("[error code] " + sepr + " catched!!!"),一切正常(另请注意,这个问题仅在我使用 Gradle 时发生,如果我使用所有参数手动运行 javac 或使用 Maven 一切都很好)。
我发现如果我用简单的“\n”符号替换系统分隔符提供的编译器错误消息,则会正确显示。现在我选择这个解决方案作为解决方法。

于 2017-04-11T12:40:20.097 回答