diff --git a/Makefile b/Makefile index e03d4909e05..2bc08f1ead3 100644 --- a/Makefile +++ b/Makefile @@ -335,7 +335,8 @@ TESTOBJ = test/fixture.o \ test/testutils.o \ test/testvaarg.o \ test/testvalueflow.o \ - test/testvarid.o + test/testvarid.o \ + test/testvfvalue.o .PHONY: run-dmake tags @@ -900,6 +901,9 @@ test/testvalueflow.o: test/testvalueflow.cpp externals/simplecpp/simplecpp.h lib test/testvarid.o: test/testvarid.cpp externals/simplecpp/simplecpp.h lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvarid.cpp +test/testvfvalue.o: test/testvfvalue.cpp lib/addoninfo.h lib/check.h lib/checkers.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/utils.h lib/vfvalue.h test/fixture.h + $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testvfvalue.cpp + externals/simplecpp/simplecpp.o: externals/simplecpp/simplecpp.cpp externals/simplecpp/simplecpp.h $(CXX) $(CPPFLAGS) $(CXXFLAGS) -w -c -o $@ externals/simplecpp/simplecpp.cpp diff --git a/lib/token.cpp b/lib/token.cpp index 7c7d7a278a9..9243c01aa81 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -21,6 +21,7 @@ #include "astutils.h" #include "errortypes.h" #include "library.h" +#include "mathlib.h" #include "settings.h" #include "simplecpp.h" #include "symboldatabase.h" @@ -1801,7 +1802,7 @@ void Token::printValueFlow(bool xml, std::ostream &out) const break; case ValueFlow::Value::ValueType::FLOAT: outs += "floatvalue=\""; - outs += std::to_string(value.floatValue); // TODO: should this be MathLib::toString()? + outs += MathLib::toString(value.floatValue); outs += '\"'; break; case ValueFlow::Value::ValueType::MOVED: @@ -1875,7 +1876,6 @@ void Token::printValueFlow(bool xml, std::ostream &out) const outs += "/>\n"; } - else { if (&value != &values->front()) outs += ","; diff --git a/lib/vfvalue.cpp b/lib/vfvalue.cpp index 8e694c6eeb7..9dd1d423faa 100644 --- a/lib/vfvalue.cpp +++ b/lib/vfvalue.cpp @@ -19,6 +19,7 @@ #include "vfvalue.h" #include "errortypes.h" +#include "mathlib.h" #include "token.h" #include @@ -58,7 +59,7 @@ namespace ValueFlow { ss << this->tokvalue->str(); break; case ValueType::FLOAT: - ss << this->floatValue; + ss << MathLib::toString(this->floatValue); break; case ValueType::MOVED: ss << toString(this->moveKind); diff --git a/test/cli/other_test.py b/test/cli/other_test.py index 9b25b9fbb36..01c2adaaf4e 100644 --- a/test/cli/other_test.py +++ b/test/cli/other_test.py @@ -3064,4 +3064,102 @@ def test_file_ignore_2(tmp_path): # #13570 'cppcheck: error: could not find or open any of the paths given.', 'cppcheck: Maybe all paths were ignored?' ] - assert stderr.splitlines() == [] \ No newline at end of file + assert stderr.splitlines() == [] + + +def test_debug_valueflow(tmp_path): + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write( +"""int f() +{ + double d = 1.0 / 0.5; + return d; +} +""") + + args = [ + '-q', + '--debug', # TODO: limit to valueflow output + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0, stdout + + # check sections in output + assert stdout.find('##file ') != -1 + assert stdout.find('##Value flow') != -1 + assert stdout.find('### Symbol database ###') == -1 + assert stdout.find('##AST') == -1 + assert stdout.find('### Template Simplifier pass ') == -1 + assert stderr.splitlines() == [] + + # check precision in output - #13607 + valueflow = stdout[stdout.find('##Value flow'):] + assert valueflow.splitlines() == [ + '##Value flow', + 'File {}'.format(str(test_file).replace('\\', '/')), + 'Line 3', + ' = always 2.0', + ' 1.0 always 1.0', + ' / always 2.0', + ' 0.5 always 0.5', + 'Line 4', + ' d always {symbolic=(1.0/0.5),2.0}' + ] + + +def test_debug_valueflow_xml(tmp_path): # #13606 + test_file = tmp_path / 'test.c' + with open(test_file, "w") as f: + f.write( +"""double f() +{ + double d = 0.0000001; + return d; +} +""") + + args = [ + '-q', + '--debug', # TODO: limit to valueflow output + '--xml', + str(test_file) + ] + + exitcode, stdout, stderr = cppcheck(args) + assert exitcode == 0, stdout + + assert stderr + assert ElementTree.fromstring(stderr) is not None + + # check sections in output + assert stdout.find('##file ') != -1 # also exists in CDATA + assert stdout.find('##Value flow') == -1 + assert stdout.find('### Symbol database ###') == -1 + assert stdout.find('##AST') == -1 + assert stdout.find('### Template Simplifier pass ') == -1 + + # check XML nodes in output + debug_xml = ElementTree.fromstring(stdout) + assert debug_xml is not None + assert debug_xml.tag == 'debug' + file_elem = debug_xml.findall('file') + assert len(file_elem) == 1 + valueflow_elem = debug_xml.findall('valueflow') + assert len(valueflow_elem) == 1 + scopes_elem = debug_xml.findall('scopes') + assert len(scopes_elem) == 1 + ast_elem = debug_xml.findall('ast') + assert len(ast_elem) == 0 + + # check precision in output - #13606 + value_elem = valueflow_elem[0].findall('values/value') + assert len(value_elem) == 3 + assert 'floatvalue' in value_elem[0].attrib + assert value_elem[0].attrib['floatvalue'] == '1e-07' + assert 'floatvalue' in value_elem[1].attrib + assert value_elem[1].attrib['floatvalue'] == '1e-07' + assert 'floatvalue' in value_elem[2].attrib + assert value_elem[2].attrib['floatvalue'] == '1e-07' \ No newline at end of file diff --git a/test/testrunner.vcxproj b/test/testrunner.vcxproj index 02054bbbb2d..144a324163e 100755 --- a/test/testrunner.vcxproj +++ b/test/testrunner.vcxproj @@ -111,6 +111,7 @@ + diff --git a/test/testvfvalue.cpp b/test/testvfvalue.cpp new file mode 100644 index 00000000000..5326c476ec5 --- /dev/null +++ b/test/testvfvalue.cpp @@ -0,0 +1,48 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2024 Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "fixture.h" +#include "vfvalue.h" + +class TestValueFlowValue : public TestFixture { +public: + TestValueFlowValue() : TestFixture("TestValueFlowValue") {} + +private: + void run() override { + TEST_CASE(toString); + } + + void toString() const { + { + ValueFlow::Value v; + ASSERT_EQUALS("0", v.toString()); + v.intvalue = -1; + ASSERT_EQUALS("-1", v.toString()); + } + { + ValueFlow::Value v; + v.valueType = ValueFlow::Value::ValueType::FLOAT; + ASSERT_EQUALS("0.0", v.toString()); + v.floatValue = 0.0000000000001; + ASSERT_EQUALS("1e-13", v.toString()); + } + } +}; + +REGISTER_TEST(TestValueFlowValue)