From 2579439ee64c8964feacbc462d7306d280c84c8e Mon Sep 17 00:00:00 2001 From: Andrea Guarino Date: Wed, 11 Sep 2019 11:54:34 +0200 Subject: [PATCH 1/4] SONARPY-407 Fix firstToken and lastToken for nested PyQualifiedExpression --- .../sonar/python/tree/PyQualifiedExpressionTreeImpl.java | 8 -------- .../main/java/org/sonar/python/tree/PythonTreeMaker.java | 5 ++--- .../java/org/sonar/python/tree/PythonTreeMakerTest.java | 4 ++++ 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/python-squid/src/main/java/org/sonar/python/tree/PyQualifiedExpressionTreeImpl.java b/python-squid/src/main/java/org/sonar/python/tree/PyQualifiedExpressionTreeImpl.java index 8e2f602fda..b2400943ce 100644 --- a/python-squid/src/main/java/org/sonar/python/tree/PyQualifiedExpressionTreeImpl.java +++ b/python-squid/src/main/java/org/sonar/python/tree/PyQualifiedExpressionTreeImpl.java @@ -19,7 +19,6 @@ */ package org.sonar.python.tree; -import com.sonar.sslr.api.AstNode; import com.sonar.sslr.api.Token; import java.util.Arrays; import java.util.List; @@ -34,13 +33,6 @@ public class PyQualifiedExpressionTreeImpl extends PyTree implements PyQualified private final PyExpressionTree qualifier; private final Token dotToken; - public PyQualifiedExpressionTreeImpl(AstNode astNode, PyNameTree name, PyExpressionTree qualifier, Token dotToken) { - super(astNode); - this.name = name; - this.qualifier = qualifier; - this.dotToken = dotToken; - } - public PyQualifiedExpressionTreeImpl(PyNameTree name, PyExpressionTree qualifier, Token dotToken) { super(qualifier.firstToken(), name.lastToken()); this.name = name; diff --git a/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java b/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java index 06b658dff4..bc9363ba5a 100644 --- a/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java +++ b/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java @@ -1001,11 +1001,10 @@ public PyQualifiedExpressionTree qualifiedExpression(AstNode astNode) { AstNode lastNameNode = astNode.getLastChild(); for (AstNode nameNode : names) { if (nameNode != lastNameNode) { - // FIXME: there is no corresponding astNode, parseTree and strongly typed AST are structurally different - qualifier = new PyQualifiedExpressionTreeImpl(astNode, name(nameNode), qualifier, nameNode.getPreviousSibling().getToken()); + qualifier = new PyQualifiedExpressionTreeImpl(name(nameNode), qualifier, nameNode.getPreviousSibling().getToken()); } } - return new PyQualifiedExpressionTreeImpl(astNode, name(lastNameNode), qualifier, lastNameNode.getPreviousSibling().getToken()); + return new PyQualifiedExpressionTreeImpl(name(lastNameNode), qualifier, lastNameNode.getPreviousSibling().getToken()); } public PyCallExpressionTree callExpression(AstNode astNode) { diff --git a/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java b/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java index 8bfd26d3d7..e64eddaf72 100644 --- a/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java +++ b/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java @@ -1163,9 +1163,13 @@ public void attributeRef_expression() { qualifiedExpression = parse("foo.bar.baz", treeMaker::qualifiedExpression); assertThat(qualifiedExpression.name().name()).isEqualTo("baz"); + assertThat(qualifiedExpression.firstToken().getValue()).isEqualTo("foo"); + assertThat(qualifiedExpression.lastToken().getValue()).isEqualTo("baz"); assertThat(qualifiedExpression.qualifier()).isInstanceOf(PyQualifiedExpressionTree.class); PyQualifiedExpressionTree qualExpr = (PyQualifiedExpressionTree) qualifiedExpression.qualifier(); assertThat(qualExpr.name().name()).isEqualTo("bar"); + assertThat(qualExpr.firstToken().getValue()).isEqualTo("foo"); + assertThat(qualExpr.lastToken().getValue()).isEqualTo("bar"); assertThat(qualExpr.qualifier()).isInstanceOf(PyNameTree.class); PyNameTree name = (PyNameTree) qualExpr.qualifier(); assertThat(name.name()).isEqualTo("foo"); From be582e030381dbdf2100c14ecdf60d3958af72e8 Mon Sep 17 00:00:00 2001 From: Andrea Guarino Date: Wed, 11 Sep 2019 14:57:23 +0200 Subject: [PATCH 2/4] SONARPY-407 ClassDef: argList should be null if there are no arguments --- .../java/org/sonar/python/api/tree/PyClassDefTree.java | 6 ------ .../java/org/sonar/python/tree/PythonTreeMaker.java | 4 +--- .../org/sonar/python/tree/PythonTreeMakerTest.java | 10 ++++++++++ 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/python-squid/src/main/java/org/sonar/python/api/tree/PyClassDefTree.java b/python-squid/src/main/java/org/sonar/python/api/tree/PyClassDefTree.java index 83e0ef5dbd..e8cfbec2f4 100644 --- a/python-squid/src/main/java/org/sonar/python/api/tree/PyClassDefTree.java +++ b/python-squid/src/main/java/org/sonar/python/api/tree/PyClassDefTree.java @@ -34,12 +34,6 @@ public interface PyClassDefTree extends PyStatementTree { @CheckForNull Token leftPar(); - - /** - * null if class is defined without args : class Foo: - * empty list if class defined with empty parentheses : class Foo(): - * @return - */ @CheckForNull PyArgListTree args(); diff --git a/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java b/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java index bc9363ba5a..029984ab25 100644 --- a/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java +++ b/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java @@ -505,9 +505,7 @@ public PyClassDefTree classDefStatement(AstNode astNode) { PyArgListTree args = null; AstNode leftPar = astNode.getFirstChild(PythonPunctuator.LPARENTHESIS); if (leftPar != null) { - AstNode argList = astNode.getFirstChild(PythonGrammar.ARGLIST); - // FIXME: PyArgList should never have null firstToken and lastToken - args = argList != null ? argList(argList) : new PyArgListTreeImpl(argList, Collections.emptyList()); + args = argList(astNode.getFirstChild(PythonGrammar.ARGLIST)); } PyStatementListTree body = getStatementListFromSuite(astNode.getFirstChild(PythonGrammar.SUITE)); Token classToken = astNode.getFirstChild(PythonKeyword.CLASS).getToken(); diff --git a/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java b/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java index e64eddaf72..a88f744905 100644 --- a/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java +++ b/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java @@ -757,6 +757,16 @@ public void classdef_statement() { assertThat(classDefTree.args().arguments().get(0).is(Tree.Kind.ARGUMENT)).isTrue(); assertThat(classDefTree.decorators()).isEmpty(); + classDefTree = parse("class clazz: pass", treeMaker::classDefStatement); + assertThat(classDefTree.leftPar()).isNull(); + assertThat(classDefTree.rightPar()).isNull(); + assertThat(classDefTree.args()).isNull(); + + classDefTree = parse("class clazz(): pass", treeMaker::classDefStatement); + assertThat(classDefTree.leftPar().getValue()).isEqualTo("("); + assertThat(classDefTree.rightPar().getValue()).isEqualTo(")"); + assertThat(classDefTree.args()).isNull(); + astNode = p.parse("@foo.bar\nclass clazz: pass"); classDefTree = treeMaker.classDefStatement(astNode); assertThat(classDefTree.decorators()).hasSize(1); From e6aacd89a663bd8ca52371a31d5ad673faa5d3f5 Mon Sep 17 00:00:00 2001 From: Andrea Guarino Date: Wed, 11 Sep 2019 16:32:19 +0200 Subject: [PATCH 3/4] SONARPY-407 Fix firstToken and lastToken for If, Else, Except, Finally nodes. Add more tests on first and last token --- .../python/tree/PyElseStatementTreeImpl.java | 5 +- .../python/tree/PyExceptClauseTreeImpl.java | 12 ++-- .../python/tree/PyFinallyClauseTreeImpl.java | 5 +- .../python/tree/PyIfStatementTreeImpl.java | 9 ++- .../sonar/python/tree/PythonTreeMaker.java | 16 ++--- .../python/tree/PythonTreeMakerTest.java | 66 ++++++++++++++++++- 6 files changed, 85 insertions(+), 28 deletions(-) diff --git a/python-squid/src/main/java/org/sonar/python/tree/PyElseStatementTreeImpl.java b/python-squid/src/main/java/org/sonar/python/tree/PyElseStatementTreeImpl.java index fd806f8927..1fe00892e8 100644 --- a/python-squid/src/main/java/org/sonar/python/tree/PyElseStatementTreeImpl.java +++ b/python-squid/src/main/java/org/sonar/python/tree/PyElseStatementTreeImpl.java @@ -19,7 +19,6 @@ */ package org.sonar.python.tree; -import com.sonar.sslr.api.AstNode; import com.sonar.sslr.api.Token; import java.util.Collections; import java.util.List; @@ -32,8 +31,8 @@ public class PyElseStatementTreeImpl extends PyTree implements PyElseStatementTr private final Token elseKeyword; private final PyStatementListTree body; - public PyElseStatementTreeImpl(AstNode astNode, Token elseKeyword, PyStatementListTree body) { - super(astNode); + public PyElseStatementTreeImpl(Token elseKeyword, PyStatementListTree body) { + super(elseKeyword, body.lastToken()); this.elseKeyword = elseKeyword; this.body = body; } diff --git a/python-squid/src/main/java/org/sonar/python/tree/PyExceptClauseTreeImpl.java b/python-squid/src/main/java/org/sonar/python/tree/PyExceptClauseTreeImpl.java index 873bb2914a..428fa8228c 100644 --- a/python-squid/src/main/java/org/sonar/python/tree/PyExceptClauseTreeImpl.java +++ b/python-squid/src/main/java/org/sonar/python/tree/PyExceptClauseTreeImpl.java @@ -38,8 +38,8 @@ public class PyExceptClauseTreeImpl extends PyTree implements PyExceptClauseTree private final Token commaToken; private final PyExpressionTree exceptionInstance; - public PyExceptClauseTreeImpl(AstNode astNode, Token exceptKeyword, PyStatementListTree body) { - super(astNode); + public PyExceptClauseTreeImpl(Token exceptKeyword, PyStatementListTree body) { + super(exceptKeyword, body.lastToken()); this.exceptKeyword = exceptKeyword; this.body = body; this.exception = null; @@ -48,8 +48,8 @@ public PyExceptClauseTreeImpl(AstNode astNode, Token exceptKeyword, PyStatementL this.exceptionInstance = null; } - public PyExceptClauseTreeImpl(AstNode astNode, Token exceptKeyword, PyStatementListTree body, PyExpressionTree exception, AstNode asNode, AstNode commaNode, PyExpressionTree exceptionInstance) { - super(astNode); + public PyExceptClauseTreeImpl(Token exceptKeyword, PyStatementListTree body, PyExpressionTree exception, AstNode asNode, AstNode commaNode, PyExpressionTree exceptionInstance) { + super(exceptKeyword, body.lastToken()); this.exceptKeyword = exceptKeyword; this.body = body; this.exception = exception; @@ -58,8 +58,8 @@ public PyExceptClauseTreeImpl(AstNode astNode, Token exceptKeyword, PyStatementL this.exceptionInstance = exceptionInstance; } - public PyExceptClauseTreeImpl(AstNode except, Token exceptKeyword, PyStatementListTree body, PyExpressionTree exception) { - super(except); + public PyExceptClauseTreeImpl(Token exceptKeyword, PyStatementListTree body, PyExpressionTree exception) { + super(exceptKeyword, body.lastToken()); this.exceptKeyword = exceptKeyword; this.body = body; this.exception = exception; diff --git a/python-squid/src/main/java/org/sonar/python/tree/PyFinallyClauseTreeImpl.java b/python-squid/src/main/java/org/sonar/python/tree/PyFinallyClauseTreeImpl.java index 6849d836d6..7e194147a3 100644 --- a/python-squid/src/main/java/org/sonar/python/tree/PyFinallyClauseTreeImpl.java +++ b/python-squid/src/main/java/org/sonar/python/tree/PyFinallyClauseTreeImpl.java @@ -19,7 +19,6 @@ */ package org.sonar.python.tree; -import com.sonar.sslr.api.AstNode; import com.sonar.sslr.api.Token; import java.util.Collections; import java.util.List; @@ -32,8 +31,8 @@ public class PyFinallyClauseTreeImpl extends PyTree implements PyFinallyClauseTr private final Token finallyKeyword; private final PyStatementListTree body; - public PyFinallyClauseTreeImpl(AstNode astNode, Token finallyKeyword, PyStatementListTree body) { - super(astNode); + public PyFinallyClauseTreeImpl(Token finallyKeyword, PyStatementListTree body) { + super(finallyKeyword, body.lastToken()); this.finallyKeyword = finallyKeyword; this.body = body; } diff --git a/python-squid/src/main/java/org/sonar/python/tree/PyIfStatementTreeImpl.java b/python-squid/src/main/java/org/sonar/python/tree/PyIfStatementTreeImpl.java index dc853d71e3..c68a3b029d 100644 --- a/python-squid/src/main/java/org/sonar/python/tree/PyIfStatementTreeImpl.java +++ b/python-squid/src/main/java/org/sonar/python/tree/PyIfStatementTreeImpl.java @@ -19,7 +19,6 @@ */ package org.sonar.python.tree; -import com.sonar.sslr.api.AstNode; import com.sonar.sslr.api.Token; import java.util.Arrays; import java.util.Collections; @@ -48,8 +47,8 @@ public class PyIfStatementTreeImpl extends PyTree implements PyIfStatementTree { * * If statement constructor */ - public PyIfStatementTreeImpl(AstNode node, Token ifKeyword, PyExpressionTree condition, PyStatementListTree statements, List elifBranches, @CheckForNull PyElseStatementTree elseStatement) { - super(node); + public PyIfStatementTreeImpl(Token ifKeyword, PyExpressionTree condition, PyStatementListTree statements, List elifBranches, @CheckForNull PyElseStatementTree elseStatement) { + super(ifKeyword, statements.lastToken()); this.keyword = ifKeyword; this.condition = condition; this.statements = statements; @@ -61,8 +60,8 @@ public PyIfStatementTreeImpl(AstNode node, Token ifKeyword, PyExpressionTree con /** * Elif statement constructor */ - public PyIfStatementTreeImpl(AstNode node, Token elifKeyword, PyExpressionTree condition, PyStatementListTree statements) { - super(node); + public PyIfStatementTreeImpl(Token elifKeyword, PyExpressionTree condition, PyStatementListTree statements) { + super(elifKeyword, statements.lastToken()); this.keyword = elifKeyword; this.condition = condition; this.statements = statements; diff --git a/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java b/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java index 029984ab25..29ac3085cf 100644 --- a/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java +++ b/python-squid/src/main/java/org/sonar/python/tree/PythonTreeMaker.java @@ -416,8 +416,7 @@ public PyIfStatementTree ifStatement(AstNode astNode) { .map(this::elifStatement) .collect(Collectors.toList()); - return new PyIfStatementTreeImpl( - astNode, ifToken, expression(condition), statements, elifBranches, elseStatement); + return new PyIfStatementTreeImpl(ifToken, expression(condition), statements, elifBranches, elseStatement); } private PyIfStatementTree elifStatement(AstNode astNode) { @@ -425,14 +424,13 @@ private PyIfStatementTree elifStatement(AstNode astNode) { AstNode suite = astNode.getNextSibling().getNextSibling().getNextSibling(); AstNode condition = astNode.getNextSibling(); PyStatementListTree statements = getStatementListFromSuite(suite); - return new PyIfStatementTreeImpl( - astNode, elifToken, expression(condition), statements); + return new PyIfStatementTreeImpl(elifToken, expression(condition), statements); } private PyElseStatementTree elseStatement(AstNode astNode) { Token elseToken = astNode.getPreviousSibling().getPreviousSibling().getToken(); PyStatementListTree statements = getStatementListFromSuite(astNode); - return new PyElseStatementTreeImpl(astNode, elseToken, statements); + return new PyElseStatementTreeImpl(elseToken, statements); } public PyFunctionDefTree funcDefStatement(AstNode astNode) { @@ -620,7 +618,7 @@ public PyTryStatementTree tryStatement(AstNode astNode) { if (finallyNode != null) { AstNode finallySuite = finallyNode.getNextSibling().getNextSibling(); PyStatementListTree body = getStatementListFromSuite(finallySuite); - finallyClause = new PyFinallyClauseTreeImpl(finallySuite, finallyNode.getToken(), body); + finallyClause = new PyFinallyClauseTreeImpl(finallyNode.getToken(), body); } PyElseStatementTree elseStatementTree = null; AstNode elseNode = astNode.getFirstChild(PythonKeyword.ELSE); @@ -665,15 +663,15 @@ private PyExceptClauseTree exceptClause(AstNode except, PyStatementListTree body Token exceptKeyword = except.getFirstChild(PythonKeyword.EXCEPT).getToken(); AstNode exceptionNode = except.getFirstChild(PythonGrammar.TEST); if (exceptionNode == null) { - return new PyExceptClauseTreeImpl(except, exceptKeyword, body); + return new PyExceptClauseTreeImpl(exceptKeyword, body); } AstNode asNode = except.getFirstChild(PythonKeyword.AS); AstNode commaNode = except.getFirstChild(PythonPunctuator.COMMA); if (asNode != null || commaNode != null) { PyExpressionTree exceptionInstance = expression(except.getLastChild(PythonGrammar.TEST)); - return new PyExceptClauseTreeImpl(except, exceptKeyword, body, expression(exceptionNode), asNode, commaNode, exceptionInstance); + return new PyExceptClauseTreeImpl(exceptKeyword, body, expression(exceptionNode), asNode, commaNode, exceptionInstance); } - return new PyExceptClauseTreeImpl(except, exceptKeyword, body, expression(exceptionNode)); + return new PyExceptClauseTreeImpl(exceptKeyword, body, expression(exceptionNode)); } // expressions diff --git a/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java b/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java index a88f744905..2e790e7cad 100644 --- a/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java +++ b/python-squid/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java @@ -204,6 +204,8 @@ public void IfStatement() { assertThat(pyIfStatementTree.isElif()).isFalse(); assertThat(pyIfStatementTree.elifBranches()).isEmpty(); PyElseStatementTree elseBranch = pyIfStatementTree.elseBranch(); + assertThat(elseBranch.firstToken().getValue()).isEqualTo("else"); + assertThat(elseBranch.lastToken().getValue()).isEqualTo("pass"); assertThat(elseBranch).isNotNull(); assertThat(elseBranch.elseKeyword().getValue()).isEqualTo("else"); assertThat(elseBranch.body().statements()).hasSize(1); @@ -218,6 +220,8 @@ public void IfStatement() { assertThat(pyIfStatementTree.elifBranches()).hasSize(1); PyIfStatementTree elif = pyIfStatementTree.elifBranches().get(0); assertThat(elif.condition()).isInstanceOf(PyExpressionTree.class); + assertThat(elif.firstToken().getValue()).isEqualTo("elif"); + assertThat(elif.lastToken().getValue()).isEqualTo("pass"); assertThat(elif.isElif()).isTrue(); assertThat(elif.elseBranch()).isNull(); assertThat(elif.elifBranches()).isEmpty(); @@ -482,6 +486,8 @@ public void importStatement() { setRootRule(PythonGrammar.IMPORT_STMT); AstNode astNode = p.parse("import foo"); PyImportNameTree importStatement = (PyImportNameTree) treeMaker.importStatement(astNode); + assertThat(importStatement.firstToken().getValue()).isEqualTo("import"); + assertThat(importStatement.lastToken().getValue()).isEqualTo("foo"); assertThat(importStatement).isNotNull(); assertThat(importStatement.importKeyword().getValue()).isEqualTo("import"); assertThat(importStatement.modules()).hasSize(1); @@ -493,9 +499,13 @@ public void importStatement() { astNode = p.parse("import foo as f"); importStatement = (PyImportNameTree) treeMaker.importStatement(astNode); assertThat(importStatement).isNotNull(); + assertThat(importStatement.firstToken().getValue()).isEqualTo("import"); + assertThat(importStatement.lastToken().getValue()).isEqualTo("f"); assertThat(importStatement.importKeyword().getValue()).isEqualTo("import"); assertThat(importStatement.modules()).hasSize(1); importedName1 = importStatement.modules().get(0); + assertThat(importedName1.firstToken().getValue()).isEqualTo("foo"); + assertThat(importedName1.lastToken().getValue()).isEqualTo("f"); assertThat(importedName1.dottedName().names()).hasSize(1); assertThat(importedName1.dottedName().names().get(0).name()).isEqualTo("foo"); assertThat(importedName1.asKeyword().getValue()).isEqualTo("as"); @@ -533,6 +543,8 @@ public void importFromStatement() { AstNode astNode = p.parse("from foo import f"); PyImportFromTree importStatement = (PyImportFromTree) treeMaker.importStatement(astNode); assertThat(importStatement).isNotNull(); + assertThat(importStatement.firstToken().getValue()).isEqualTo("from"); + assertThat(importStatement.lastToken().getValue()).isEqualTo("f"); assertThat(importStatement.importKeyword().getValue()).isEqualTo("import"); assertThat(importStatement.dottedPrefixForModule()).isEmpty(); assertThat(importStatement.fromKeyword().getValue()).isEqualTo("from"); @@ -863,6 +875,8 @@ public void assignement_statement() { setRootRule(PythonGrammar.EXPRESSION_STMT); AstNode astNode = p.parse("x = y"); PyAssignmentStatementTree pyAssignmentStatement = treeMaker.assignment(astNode); + assertThat(pyAssignmentStatement.firstToken().getValue()).isEqualTo("x"); + assertThat(pyAssignmentStatement.lastToken().getValue()).isEqualTo("y"); PyNameTree assigned = (PyNameTree) pyAssignmentStatement.assignedValue(); PyNameTree lhs = (PyNameTree) pyAssignmentStatement.lhsExpressions().get(0).expressions().get(0); assertThat(assigned.name()).isEqualTo("y"); @@ -917,6 +931,8 @@ public void annotated_assignment() { setRootRule(PythonGrammar.EXPRESSION_STMT); AstNode astNode = p.parse("x : string = 1"); PyAnnotatedAssignmentTree annAssign = treeMaker.annotatedAssignment(astNode); + assertThat(annAssign.firstToken().getValue()).isEqualTo("x"); + assertThat(annAssign.lastToken().getValue()).isEqualTo("1"); assertThat(annAssign.getKind()).isEqualTo(Tree.Kind.ANNOTATED_ASSIGNMENT); assertThat(annAssign.children()).hasSize(3); assertThat(annAssign.variable().getKind()).isEqualTo(Tree.Kind.NAME); @@ -952,6 +968,8 @@ public void compound_assignement_statement() { setRootRule(PythonGrammar.EXPRESSION_STMT); astNode = p.parse("x,y,z += 1"); pyCompoundAssignmentStatement = treeMaker.compoundAssignment(astNode); + assertThat(pyCompoundAssignmentStatement.firstToken().getValue()).isEqualTo("x"); + assertThat(pyCompoundAssignmentStatement.lastToken().getValue()).isEqualTo("1"); assertThat(pyCompoundAssignmentStatement.getKind()).isEqualTo(Tree.Kind.COMPOUND_ASSIGNMENT); assertThat(pyCompoundAssignmentStatement.children()).hasSize(2); assertThat(pyCompoundAssignmentStatement.compoundAssignmentToken().getValue()).isEqualTo("+="); @@ -978,11 +996,15 @@ public void try_statement() { setRootRule(PythonGrammar.TRY_STMT); AstNode astNode = p.parse("try: pass\nexcept Error: pass"); PyTryStatementTree tryStatement = treeMaker.tryStatement(astNode); + assertThat(tryStatement.firstToken().getValue()).isEqualTo("try"); + assertThat(tryStatement.lastToken().getValue()).isEqualTo("pass"); assertThat(tryStatement.tryKeyword().getValue()).isEqualTo("try"); assertThat(tryStatement.body().statements()).hasSize(1); assertThat(tryStatement.elseClause()).isNull(); assertThat(tryStatement.finallyClause()).isNull(); assertThat(tryStatement.exceptClauses()).hasSize(1); + assertThat(tryStatement.exceptClauses().get(0).firstToken().getValue()).isEqualTo("except"); + assertThat(tryStatement.exceptClauses().get(0).lastToken().getValue()).isEqualTo("pass"); assertThat(tryStatement.exceptClauses().get(0).exceptKeyword().getValue()).isEqualTo("except"); assertThat(tryStatement.exceptClauses().get(0).body().statements()).hasSize(1); assertThat(tryStatement.children()).hasSize(4); @@ -1002,6 +1024,8 @@ public void try_statement() { assertThat(tryStatement.elseClause()).isNull(); assertThat(tryStatement.exceptClauses()).hasSize(1); assertThat(tryStatement.finallyClause()).isNotNull(); + assertThat(tryStatement.finallyClause().firstToken().getValue()).isEqualTo("finally"); + assertThat(tryStatement.finallyClause().lastToken().getValue()).isEqualTo("pass"); assertThat(tryStatement.finallyClause().finallyKeyword().getValue()).isEqualTo("finally"); assertThat(tryStatement.finallyClause().body().statements()).hasSize(1); assertThat(tryStatement.children()).hasSize(4); @@ -1012,6 +1036,8 @@ public void try_statement() { assertThat(tryStatement.exceptClauses()).hasSize(1); assertThat(tryStatement.finallyClause()).isNull(); assertThat(tryStatement.elseClause().elseKeyword().getValue()).isEqualTo("else"); + assertThat(tryStatement.elseClause().firstToken().getValue()).isEqualTo("else"); + assertThat(tryStatement.elseClause().lastToken().getValue()).isEqualTo("pass"); assertThat(tryStatement.elseClause().body().statements()).hasSize(1); assertThat(tryStatement.children()).hasSize(4); @@ -1066,6 +1092,8 @@ public void async_statement() { public void with_statement() { setRootRule(PythonGrammar.WITH_STMT); PyWithStatementTree withStatement = parse("with foo : pass", treeMaker::withStatement); + assertThat(withStatement.firstToken().getValue()).isEqualTo("with"); + assertThat(withStatement.lastToken().getValue()).isEqualTo("pass"); assertThat(withStatement.isAsync()).isFalse(); assertThat(withStatement.asyncKeyword()).isNull(); assertThat(withStatement.withItems()).hasSize(1); @@ -1081,11 +1109,15 @@ public void with_statement() { withStatement = parse("with foo as bar, qix : pass", treeMaker::withStatement); assertThat(withStatement.withItems()).hasSize(2); pyWithItemTree = withStatement.withItems().get(0); + assertThat(pyWithItemTree.firstToken().getValue()).isEqualTo("foo"); + assertThat(pyWithItemTree.lastToken().getValue()).isEqualTo("bar"); assertThat(pyWithItemTree.test()).isNotNull(); assertThat(pyWithItemTree.as()).isNotNull(); assertThat(pyWithItemTree.expression()).isNotNull(); pyWithItemTree = withStatement.withItems().get(1); assertThat(pyWithItemTree.test()).isNotNull(); + assertThat(pyWithItemTree.firstToken().getValue()).isEqualTo("qix"); + assertThat(pyWithItemTree.lastToken().getValue()).isEqualTo("qix"); assertThat(pyWithItemTree.as()).isNull(); assertThat(pyWithItemTree.expression()).isNull(); assertThat(withStatement.statements().statements()).hasSize(1); @@ -1115,6 +1147,8 @@ public void call_expression() { setRootRule(PythonGrammar.CALL_EXPR); PyCallExpressionTree callExpression = parse("foo()", treeMaker::callExpression); assertThat(callExpression.argumentList()).isNull(); + assertThat(callExpression.firstToken().getValue()).isEqualTo("foo"); + assertThat(callExpression.lastToken().getValue()).isEqualTo(")"); assertThat(callExpression.arguments()).isEmpty(); PyNameTree name = (PyNameTree) callExpression.callee(); assertThat(name.name()).isEqualTo("foo"); @@ -1136,6 +1170,8 @@ public void call_expression() { callExpression = parse("foo.bar()", treeMaker::callExpression); assertThat(callExpression.argumentList()).isNull(); PyQualifiedExpressionTree callee = (PyQualifiedExpressionTree) callExpression.callee(); + assertThat(callExpression.firstToken().getValue()).isEqualTo("foo"); + assertThat(callExpression.lastToken().getValue()).isEqualTo(")"); assertThat(callee.name().name()).isEqualTo("bar"); assertThat(((PyNameTree) callee.qualifier()).name()).isEqualTo("foo"); assertThat(callExpression.children()).hasSize(2); @@ -1149,6 +1185,8 @@ public void combinations_with_call_expressions() { assertThat(nestingCall.argumentList().arguments()).extracting(t -> t.expression().getKind()).containsExactly(Tree.Kind.NUMERIC_LITERAL); PyQualifiedExpressionTree callee = (PyQualifiedExpressionTree) nestingCall.callee(); assertThat(callee.name().name()).isEqualTo("bar"); + assertThat(callee.qualifier().firstToken().getValue()).isEqualTo("foo"); + assertThat(callee.qualifier().lastToken().getValue()).isEqualTo(")"); assertThat(callee.qualifier().getKind()).isEqualTo(Tree.Kind.CALL_EXPR); nestingCall = (PyCallExpressionTree) parse("foo('a').bar()", treeMaker::expression); @@ -1554,6 +1592,8 @@ public void list_literal() { setRootRule(PythonGrammar.ATOM); PyExpressionTree parse = parse("[1, \"foo\"]", treeMaker::expression); assertThat(parse.is(Tree.Kind.LIST_LITERAL)).isTrue(); + assertThat(parse.firstToken().getValue()).isEqualTo("["); + assertThat(parse.lastToken().getValue()).isEqualTo("]"); PyListLiteralTree listLiteralTree = (PyListLiteralTree) parse; List expressions = listLiteralTree.elements().expressions(); assertThat(expressions).hasSize(2); @@ -1570,9 +1610,13 @@ public void list_comprehension() { PyComprehensionExpressionTree comprehension = (PyComprehensionExpressionTree) parse("[x+y for x,y in [(42, 43)]]", treeMaker::expression); assertThat(comprehension.getKind()).isEqualTo(Tree.Kind.LIST_COMPREHENSION); + assertThat(comprehension.firstToken().getValue()).isEqualTo("["); + assertThat(comprehension.lastToken().getValue()).isEqualTo("]"); assertThat(comprehension.resultExpression().getKind()).isEqualTo(Tree.Kind.PLUS); assertThat(comprehension.children()).hasSize(2); PyComprehensionForTree forClause = comprehension.comprehensionFor(); + assertThat(forClause.firstToken().getValue()).isEqualTo("for"); + assertThat(forClause.lastToken().getValue()).isEqualTo("]"); assertThat(forClause.getKind()).isEqualTo(Tree.Kind.COMP_FOR); assertThat(forClause.forToken().getValue()).isEqualTo("for"); assertThat(forClause.loopExpression().getKind()).isEqualTo(Tree.Kind.TUPLE); @@ -1655,7 +1699,10 @@ public void tuples() { private PyTupleTree parseTuple(String code) { setRootRule(PythonGrammar.TEST); - return (PyTupleTree) parse(code, treeMaker::expression); + PyTupleTree tuple = (PyTupleTree) parse(code, treeMaker::expression); + assertThat(tuple.firstToken().getValue()).isEqualTo("("); + assertThat(tuple.lastToken().getValue()).isEqualTo(")"); + return tuple; } @Test @@ -1678,6 +1725,8 @@ public void not() { public void conditional_expression() { setRootRule(PythonGrammar.TEST); PyConditionalExpressionTree conditionalExpressionTree = (PyConditionalExpressionTree) parse("1 if condition else 2", treeMaker::expression); + assertThat(conditionalExpressionTree.firstToken().getValue()).isEqualTo("1"); + assertThat(conditionalExpressionTree.lastToken().getValue()).isEqualTo("2"); assertThat(conditionalExpressionTree.ifKeyword().getValue()).isEqualTo("if"); assertThat(conditionalExpressionTree.elseKeyword().getValue()).isEqualTo("else"); assertThat(conditionalExpressionTree.condition().getKind()).isEqualTo(Tree.Kind.NAME); @@ -1688,13 +1737,18 @@ public void conditional_expression() { (PyConditionalExpressionTree) parse("1 if x else 2 if y else 3", treeMaker::expression); assertThat(nestedConditionalExpressionTree.condition().getKind()).isEqualTo(Tree.Kind.NAME); assertThat(nestedConditionalExpressionTree.trueExpression().getKind()).isEqualTo(Tree.Kind.NUMERIC_LITERAL); - assertThat(nestedConditionalExpressionTree.falseExpression().getKind()).isEqualTo(Tree.Kind.CONDITIONAL_EXPR); + PyExpressionTree nestedConditionalExpr = nestedConditionalExpressionTree.falseExpression(); + assertThat(nestedConditionalExpr.firstToken().getValue()).isEqualTo("2"); + assertThat(nestedConditionalExpr.lastToken().getValue()).isEqualTo("3"); + assertThat(nestedConditionalExpr.getKind()).isEqualTo(Tree.Kind.CONDITIONAL_EXPR); } @Test public void dictionary_literal() { setRootRule(PythonGrammar.ATOM); PyDictionaryLiteralTree tree = (PyDictionaryLiteralTree) parse("{'key': 'value'}", treeMaker::expression); + assertThat(tree.firstToken().getValue()).isEqualTo("{"); + assertThat(tree.lastToken().getValue()).isEqualTo("}"); assertThat(tree.getKind()).isEqualTo(Tree.Kind.DICTIONARY_LITERAL); assertThat(tree.elements()).hasSize(1); PyKeyValuePairTree keyValuePair = tree.elements().iterator().next(); @@ -1722,6 +1776,8 @@ public void dict_comprehension() { setRootRule(PythonGrammar.TEST); PyDictCompExpressionTree comprehension = (PyDictCompExpressionTree) parse("{x-1:y+1 for x,y in [(42,43)]}", treeMaker::expression); + assertThat(comprehension.firstToken().getValue()).isEqualTo("{"); + assertThat(comprehension.lastToken().getValue()).isEqualTo("}"); assertThat(comprehension.getKind()).isEqualTo(Tree.Kind.DICT_COMPREHENSION); assertThat(comprehension.colonToken().getValue()).isEqualTo(":"); assertThat(comprehension.keyExpression().getKind()).isEqualTo(Tree.Kind.MINUS); @@ -1736,6 +1792,8 @@ public void dict_comprehension() { public void set_literal() { setRootRule(PythonGrammar.ATOM); PySetLiteralTree tree = (PySetLiteralTree) parse("{ x }", treeMaker::expression); + assertThat(tree.firstToken().getValue()).isEqualTo("{"); + assertThat(tree.lastToken().getValue()).isEqualTo("}"); assertThat(tree.getKind()).isEqualTo(Tree.Kind.SET_LITERAL); assertThat(tree.elements()).hasSize(1); PyExpressionTree element = tree.elements().iterator().next(); @@ -1759,6 +1817,8 @@ public void set_comprehension() { setRootRule(PythonGrammar.TEST); PyComprehensionExpressionTree comprehension = (PyComprehensionExpressionTree) parse("{x-1 for x in [42, 43]}", treeMaker::expression); + assertThat(comprehension.firstToken().getValue()).isEqualTo("{"); + assertThat(comprehension.lastToken().getValue()).isEqualTo("}"); assertThat(comprehension.getKind()).isEqualTo(Tree.Kind.SET_COMPREHENSION); assertThat(comprehension.resultExpression().getKind()).isEqualTo(Tree.Kind.MINUS); assertThat(comprehension.children()).hasSize(2); @@ -1771,6 +1831,8 @@ public void repr_expression() { setRootRule(PythonGrammar.ATOM); PyReprExpressionTree reprExpressionTree = (PyReprExpressionTree) parse("`1`", treeMaker::expression); assertThat(reprExpressionTree.getKind()).isEqualTo(Tree.Kind.REPR); + assertThat(reprExpressionTree.firstToken().getValue()).isEqualTo("`"); + assertThat(reprExpressionTree.lastToken().getValue()).isEqualTo("`"); assertThat(reprExpressionTree.openingBacktick().getValue()).isEqualTo("`"); assertThat(reprExpressionTree.closingBacktick().getValue()).isEqualTo("`"); assertThat(reprExpressionTree.expressionList().expressions()).hasSize(1); From 9831015bedbe955d52a1cdcecb94a09b0f990407 Mon Sep 17 00:00:00 2001 From: Andrea Guarino Date: Wed, 11 Sep 2019 17:57:14 +0200 Subject: [PATCH 4/4] Fixes after review --- .../sonar/python/api/tree/PyClassDefTree.java | 3 + .../python/tree/BaseTreeVisitorTest.java | 70 ++++++++++++------- 2 files changed, 46 insertions(+), 27 deletions(-) diff --git a/python-squid/src/main/java/org/sonar/python/api/tree/PyClassDefTree.java b/python-squid/src/main/java/org/sonar/python/api/tree/PyClassDefTree.java index e8cfbec2f4..e8fbfa5a96 100644 --- a/python-squid/src/main/java/org/sonar/python/api/tree/PyClassDefTree.java +++ b/python-squid/src/main/java/org/sonar/python/api/tree/PyClassDefTree.java @@ -34,6 +34,9 @@ public interface PyClassDefTree extends PyStatementTree { @CheckForNull Token leftPar(); + /** + * null if class is defined without args {@code class Foo:...} or {@code class Foo():...} + */ @CheckForNull PyArgListTree args(); diff --git a/python-squid/src/test/java/org/sonar/python/tree/BaseTreeVisitorTest.java b/python-squid/src/test/java/org/sonar/python/tree/BaseTreeVisitorTest.java index cb809d86b9..465ef6998d 100644 --- a/python-squid/src/test/java/org/sonar/python/tree/BaseTreeVisitorTest.java +++ b/python-squid/src/test/java/org/sonar/python/tree/BaseTreeVisitorTest.java @@ -22,6 +22,7 @@ import com.sonar.sslr.api.AstNode; import java.util.List; import java.util.function.Function; +import javax.annotation.Nullable; import org.junit.Test; import org.sonar.python.api.PythonGrammar; import org.sonar.python.api.tree.PyAnnotatedAssignmentTree; @@ -64,19 +65,34 @@ import org.sonar.python.api.tree.PyTupleTree; import org.sonar.python.api.tree.PyWithStatementTree; import org.sonar.python.api.tree.PyYieldStatementTree; +import org.sonar.python.api.tree.Tree; import org.sonar.python.parser.RuleTest; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; public class BaseTreeVisitorTest extends RuleTest { private final PythonTreeMaker treeMaker = new PythonTreeMaker(); + private static class FirstLastTokenVerifierVisitor extends BaseTreeVisitor { + public FirstLastTokenVerifierVisitor() {} + + @Override + protected void scan(@Nullable Tree tree) { + if (tree != null) { + assertThat(tree.firstToken()).isNotNull(); + assertThat(tree.lastToken()).isNotNull(); + } + super.scan(tree); + } + } + @Test public void if_statement() { setRootRule(PythonGrammar.IF_STMT); PyIfStatementTree tree = parse("if p1: print 'a'\nelif p2: return\nelse: yield", treeMaker::ifStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitIfStatement(tree); verify(visitor).visitIfStatement(tree); verify(visitor).visitIfStatement(tree.elifBranches().get(0)); @@ -89,7 +105,7 @@ public void if_statement() { public void exec_statement() { setRootRule(PythonGrammar.EXEC_STMT); PyExecStatementTree tree = parse("exec 'foo' in globals, locals", treeMaker::execStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitExecStatement(tree); verify(visitor).scan(tree.expression()); verify(visitor).scan(tree.globalsExpression()); @@ -100,7 +116,7 @@ public void exec_statement() { public void assert_statement() { setRootRule(PythonGrammar.ASSERT_STMT); PyAssertStatementTree tree = parse("assert x, y", treeMaker::assertStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitAssertStatement(tree); verify(visitor).scan(tree.expressions()); } @@ -109,7 +125,7 @@ public void assert_statement() { public void delete_statement() { setRootRule(PythonGrammar.DEL_STMT); PyDelStatementTree tree = parse("del x", treeMaker::delStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitDelStatement(tree); verify(visitor).scan(tree.expressions()); } @@ -119,7 +135,7 @@ public void fundef_statement() { setRootRule(PythonGrammar.FUNCDEF); PyFunctionDefTree pyFunctionDefTree = parse("def foo(x:int): pass", treeMaker::funcDefStatement); PyParameterTree parameter = pyFunctionDefTree.parameters().nonTuple().get(0); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitFunctionDef(pyFunctionDefTree); verify(visitor).visitName(pyFunctionDefTree.name()); verify(visitor).visitParameter(parameter); @@ -131,7 +147,7 @@ public void fundef_statement() { public void fundef_with_tuple_param() { setRootRule(PythonGrammar.FUNCDEF); PyFunctionDefTree pyFunctionDefTree = parse("def foo(x, (y, z)): pass", treeMaker::funcDefStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitFunctionDef(pyFunctionDefTree); List parameters = pyFunctionDefTree.parameters().all(); @@ -146,13 +162,13 @@ public void fundef_with_tuple_param() { public void import_statement() { setRootRule(PythonGrammar.IMPORT_STMT); PyImportFromTree tree = (PyImportFromTree) parse("from foo import f as g", treeMaker::importStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitImportFrom(tree); verify(visitor).visitAliasedName(tree.importedNames().get(0)); verify(visitor).visitDottedName(tree.module()); PyImportNameTree pyTree = (PyImportNameTree) parse("import f as g", treeMaker::importStatement); - visitor = spy(BaseTreeVisitor.class); + visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitImportName(pyTree); verify(visitor).visitAliasedName(pyTree.modules().get(0)); } @@ -161,7 +177,7 @@ public void import_statement() { public void for_statement() { setRootRule(PythonGrammar.FOR_STMT); PyForStatementTree tree = parse("for foo in bar:pass\nelse: pass", treeMaker::forStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitForStatement(tree); verify(visitor).visitPassStatement((PyPassStatementTree) tree.body().statements().get(0)); verify(visitor).visitPassStatement((PyPassStatementTree) tree.elseBody().statements().get(0)); @@ -171,7 +187,7 @@ public void for_statement() { public void while_statement() { setRootRule(PythonGrammar.WHILE_STMT); PyWhileStatementTreeImpl tree = parse("while foo:\n pass\nelse:\n pass", treeMaker::whileStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitWhileStatement(tree); verify(visitor).visitPassStatement((PyPassStatementTree) tree.body().statements().get(0)); verify(visitor).visitPassStatement((PyPassStatementTree) tree.elseBody().statements().get(0)); @@ -181,7 +197,7 @@ public void while_statement() { public void try_statement() { setRootRule(PythonGrammar.TRY_STMT); PyTryStatementTree tree = parse("try: pass\nexcept Error: pass\nfinally: pass", treeMaker::tryStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitTryStatement(tree); verify(visitor).visitFinallyClause(tree.finallyClause()); verify(visitor).visitExceptClause(tree.exceptClauses().get(0)); @@ -192,7 +208,7 @@ public void try_statement() { public void with_statement() { setRootRule(PythonGrammar.WITH_STMT); PyWithStatementTree tree = parse("with foo as bar, qix : pass", treeMaker::withStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitWithStatement(tree); verify(visitor).visitWithItem(tree.withItems().get(0)); verify(visitor).visitPassStatement((PyPassStatementTree) tree.statements().statements().get(0)); @@ -202,7 +218,7 @@ public void with_statement() { public void class_statement() { setRootRule(PythonGrammar.CLASSDEF); PyClassDefTree tree = parse("class clazz(Parent): pass", treeMaker::classDefStatement); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitClassDef(tree); verify(visitor).visitName(tree.name()); verify(visitor).visitArgumentList(tree.args()); @@ -213,7 +229,7 @@ public void class_statement() { public void qualified_expr() { setRootRule(PythonGrammar.ATTRIBUTE_REF); PyQualifiedExpressionTree tree = parse("a.b", treeMaker::qualifiedExpression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitQualifiedExpression(tree); verify(visitor).visitName(tree.name()); } @@ -222,7 +238,7 @@ public void qualified_expr() { public void assignement_stmt() { setRootRule(PythonGrammar.EXPRESSION_STMT); PyAssignmentStatementTree tree = parse("a = b", treeMaker::assignment); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitAssignmentStatement(tree); verify(visitor).visitExpressionList(tree.lhsExpressions().get(0)); } @@ -231,7 +247,7 @@ public void assignement_stmt() { public void annotated_assignment() { setRootRule(PythonGrammar.EXPRESSION_STMT); PyAnnotatedAssignmentTree tree = parse("a : int = b", treeMaker::annotatedAssignment); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitAnnotatedAssignment(tree); verify(visitor).visitName((PyNameTree) tree.variable()); verify(visitor).visitName((PyNameTree) tree.annotation()); @@ -242,7 +258,7 @@ public void annotated_assignment() { public void lambda() { setRootRule(PythonGrammar.LAMBDEF); PyLambdaExpressionTree tree = parse("lambda x : x", treeMaker::lambdaExpression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); visitor.visitLambda(tree); verify(visitor).visitParameterList(tree.parameters()); verify(visitor).visitParameter(tree.parameters().nonTuple().get(0)); @@ -252,7 +268,7 @@ public void lambda() { public void starred_expr() { setRootRule(PythonGrammar.STAR_EXPR); PyStarredExpressionTree tree = (PyStarredExpressionTree) parse("*a", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); tree.accept(visitor); verify(visitor).visitName((PyNameTree) tree.expression()); } @@ -261,7 +277,7 @@ public void starred_expr() { public void await_expr() { setRootRule(PythonGrammar.EXPR); PyAwaitExpressionTree tree = (PyAwaitExpressionTree) parse("await x", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); tree.accept(visitor); verify(visitor).visitName((PyNameTree) tree.expression()); } @@ -270,7 +286,7 @@ public void await_expr() { public void slice_expr() { setRootRule(PythonGrammar.EXPR); PySliceExpressionTree expr = (PySliceExpressionTree) parse("a[b:c:d]", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); expr.accept(visitor); verify(visitor).visitName((PyNameTree) expr.object()); verify(visitor).visitSliceList(expr.sliceList()); @@ -285,7 +301,7 @@ public void slice_expr() { public void subscription_expr() { setRootRule(PythonGrammar.EXPR); PySubscriptionExpressionTree expr = (PySubscriptionExpressionTree) parse("a[b]", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); expr.accept(visitor); verify(visitor).visitName((PyNameTree) expr.object()); verify(visitor).visitName((PyNameTree) expr.subscripts().expressions().get(0)); @@ -295,7 +311,7 @@ public void subscription_expr() { public void parenthesized_expr() { setRootRule(PythonGrammar.EXPR); PyParenthesizedExpressionTree expr = (PyParenthesizedExpressionTree) parse("(a)", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); expr.accept(visitor); verify(visitor).visitName((PyNameTree) expr.expression()); } @@ -304,7 +320,7 @@ public void parenthesized_expr() { public void tuple() { setRootRule(PythonGrammar.EXPR); PyTupleTree expr = (PyTupleTree) parse("(a,)", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); expr.accept(visitor); verify(visitor).visitName((PyNameTree) expr.elements().get(0)); } @@ -313,7 +329,7 @@ public void tuple() { public void cond_expression() { setRootRule(PythonGrammar.TEST); PyConditionalExpressionTree expr = (PyConditionalExpressionTree) parse("1 if p else 2", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); expr.accept(visitor); verify(visitor).visitName((PyNameTree) expr.condition()); verify(visitor).visitNumericLiteral((PyNumericLiteralTree) expr.trueExpression()); @@ -324,7 +340,7 @@ public void cond_expression() { public void list_or_set_comprehension() { setRootRule(PythonGrammar.EXPR); PyComprehensionExpressionTree expr = (PyComprehensionExpressionTree) parse("[x+1 for x in [42, 43] if cond(x)]", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); expr.accept(visitor); verify(visitor).visitBinaryExpression((PyBinaryExpressionTree) expr.resultExpression()); @@ -342,7 +358,7 @@ public void list_or_set_comprehension() { public void dict_comprehension() { setRootRule(PythonGrammar.TEST); PyDictCompExpressionTree expr = (PyDictCompExpressionTree) parse("{x+1:y-1 for x,y in map}", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); expr.accept(visitor); verify(visitor).visitBinaryExpression((PyBinaryExpressionTree) expr.keyExpression()); @@ -354,7 +370,7 @@ public void dict_comprehension() { public void repr_expression() { setRootRule(PythonGrammar.ATOM); PyReprExpressionTree expr = (PyReprExpressionTree) parse("`1`", treeMaker::expression); - BaseTreeVisitor visitor = spy(BaseTreeVisitor.class); + FirstLastTokenVerifierVisitor visitor = spy(FirstLastTokenVerifierVisitor.class); expr.accept(visitor); verify(visitor).visitNumericLiteral((PyNumericLiteralTree) expr.expressionList().expressions().get(0));