Skip to content

Commit

Permalink
fix parsing error with right angle bracket detection
Browse files Browse the repository at this point in the history
- close #2286

```C++
void check() {
    a() < 0 || c >= 1;
    a() < 0 || c > 1;
    a() < 0 || c >> 1;

    if(a() < 0 || c >= 1) {}
    if(a() < 0 || c > 1) {}
    if(a() < 0 || c >> 1) {}

    Y<X<(6<1)>>;
    Y<X<(6>=1)>>;
    Y<X<(6<=1)>>;
    Y<X<(6>>1)>>;
    Y<X<(6<<1)>>;
    Y<X<(6<=>1)>>;
}
```
  • Loading branch information
guwirth committed Jan 11, 2022
1 parent e265c12 commit 6f8edd1
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,29 +43,45 @@
*/
public class RightAngleBracketsChannel extends Channel<Lexer> {

private int angleBracketLevel = 0;
private int parentheseLevel = 0;
private int angleBracketLevel = 0; // angle brackets < >
private int parentheseLevel = 0; // parentheses / round brackets ( )

@Override
public boolean consume(CodeReader code, Lexer output) {
var ch = (char) code.peek();
var consumed = false;

if (ch == '<') {
if (parentheseLevel == 0) {
var next = code.charAt(1);
if ((next != '<') && (next != '=')) { // not <<, <=, <<=, <=>,
angleBracketLevel++;
switch (ch) {
case '(':
parentheseLevel++;
break;
case ')':
if (parentheseLevel > 0) {
parentheseLevel--;
}
}
} else if (angleBracketLevel > 0) {
switch (ch) {
case ';': // end of expression => reset
angleBracketLevel = 0;
parentheseLevel = 0;
break;
case '>':
if (parentheseLevel == 0) {
break;
case ';': // end of expression => reset
angleBracketLevel = 0;
parentheseLevel = 0;
break;

case '<':
if (parentheseLevel == 0) {
var next = code.charAt(1);
if ((next != '<') && (next != '=')) { // not <<, <=, <<=, <=>
angleBracketLevel++;
}
}
break;

case '>':
if (angleBracketLevel > 0) {
var consume = parentheseLevel == 0;
var next = code.charAt(1);
consume = consume && !(next == '='); // not >=
consume = consume && !((next == '>') && (angleBracketLevel == 1)); // not dangling >>

if (consume) {
output.addToken(Token.builder()
.setLine(code.getLinePosition())
.setColumn(code.getColumnPosition())
Expand All @@ -74,20 +90,12 @@ public boolean consume(CodeReader code, Lexer output) {
.setType(CxxPunctuator.GT)
.build());
code.pop();

angleBracketLevel--;
consumed = true;
}
angleBracketLevel = Math.max(0, angleBracketLevel - 1);
if (angleBracketLevel == 0) {
parentheseLevel = 0;
}
break;
case '(':
parentheseLevel++;
break;
case ')':
parentheseLevel = Math.max(0, parentheseLevel - 1);
break;
}
}
break;
}

return consumed;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -713,7 +713,7 @@ private static void expressions(LexerfulGrammarBuilder b) {
).skipIfOneChild();

b.rule(cudaKernel).is(
b.sequence("<<", "<", b.optional(expressionList), ">", ">>") // CUDA
b.sequence("<<", "<", b.optional(expressionList), ">>", ">") // CUDA
);

b.rule(typeIdEnclosed).is( // todo
Expand Down
22 changes: 22 additions & 0 deletions cxx-squid/src/test/java/org/sonar/cxx/parser/StatementTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,28 @@ public void statement_reallife() {
.matches("friend class SmartPtr<T>;");
}

@Test
public void expressionStatement_reallife() {
setRootRule(CxxGrammarImpl.expressionStatement);

assertThatParser()
// fix #2286: use expressionStatement with ; at the end to reset RightAngleBracketsChannel after each matches
.matches("a() < 0 || c >= 1;")
.matches("a() < 0 || c > 1;")
.matches("a() < 0 || c >> 1;");
}

@Test
public void selectionStatement_reallife() {
setRootRule(CxxGrammarImpl.selectionStatement);

assertThatParser()
// fix #2286
.matches("if(a() < 0 || c >= 1) {}")
.matches("if(a() < 0 || c > 1) {}")
.matches("if(a() < 0 || c >> 1) {}");
}

@Test
public void labeledStatement() {
setRootRule(CxxGrammarImpl.labeledStatement);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,13 @@ public void simpleTemplateId_reallife() {
.matches("A<(X>Y)>")
.matches("A<(X<Y)>")
.matches("vector<std::vector<bool>>")
.matches("Y<X<(6>>1)>>");
.matches("Y<X<(6>1)>>")
.matches("Y<X<(6<1)>>")
.matches("Y<X<(6>=1)>>")
.matches("Y<X<(6<=1)>>")
.matches("Y<X<(6>>1)>>")
.matches("Y<X<(6<<1)>>")
.matches("Y<X<(6<=>1)>>");
}

@Test
Expand Down

0 comments on commit 6f8edd1

Please sign in to comment.