Skip to content

Commit

Permalink
Complete support of alternative operators
Browse files Browse the repository at this point in the history
* complete list of `overloadable-operator`s
  (yes, alternative operators can be used for operator overloading too)
* complete `equalityExpression`, `andExpression`, `exclusiveOrExpression`, `inclusiveOrExpression`, `logicalAndExpression`, `logicalOrExpression`

fixes SonarOpenCommunity#1569

* add missing support of alternative operators to the complexity metrics (see # SonarOpenCommunity#1494)
  • Loading branch information
ivangalkin committed Oct 25, 2018
1 parent bb69606 commit 6045ee1
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ private CxxComplexityConstants() {
CxxKeyword.DEFAULT,
CxxPunctuator.AND,
CxxPunctuator.OR,
CxxKeyword.AND,
CxxKeyword.OR,
CxxPunctuator.QUEST };

}
27 changes: 14 additions & 13 deletions cxx-squid/src/main/java/org/sonar/cxx/parser/CxxGrammarImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ public enum CxxGrammarImpl implements GrammarRuleKey {

// Overloading
operatorFunctionId,
operator,
overloadableOperator,
literalOperatorId,

// Templates
Expand Down Expand Up @@ -732,27 +732,27 @@ private static void expressions(LexerfulGrammarBuilder b) {
).skipIfOneChild();

b.rule(equalityExpression).is(
relationalExpression, b.zeroOrMore(b.firstOf("==", "!="), relationalExpression) // C++
relationalExpression, b.zeroOrMore(b.firstOf("==", "!=", CxxKeyword.NOT_EQ), relationalExpression) // C++
).skipIfOneChild();

b.rule(andExpression).is(
equalityExpression, b.zeroOrMore("&", equalityExpression) // C++
equalityExpression, b.zeroOrMore(b.firstOf("&", CxxKeyword.BITAND), equalityExpression) // C++
).skipIfOneChild();

b.rule(exclusiveOrExpression).is(
andExpression, b.zeroOrMore("^", andExpression) // C++
andExpression, b.zeroOrMore(b.firstOf("^", CxxKeyword.XOR), andExpression) // C++
).skipIfOneChild();

b.rule(inclusiveOrExpression).is(
exclusiveOrExpression, b.zeroOrMore("|", exclusiveOrExpression) // C++
exclusiveOrExpression, b.zeroOrMore(b.firstOf("|", CxxKeyword.BITOR), exclusiveOrExpression) // C++
).skipIfOneChild();

b.rule(logicalAndExpression).is(
inclusiveOrExpression, b.zeroOrMore("&&", inclusiveOrExpression) // C++
inclusiveOrExpression, b.zeroOrMore(b.firstOf("&&", CxxKeyword.AND), inclusiveOrExpression) // C++
).skipIfOneChild();

b.rule(logicalOrExpression).is(
logicalAndExpression, b.zeroOrMore("||", logicalAndExpression) // C++
logicalAndExpression, b.zeroOrMore(b.firstOf("||", CxxKeyword.OR), logicalAndExpression) // C++
).skipIfOneChild();

b.rule(conditionalExpression).is(
Expand Down Expand Up @@ -1743,21 +1743,22 @@ private static void specialMemberFunctions(LexerfulGrammarBuilder b) {
//
private static void overloading(LexerfulGrammarBuilder b) {
b.rule(operatorFunctionId).is(
CxxKeyword.OPERATOR, operator // C++ //todo wrong
CxxKeyword.OPERATOR, overloadableOperator // C++ //todo wrong
);

b.rule(operator).is( // C++ todo optimize new/delete?
b.rule(overloadableOperator).is( // C++ todo optimize new/delete?
b.firstOf(
b.sequence(CxxKeyword.NEW, "[", "]"),
b.sequence(CxxKeyword.DELETE, "[", "]"),
CxxKeyword.NEW, CxxKeyword.DELETE,
"+", "-", "*", "/", "%", "^", "&", "|", "~",
"!", "=", "<", ">", "+=", "-=", "*=", "/=", "%=",
"^=", "&=", "|=", "<<", ">>", ">>=", "<<=", "==", "!=",
"<=", ">=", "&&", "||", "++", "--", ",", "->*", "->",
"+", "-", "*", "/", "%", "^", CxxKeyword.XOR, "&", CxxKeyword.BITAND, "|", CxxKeyword.BITOR, "~",
CxxKeyword.COMPL, "!", CxxKeyword.NOT, "=", "<", ">", "+=", "-=", "*=", "/=", "%=", "^=", CxxKeyword.XOR_EQ,
"&=", CxxKeyword.AND_EQ, "|=", CxxKeyword.OR_EQ, "<<", ">>", ">>=", "<<=", "==", "!=", CxxKeyword.NOT_EQ,
"<=", ">=", "&&", CxxKeyword.AND, "||", CxxKeyword.OR, "++", "--", ",", "->*", "->",
b.sequence("(", ")"),
b.sequence("[", "]")
)
// c++ todo missing optional < template-argument-list > ?
);

b.rule(literalOperatorId).is(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ private static String getOperatorId(AstNode operatorFunctionId) {
StringBuilder builder = new StringBuilder(
operatorFunctionId.getTokenValue());
AstNode operator = operatorFunctionId
.getFirstDescendant(CxxGrammarImpl.operator);
.getFirstDescendant(CxxGrammarImpl.overloadableOperator);

if (operator != null) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,9 @@ private String getNodeDescripton() {
return "switch label";
} else if (nodeType == CxxKeyword.GOTO) {
return "goto statement";
} else if (nodeType == CxxPunctuator.AND || nodeType == CxxPunctuator.OR
|| nodeType == CxxGrammarImpl.logicalAndExpression || nodeType == CxxGrammarImpl.logicalOrExpression) {
} else if (nodeType == CxxPunctuator.AND || nodeType == CxxPunctuator.OR || nodeType == CxxKeyword.AND
|| nodeType == CxxKeyword.OR || nodeType == CxxGrammarImpl.logicalAndExpression
|| nodeType == CxxGrammarImpl.logicalOrExpression) {
return "logical operator";
} else if (nodeType == CxxPunctuator.QUEST) {
return "conditional operator";
Expand Down
7 changes: 7 additions & 0 deletions cxx-squid/src/test/java/org/sonar/cxx/CxxAstScannerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ public void complexity() throws UnsupportedEncodingException, IOException {
assertThat(file.getInt(CxxMetric.COMPLEXITY)).isEqualTo(14);
}

@Test
public void complexity_alternative() throws UnsupportedEncodingException, IOException {
CxxFileTester tester = CxxFileTesterHelper.CreateCxxFileTester("src/test/resources/metrics/complexity_alternative.cc", ".", "");
SourceFile file = CxxAstScanner.scanSingleFile(tester.cxxFile, tester.sensorContext, CxxFileTesterHelper.mockCxxLanguage());
assertThat(file.getInt(CxxMetric.COMPLEXITY)).isEqualTo(14);
}

@Test
public void complexity_macro() throws UnsupportedEncodingException, IOException {
CxxFileTester tester = CxxFileTesterHelper.CreateCxxFileTester("src/test/resources/metrics/complexity_macro.cc", ".", "");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ public void logicalOrExpression() {

assertThat(p).matches("logicalAndExpression");
assertThat(p).matches("logicalAndExpression || logicalAndExpression");
assertThat(p).matches("logicalAndExpression or logicalAndExpression");
}

@Test
Expand Down Expand Up @@ -455,6 +456,7 @@ public void logicalAndExpression() {

assertThat(p).matches("inclusiveOrExpression");
assertThat(p).matches("inclusiveOrExpression && inclusiveOrExpression");
assertThat(p).matches("inclusiveOrExpression and inclusiveOrExpression");
}

@Test
Expand All @@ -464,6 +466,7 @@ public void inclusiveOrExpression() {

assertThat(p).matches("exclusiveOrExpression");
assertThat(p).matches("exclusiveOrExpression | exclusiveOrExpression");
assertThat(p).matches("exclusiveOrExpression bitor exclusiveOrExpression");
}

@Test
Expand All @@ -473,6 +476,7 @@ public void exclusiveOrExpression() {

assertThat(p).matches("andExpression");
assertThat(p).matches("andExpression ^ andExpression");
assertThat(p).matches("andExpression xor andExpression");
}

@Test
Expand All @@ -482,6 +486,7 @@ public void andExpression() {

assertThat(p).matches("equalityExpression");
assertThat(p).matches("equalityExpression & equalityExpression");
assertThat(p).matches("equalityExpression bitand equalityExpression");
}

@Test
Expand All @@ -492,6 +497,7 @@ public void equalityExpression() {
assertThat(p).matches("relationalExpression");
assertThat(p).matches("relationalExpression == relationalExpression");
assertThat(p).matches("relationalExpression != relationalExpression");
assertThat(p).matches("relationalExpression not_eq relationalExpression");
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public void operatorFunctionId_reallife() {

@Test
public void operator() {
p.setRootRule(g.rule(CxxGrammarImpl.operator));
p.setRootRule(g.rule(CxxGrammarImpl.overloadableOperator));

assertThat(p).matches("new");
assertThat(p).matches("new[]");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ public void binary_logical_mixed() throws UnsupportedEncodingException, IOExcept
assertThat(testFile("src/test/resources/visitors/binary_logical_mixed.cc")).isEqualTo(4);
}

@Test
public void binary_logical_mixed_alternative() throws UnsupportedEncodingException, IOException {
assertThat(testFile("src/test/resources/visitors/binary_logical_mixed_alternative.cc")).isEqualTo(4);
}

@Test
public void binary_logical_not() throws UnsupportedEncodingException, IOException {
assertThat(testFile("src/test/resources/visitors/binary_logical_not.cc")).isEqualTo(3);
Expand Down
34 changes: 34 additions & 0 deletions cxx-squid/src/test/resources/metrics/complexity_alternative.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// same as complexity.cc but with alternative logical operators 'and' and 'or'
# include <iostream>
# include <exception>

using namespace std;

int main(){
if(true)
;

if(true and false)
;

if(true or false)
;

for(;;);

while(true);

try{
}
catch(std::exception e) {}
catch(...) {}

true ? 1 : 0;

int i = 3;
switch(i){
case 2: break;
case 3: break;
default: break;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// same as binary_logical_mixed.cc but with alternative logical operators 'and' and 'or'
bool logical_mixed(bool a, bool b, bool c, bool d, bool e, bool f)
{
if (a // +1 for `if`
and b and c // +1
or d or e // +1
and f) // +1
{
return true;
}
return false;
}

0 comments on commit 6045ee1

Please sign in to comment.