Skip to content

Commit fd05909

Browse files
committed
SONARPY-2056 IPython line magics starting with numbers or special characters should be parsed correctly (#1910)
1 parent df58518 commit fd05909

File tree

4 files changed

+20
-12
lines changed

4 files changed

+20
-12
lines changed

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@
2424
import static com.sonar.sslr.api.GenericTokenType.EOF;
2525
import static org.sonar.python.api.IPythonGrammar.CELL;
2626
import static org.sonar.python.api.IPythonGrammar.CELL_MAGIC_STATEMENT;
27-
import static org.sonar.python.api.IPythonGrammar.LINE_MAGIC_STATEMENT;
2827
import static org.sonar.python.api.IPythonGrammar.DYNAMIC_OBJECT_INFO_STATEMENT;
2928
import static org.sonar.python.api.IPythonGrammar.LINE_MAGIC;
29+
import static org.sonar.python.api.IPythonGrammar.LINE_MAGIC_STATEMENT;
3030
import static org.sonar.python.api.IPythonGrammar.MAGIC_CELL;
31-
import static org.sonar.python.api.PythonGrammar.ASSERT_STMT;
3231
import static org.sonar.python.api.PythonGrammar.ANNOTATED_RHS;
32+
import static org.sonar.python.api.PythonGrammar.ASSERT_STMT;
3333
import static org.sonar.python.api.PythonGrammar.BREAK_STMT;
3434
import static org.sonar.python.api.PythonGrammar.CONTINUE_STMT;
3535
import static org.sonar.python.api.PythonGrammar.DEL_STMT;
@@ -38,7 +38,6 @@
3838
import static org.sonar.python.api.PythonGrammar.FILE_INPUT;
3939
import static org.sonar.python.api.PythonGrammar.GLOBAL_STMT;
4040
import static org.sonar.python.api.PythonGrammar.IMPORT_STMT;
41-
import static org.sonar.python.api.PythonGrammar.NAME;
4241
import static org.sonar.python.api.PythonGrammar.NONLOCAL_STMT;
4342
import static org.sonar.python.api.PythonGrammar.PASS_STMT;
4443
import static org.sonar.python.api.PythonGrammar.PRINT_STMT;
@@ -75,7 +74,7 @@ protected void iPythonRules(LexerfulGrammarBuilder b) {
7574
b.rule(LINE_MAGIC_STATEMENT).is(LINE_MAGIC);
7675
b.rule(LINE_MAGIC).is(
7776
b.firstOf(PythonPunctuator.MOD, "!", PythonPunctuator.DIV),
78-
NAME,
77+
b.anyTokenButNot(PythonPunctuator.MOD),
7978
b.zeroOrMore(b.anyTokenButNot(b.firstOf(NEWLINE, b.next(EOF))))
8079
);
8180
b.rule(DYNAMIC_OBJECT_INFO_STATEMENT).is(b.firstOf(

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

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141
import org.sonar.python.DocstringExtractor;
4242
import org.sonar.python.IPythonLocation;
4343
import org.sonar.python.api.IPythonGrammar;
44-
import org.sonar.python.api.PythonGrammar;
4544

4645
public class IPythonTreeMaker extends PythonTreeMaker {
4746

@@ -153,15 +152,14 @@ protected DynamicObjectInfoStatement dynamicObjectInfoStatement(AstNode astNode)
153152

154153
protected LineMagic lineMagic(AstNode astNode) {
155154
var percent = toPyToken(astNode.getFirstChild().getToken());
156-
var name = toPyToken(astNode.getFirstChild(PythonGrammar.NAME).getToken());
157155

158156
var tokens = astNode.getChildren()
159157
.stream()
160-
.skip(2)
158+
.skip(1)
161159
.map(AstNode::getTokens)
162160
.flatMap(Collection::stream)
163161
.map(this::toPyToken)
164162
.toList();
165-
return new LineMagicImpl(percent, name, tokens);
163+
return new LineMagicImpl(percent, tokens);
166164
}
167165
}

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,10 @@
2929
public class LineMagicImpl extends PyTree implements LineMagic {
3030

3131
private final Token percent;
32-
private final Tree name;
3332
private final List<Token> tokens;
3433

35-
public LineMagicImpl(Token percent, Tree name, List<Token> tokens) {
34+
public LineMagicImpl(Token percent, List<Token> tokens) {
3635
this.percent = percent;
37-
this.name = name;
3836
this.tokens = tokens;
3937
}
4038

@@ -52,7 +50,6 @@ public Kind getKind() {
5250
List<Tree> computeChildren() {
5351
var children = new ArrayList<Tree>();
5452
children.add(percent);
55-
children.add(name);
5653
children.addAll(tokens);
5754
return children;
5855
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,20 @@ void lineMagic() {
212212
assertThat(lineMagic)
213213
.isNotNull()
214214
.isInstanceOf(LineMagic.class);
215+
216+
statements = parseIPython("""
217+
!7z --help
218+
!./script.sh
219+
!
220+
""", treeMaker::fileInput).statements().statements();
221+
assertThat(statements).hasSize(3);
222+
assertThat(statements.get(0).getKind()).isEqualTo(Tree.Kind.EXPRESSION_STMT);
223+
assertThat(((ExpressionStatement) statements.get(0)).expressions()).hasSize(1).allMatch(e -> e.is(Tree.Kind.LINE_MAGIC));
224+
assertThat(statements.get(1).getKind()).isEqualTo(Tree.Kind.EXPRESSION_STMT);
225+
assertThat(((ExpressionStatement) statements.get(1)).expressions()).hasSize(1).allMatch(e -> e.is(Tree.Kind.LINE_MAGIC));
226+
assertThat(statements.get(2).getKind()).isEqualTo(Tree.Kind.EXPRESSION_STMT);
227+
assertThat(((ExpressionStatement) statements.get(2)).expressions()).hasSize(1).allMatch(e -> e.is(Tree.Kind.LINE_MAGIC));
228+
215229
}
216230

217231
@Test

0 commit comments

Comments
 (0)