From 1966a7648c8ea5497d85c38aaa9d818dcb3bc558 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Fournier?= Date: Wed, 3 Apr 2019 14:48:48 +0200 Subject: [PATCH] Cleanup grammar --- pmd-java/etc/grammar/Java.jjt | 62 ++++++------------- .../pmd/lang/java/ast/ASTAmbiguousName.java | 14 +++-- .../pmd/lang/java/ast/LeftRecursiveNode.java | 1 - .../java/xpath/SemanticAmbiguityChecker.java | 7 +-- 4 files changed, 30 insertions(+), 54 deletions(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index be0ecb3a25..a922214614 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -479,6 +479,17 @@ public class JavaParser { } } + private void forceTypeContext() { + Node top = jjtree.peekNode(); + + if (top instanceof ASTAmbiguousName) { + // see doc on the method + Node replacement = ((ASTAmbiguousName) top).forceTypeContext(); + jjtree.popNode(); + jjtree.pushNode(replacement); + } + } + } PARSER_END(JavaParser) @@ -2040,13 +2051,6 @@ void ArrayTypeDim(): void ReferenceType() #void: {} { - - // TODO TypeVariable is ambiguous with ClassOrInterfaceType - // but I think it would be good to have a node for it nevertheless - // to help typeres, since TypeVariables have special types (intersection types) - // This could be handled in a rewrite phase, which is necessary for - // disambiguation. Since type parameters shadow anything, their disambiguation - // is stable regardless of classpath config. ( PrimitiveType() Dims() ) #ArrayType | ( ClassOrInterfaceType() [ LOOKAHEAD(2) Dims() ] ) #ArrayType(>1) } @@ -2059,20 +2063,12 @@ void ReferenceType() #void: void ClassOrInterfaceType() #void: {} { - - - /* FIXME We gobble up all identifiers until we find either type arguments or annotations, because it may be a FQCN, e.g. java.util.List is a single node. - - But java.util.Map.Entry should be two nodes ((java.util.Map).Entry) - I would have said this doesn't matter but the other fixme comment just - below shows we need a rewrite phase anyway */ - /* First, gobble up all identifiers until the first type arguments or annotation is found. The name is ambiguous between package or @@ -2095,10 +2091,9 @@ void ClassOrInterfaceType() #void: /* Now if there are other segments, either the previous segment specified type - arguments, or the next has an annotation. - - Each of the following segments is its own ClassOrInterfaceType which encloses the - previous one. The resulting structure appears left-recursive, but the parser just + arguments, or the next has an annotation. Either way we know that all the + following segments is a type name. Each segment is parsed as its own ClassOrInterfaceType + which encloses the previous one. The resulting structure appears left-recursive, but the parser just executes a loop. That scheme preserves the position of type arguments and annotations. See #1150. */ @@ -2111,14 +2106,7 @@ void ClassOrInterfaceType() #void: [ LOOKAHEAD( "<" ) TypeArguments() ] ) #ClassOrInterfaceType )* - { - Node top = jjtree.peekNode(); - if (top instanceof ASTAmbiguousName) { - Node replacement = ((ASTAmbiguousName) top).forceTypeContext(); - jjtree.popNode(); - jjtree.pushNode(replacement); - } - } + { forceTypeContext(); } } @@ -2231,19 +2219,7 @@ void Expression() #AssignmentExpression(>1): AssignmentOp AssignmentOperator() #void: {} { - ( "=" - | "*=" - | "/=" - | "%=" - | "+=" - | "-=" - | "<<=" - | ">>=" - | ">>>=" - | "&=" - | "^=" - | "|=" - ) + ( "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|=" ) {return AssignmentOp.fromImage(getToken(0).getImage());} } @@ -3232,8 +3208,10 @@ String VoidName() #void: } // This is used to get JJTree to generate a node. -// Since variable references are most of the time ambiguous, they're -// not created directly by the parser +// Variable references are always ambiguous +// when they're parsed, so they're not created +// normally by jjtree, but rather by the disambiguation +// hooks spread across the parser //noinspection JavaCCJccUnusedProduction void VariableReference(): {} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAmbiguousName.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAmbiguousName.java index 4d68b99c60..25e9361583 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAmbiguousName.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAmbiguousName.java @@ -39,8 +39,9 @@ import net.sourceforge.pmd.lang.java.xpath.SemanticAmbiguityChecker; * *
* A name is syntactically classified as an ExpressionName in these contexts: - * ... - * - As the qualifying expression in a qualified class instance creation expression (§15.9)* + * ... + * - As the qualifying expression in a qualified class instance creation + * expression (§15.9) *
* * We don't know at the moment the name is parsed that it will be @@ -49,13 +50,15 @@ import net.sourceforge.pmd.lang.java.xpath.SemanticAmbiguityChecker; * expression. In that case, the name can be reclassified, and e.g. if * it's a simple name be promoted to {@link ASTVariableReference}. This * type of immediate disambiguation is carried out by the {@link AbstractJavaNode#jjtClose()} - * method of those nodes that can be pushed. + * method of those nodes that do force a specific context on their + * left-hand side. See also {@link LeftRecursiveNode}. * *

Another mechanism is {@link #forceExprContext()} and {@link #forceTypeContext()}, * which are called by the parser to promote an ambiguous name to an - * expression or a type when it's sure they must be one. + * expression or a type when exiting from the {@link JavaParser#PrimaryExpression()} + * production or {@link JavaParser#ClassOrInterfaceType()}. * - *

These two mechanisms perform the first classification step, the + *

Those two mechanisms perform the first classification step, the * one that only depends on the syntactic context and not on semantic * information. A second pass on the AST after building the symbol tables * would allow us to remove all the remaining ambiguous names. @@ -100,6 +103,7 @@ public final class ASTAmbiguousName extends AbstractJavaTypeNode implements ASTR return getImage(); } + public List getSegments() { return Arrays.asList(getImage().split("\\.")); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/LeftRecursiveNode.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/LeftRecursiveNode.java index de52ce3942..8dd9750396 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/LeftRecursiveNode.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/LeftRecursiveNode.java @@ -11,7 +11,6 @@ package net.sourceforge.pmd.lang.java.ast; * *

This is only relevant to node construction and is package private. * - * * @author Clément Fournier */ interface LeftRecursiveNode { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/SemanticAmbiguityChecker.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/SemanticAmbiguityChecker.java index 97acd9669b..dd162ad6b0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/SemanticAmbiguityChecker.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/xpath/SemanticAmbiguityChecker.java @@ -30,12 +30,7 @@ public final class SemanticAmbiguityChecker { } - public static SemanticAmbiguityResult semanticCheck(Node node) { - if (!(node instanceof ASTAmbiguousName)) { - return null; - } - - ASTAmbiguousName name = (ASTAmbiguousName) node; + public static SemanticAmbiguityResult semanticCheck(ASTAmbiguousName name) { if (name.jjtGetParent() instanceof ASTExpression) {