diff --git a/cxx-squid/src/main/java/org/sonar/cxx/preprocessor/CxxPreprocessor.java b/cxx-squid/src/main/java/org/sonar/cxx/preprocessor/CxxPreprocessor.java index 6eb81a2622..b7a7c6a1b6 100644 --- a/cxx-squid/src/main/java/org/sonar/cxx/preprocessor/CxxPreprocessor.java +++ b/cxx-squid/src/main/java/org/sonar/cxx/preprocessor/CxxPreprocessor.java @@ -722,7 +722,7 @@ private List matchArgument(List tokens, List arguments) thr .setLine(firstToken.getLine()) .setColumn(firstToken.getColumn()) .setURI(firstToken.getURI()) - .setValueAndOriginalValue(serialize(matchedTokens)) + .setValueAndOriginalValue(serialize(matchedTokens).trim()) .setType(STRING) .build()); } @@ -757,46 +757,69 @@ private List replaceParams(List body, List parameters, List defParamValues.add(t.getValue()); } + boolean tokenPastingLeftOp = false; + boolean tokenPastingRightOp = false; + for (int i = 0; i < body.size(); ++i) { Token curr = body.get(i); int index = defParamValues.indexOf(curr.getValue()); if (index == -1) { newTokens.add(curr); - } - else if (index == arguments.size()) { + } else if (index == arguments.size()) { // EXTENSION: GCC's special meaning of token paste operator // If variable argument is left out then the comma before the paste operator will be deleted int j = i; - while(j > 0 && body.get(j - 1).getType() == WS) + while (j > 0 && body.get(j - 1).getType() == WS) { j--; - if (j == 0 || !"##".equals(body.get(--j).getValue())) + } + if (j == 0 || !"##".equals(body.get(--j).getValue())) { continue; + } int k = j; - while(j > 0 && body.get(j - 1).getType() == WS) + while (j > 0 && body.get(j - 1).getType() == WS) { j--; + } if (j > 0 && ",".equals(body.get(j - 1).getValue())) { newTokens.remove(newTokens.size() - 1 + j - i); //remove the comma newTokens.remove(newTokens.size() - 1 + k - i); //remove the paste operator } - } - else if (index < arguments.size()) { + } else if (index < arguments.size()) { + // token pasting operator? + int j = i + 1; + while (j < body.size() && body.get(j).getType() == WS) { + j++; + } + if (j < body.size() && "##".equals(body.get(j).getValue())) { + tokenPastingLeftOp = true; + } + // in case of token pasting operator do not fully expand Token replacement = arguments.get(index); - - // The arguments have to be fully expanded before expanding the body of the macro - String newValue = serialize(expandMacro("", replacement.getValue())); - - if (i > 0 && "#".equals(body.get(i - 1).getValue())) { - newTokens.remove(newTokens.size() - 1); - newValue = encloseWithQuotes(quote(newValue)); + String newValue; + if (tokenPastingLeftOp) { + newValue = replacement.getValue(); + tokenPastingLeftOp = false; + tokenPastingRightOp = true; + } else if (tokenPastingRightOp) { + newValue = replacement.getValue(); + tokenPastingLeftOp = false; + tokenPastingRightOp = false; + } else { + // otherwise the arguments have to be fully expanded before expanding the body of the macro + newValue = serialize(expandMacro("", replacement.getValue())); + if (i > 0 && "#".equals(body.get(i - 1).getValue())) { + newTokens.remove(newTokens.size() - 1); + newValue = encloseWithQuotes(quote(newValue)); + } } + newTokens.add(Token.builder() - .setLine(replacement.getLine()) - .setColumn(replacement.getColumn()) - .setURI(replacement.getURI()) - .setValueAndOriginalValue(newValue) - .setType(replacement.getType()) - .setGeneratedCode(true) - .build()); + .setLine(replacement.getLine()) + .setColumn(replacement.getColumn()) + .setURI(replacement.getURI()) + .setValueAndOriginalValue(newValue) + .setType(replacement.getType()) + .setGeneratedCode(true) + .build()); } } } diff --git a/cxx-squid/src/test/java/org/sonar/cxx/parser/PreprocessorDirectivesTest.java b/cxx-squid/src/test/java/org/sonar/cxx/parser/PreprocessorDirectivesTest.java index 98ad177f6c..eb96d4d535 100644 --- a/cxx-squid/src/test/java/org/sonar/cxx/parser/PreprocessorDirectivesTest.java +++ b/cxx-squid/src/test/java/org/sonar/cxx/parser/PreprocessorDirectivesTest.java @@ -147,24 +147,24 @@ public void complex_macro_rescanning() { + "lang_init(c)();")) .equals("c = c_init ( ) ; EOF")); - - // This one doesnt work. - // The preprocessor seems to resule resolves macro in the wrong order: - // BOOST_MSVC => _MSC_VER => 1600 ## _WORKAROUND_GUARD => 1600 _WORKAROUND_GUARD - // - // instead of - // - // BOOST_MSVC => _MSC_VER - // _MSC_VER ## _WORKAROUND_GUARD => _MSC_VER_WORKAROUND_GUARD - // _MSC_VER_WORKAROUND_GUARD => 0 - - // assert (serialize(p.parse( - // "#define _MSC_VER_WORKAROUND_GUARD 0\n" - // + "#define _MSC_VER 1600\n" - // + "#define BOOST_MSVC _MSC_VER\n" - // + "#define TEST(symbol) symbol ## _WORKAROUND_GUARD\n" - // + "TEST(BOOST_MSVC);")) - // .equals("0 ; EOF")); + assert (serialize(p.parse( + "#define _MSC_VER_WORKAROUND_GUARD 1\n" + + "#define BOOST_MSVC_WORKAROUND_GUARD 0\n" + + "#define _MSC_VER 1600\n" + + "#define BOOST_MSVC _MSC_VER\n" + + "#define TEST(symbol) symbol ## _WORKAROUND_GUARD\n" + + "int i=TEST(BOOST_MSVC);")) + .equals("int i = 0 ; EOF")); + + assert (serialize(p.parse( + "#define _MSC_VER_WORKAROUND_GUARD 1\n" + + "#define BOOST_MSVC_WORKAROUND_GUARD 0\n" + + "#define _MSC_VER 1600\n" + + "#define BOOST_MSVC _MSC_VER\n" + + "#define _WORKAROUND_GUARD _XXX\n" + + "#define TEST(symbol1, symbol2) symbol1 ## symbol2\n" + + "int i=TEST(BOOST_MSVC, _WORKAROUND_GUARD);")) + .equals("int i = 0 ; EOF")); } @Test diff --git a/integration-tests/features/test_execution_statistics.feature b/integration-tests/features/test_execution_statistics.feature index c14dc3c535..454dcd65d6 100644 --- a/integration-tests/features/test_execution_statistics.feature +++ b/integration-tests/features/test_execution_statistics.feature @@ -331,7 +331,6 @@ Feature: Providing test execution numbers AND the analysis log contains no error/warning messages except those matching: """ .*WARN.*cannot find the sources for '.*' - .*WARN.*Error evaluating expression.*, assuming 0 """ AND the following metrics have following values: | metric | value |