如何在存根中注释隐式参数

How do I annotate an implicit parameter in a stub

我正在尝试使用 Nullness Checker 构建 JPanel 的子类。

class MyView<R extends @NonNull Object> extends JPanel {
  // ...
  // constructor calls this method:
  @RequiresNonNull({"labelPanel", "fieldPanel", "checkBoxPanel"})
  private void makeTopPanel(@UnderInitialization MyView<R> this) {
    JPanel topPanel = new JPanel(new BorderLayout());
    topPanel.add(labelPanel, BorderLayout.LINE_START);
    topPanel.add(fieldPanel, BorderLayout.CENTER);
    topPanel.add(checkBoxPanel, BorderLayout.LINE_END);

    // Error here: [method.invocation.invalid] call to add(java.awt.Component,java.lang.Object)
    // not allowed on the given receiver.
    add(topPanel, BorderLayout.PAGE_START);
    setBorder(new MatteBorder(1, 0, 0, 0, Color.black));
  }
}

错误消息是这样说的:

error: [method.invocation.invalid] call to add(java.awt.Component,java.lang.Object) not allowed 
on the given receiver.
  found   : @UnderInitialization @NonNull Container
  required: @Initialized @NonNull Container

问题似乎是添加方法假定 this 已初始化。但是在构造函数中调用 Container 的 add 方法是非常安全的。所以为了防止这个错误,我想创建一个带有注释隐式参数的存根文件:

package java.awt;
public class Container extends Component {
  public void add(@UnknownInitialization Container, @NonNull Component, @NonNull Object);
}

好像没有把这里的add()方法识别为java.awt.Container.add(Component, Object)方法

这是完整的存根文件:

import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import javax.swing.border.Border;
import java.awt.Component;
import java.awt.Container;

package javax.swing;

public class Timer {
  public Timer(int delay, @Nullable ActionListener listener);
}

public class JOptionPane {
  public static void showMessageDialog(@Nullable Component parentComponent,
          Object message, String title, int messageType)
          throws HeadlessException;
}

package java.awt;
public class Container extends Component {
  public void setBorder(@UnknownInitialization JComponent this, @Nullable Border border);
  public void add(@UnknownInitialization Container this, @NonNull Component, @NonNull Object);
}

我知道我可以用注释抑制警告,但存根文件感觉更简洁。有什么方法可以修复这个存根文件吗?

有两个问题。

第一个问题是您的存根文件格式不正确

  public void add(@UnknownInitialization Container this, @NonNull Component, @NonNull Object);

应该是

  public void add(@UnknownInitialization Container this, @NonNull Component comp, @NonNull Object constraints);

因为 Java 方法声明需要形式参数名称。

此外,它缺少 import 语句:

import org.checkerframework.checker.nullness.qual.NonNull;

第二个问题是您一定没有传递-Astubs=...命令行参数,否则您会收到关于存根文件格式错误的警告。 (你没有说你是如何调用 javac,这将有助于诊断你的问题。)

当我纠正这些问题时,检查器框架按预​​期工作。 运行命令

$CHECKERFRAMEWORK/checker/bin/javac -processor nullness -g MyView.java

发出警告,

$CHECKERFRAMEWORK/checker/bin/javac -processor nullness -g MyView.java -Astubs=mystub.astub

不发出警告。

更正后的文件(即它们是完整的并且更小)出现在下面。

MyView.java:

import java.awt.BorderLayout;
import javax.swing.JPanel;
import org.checkerframework.checker.initialization.qual.UnderInitialization;

class MyView extends JPanel {

  MyView() {
    makeTopPanel();
  }

  private void makeTopPanel(@UnderInitialization MyView this) {
    JPanel topPanel = new JPanel(new BorderLayout());
    add(topPanel, BorderLayout.PAGE_START);
  }
}

mystub.astub:

import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import javax.swing.border.Border;
import java.awt.Component;
import java.awt.Container;

package javax.swing;

public class Timer {
  public Timer(int delay, @Nullable ActionListener listener);
}

public class JOptionPane {
  public static void showMessageDialog(@Nullable Component parentComponent,
          Object message, String title, int messageType)
          throws HeadlessException;
}

package java.awt;
public class Container extends Component {
  public void setBorder(@UnknownInitialization JComponent this, @Nullable Border border);
  public void add(@UnknownInitialization Container this, @NonNull Component comp, @NonNull Object constraints);
}