Skip to content
Advertisement

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

In java compiler JCTree.java the JCVariableDecl is defined as the following:

    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;
...
}

However, I am not sure how nameexpr can be useful here. In what situation nameexpr field is not null? I have read the BNF of Java 8 and JavacParser.java

    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));
    }

it seems that we need to construct a case to make

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

to be false.

Advertisement

Answer

The code is checking for a receiver parameter, which looks like this:

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

In the grammar production rules of the spec, it is listed as:

FormalParameterList:
ReceiverParameter 
FormalParameters , LastFormalParameter 
LastFormalParameter

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

ReceiverParameter:
{Annotation} UnannType [Identifier .] this

It’s a parameter that has the name of “this”, or NameOfOuterClass.this if in an inner class constructor. this is not an identifier, so this is why it is checking for pn.hasTag(Tag.IDENT).

If you have not heard of receiver parameters before, it’s basically a “an optional syntactic device that exists solely to allow the type of the represented object to be denoted in source code, so that the type may be annotated,” and “it is never bound to any value passed as an argument in a method invocation expression or qualified class instance creation expression, and it has no effect whatsoever at run time” as the language spec puts it.

Since it has almost the same structure as a variable declarator, I guess they decided to also use JCVariableDecl to represent it.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement