在Java8 编译器中,JCVariableDecl 中的nameexpr 字段是什么

In Java 8 compiler, what is nameexpr field in JCVariableDecl for

在java编译器JCTree.java中,JCVariableDecl定义如下:

    public static class JCVariableDecl extends JCStatement implements VariableTree {
        /** variable modifiers */
        public JCModifiers mods;
        /** variable name */
        public Name name;
        /** variable name expression */
        public JCExpression nameexpr;
        /** type of the variable */
        public JCExpression vartype;
        /** variable's initial value */
        public JCExpression init;
        /** symbol */
        public VarSymbol sym;
...
}

但是,我不确定 nameexpr 在这里有什么用。什么情况下nameexpr字段不为空?我已经阅读了 Java 8 和 JavacParser.java

的 BNF
    JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, boolean lambdaParameter) {
        int pos = token.pos;
        Name name;
        if (lambdaParameter && token.kind == UNDERSCORE) {
            log.error(pos, "underscore.as.identifier.in.lambda");
            name = token.name();
            nextToken();
        } else {
            if (allowThisIdent) {
                JCExpression pn = qualident(false);
                if (pn.hasTag(Tag.IDENT) && ((JCIdent)pn).name != names._this) {
                    name = ((JCIdent)pn).name;
                } else {
                    if ((mods.flags & Flags.VARARGS) != 0) {
                        log.error(token.pos, "varargs.and.receiver");
                    }
                    if (token.kind == LBRACKET) {
                        log.error(token.pos, "array.and.receiver");
                    }
                    return toP(F.at(pos).ReceiverVarDef(mods, pn, type));
                }
            } else {
                name = ident();
            }
        }
        if ((mods.flags & Flags.VARARGS) != 0 &&
                token.kind == LBRACKET) {
            log.error(token.pos, "varargs.and.old.array.syntax");
        }
        type = bracketsOpt(type);
        return toP(F.at(pos).VarDef(mods, name, type, null));
    }

看来我们需要构造一个案例来制作

pn.hasTag(Tag.IDENT) && ((JCIdent)pn).name != names._this

为假。

代码正在检查接收器参数,如下所示:

public class SomeClass {
    
    public void foo(SomeClass this) {
        //          ^^^^^^^^^^^^^^
    }
}

spec的语法产生式规则中,列为:

FormalParameterList:
ReceiverParameter 
FormalParameters , LastFormalParameter 
LastFormalParameter

FormalParameters:
FormalParameter {, FormalParameter} 
ReceiverParameter {, FormalParameter}

ReceiverParameter:
{Annotation} UnannType [Identifier .] this

这是一个名称为“this”的参数,如果在内部 class 构造函数中,则为 NameOfOuterClass.thisthis 不是标识符,所以这就是它检查 pn.hasTag(Tag.IDENT).

的原因

如果您之前没有听说过接收者参数,它基本上是一个“一种可选的句法设备,其存在的唯一目的是允许在源代码中表示所表示对象的类型,以便可以对该类型进行注释,”并且“它永远不会绑定到作为方法调用表达式或合格的 class 实例创建表达式中的参数传递的任何值,并且它在 运行 时间没有任何影响”,正如语言规范所说的那样。

由于它与变量声明符的结构几乎相同,我猜他们决定也使用 JCVariableDecl 来表示它。