Skip to content

Commit 3b1be31

Browse files
joke1196sonartech
authored andcommitted
SONARPY-2441: Fix NPE when qualified expression is used as keyword argument (#393)
GitOrigin-RevId: 329a636f233c46a099cfa1b70c5c24c08ac2a37e
1 parent c50ae79 commit 3b1be31

File tree

3 files changed

+10
-3
lines changed

3 files changed

+10
-3
lines changed

python-frontend/src/main/java/org/sonar/python/api/PythonGrammarBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ protected void grammar(LexerfulGrammarBuilder b) {
112112
POWER)).skipIfOneChild();
113113
b.rule(POWER).is(b.firstOf(
114114
b.sequence(b.optional("await"), ATOM, b.zeroOrMore(TRAILER), b.optional("**", FACTOR)),
115-
// matches "await" identifier
115+
// before python 3.5 "await" can be used as an identifier
116116
"await")).skipIfOneChild();
117117

118118
b.rule(ATOM).is(b.firstOf(

python-frontend/src/main/java/org/sonar/python/tree/PythonTreeMaker.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1584,8 +1584,11 @@ public Argument argument(AstNode astNode) {
15841584
Expression arg = expression(astNode.getLastChild(PythonGrammar.TEST));
15851585
if (assign != null) {
15861586
// Keyword in argument list must be an identifier.
1587-
AstNode nameNode = astNode.getFirstChild(PythonGrammar.TEST).getFirstChild(PythonGrammar.ATOM).getFirstChild(PythonGrammar.NAME);
1588-
return new RegularArgumentImpl(name(nameNode), toPyToken(assign.getToken()), arg);
1587+
return Optional.ofNullable(astNode.getFirstChild(PythonGrammar.TEST))
1588+
.map(test -> test.getFirstChild(PythonGrammar.ATOM))
1589+
.map(atom -> atom.getFirstChild(PythonGrammar.NAME))
1590+
.map(nameNode -> new RegularArgumentImpl(name(nameNode), toPyToken(assign.getToken()), arg))
1591+
.orElseThrow(() -> new IllegalStateException("Keyword argument must be an identifier"));
15891592
}
15901593
return star == null ? new RegularArgumentImpl(arg) : new UnpackingExpressionImpl(star, arg);
15911594
}

python-frontend/src/test/java/org/sonar/python/tree/PythonTreeMakerTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@
120120
import static org.assertj.core.api.Assertions.assertThat;
121121
import static org.assertj.core.api.Assertions.assertThatThrownBy;
122122
import static org.assertj.core.api.Assertions.fail;
123+
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
123124

124125
class PythonTreeMakerTest extends RuleTest {
125126

@@ -1748,6 +1749,9 @@ void argument() {
17481749
name = (Name) argumentTree.expression();
17491750
assertThat(name.name()).isEqualTo("foo");
17501751
assertThat(argumentTree.children()).hasSize(3).containsExactly(argumentTree.keywordArgument(), argumentTree.equalToken(), argumentTree.expression());
1752+
1753+
IllegalStateException exception = assertThrowsExactly(IllegalStateException.class, () -> parse("obj.bar=foo", treeMaker::argument));
1754+
assertThat(exception.getMessage()).isEqualTo("Keyword argument must be an identifier");
17511755
}
17521756

17531757
@Test

0 commit comments

Comments
 (0)