Add backtrace to valueflow in debug mode (#4195)
This commit is contained in:
parent
187460a277
commit
cee48e5e19
|
@ -54,7 +54,7 @@ jobs:
|
||||||
- name: Self check (unusedFunction)
|
- name: Self check (unusedFunction)
|
||||||
if: false # TODO: fails with preprocessorErrorDirective - see #10667
|
if: false # TODO: fails with preprocessorErrorDirective - see #10667
|
||||||
run: |
|
run: |
|
||||||
./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__GNUC__ -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 --inconclusive --enable=unusedFunction --exception-handling -rp=. --project=cmake.output/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr
|
./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 --inconclusive --enable=unusedFunction --exception-handling -rp=. --project=cmake.output/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr
|
||||||
env:
|
env:
|
||||||
DISABLE_VALUEFLOW: 1
|
DISABLE_VALUEFLOW: 1
|
||||||
|
|
||||||
|
@ -76,6 +76,6 @@ jobs:
|
||||||
# TODO: find a way to report unmatched suppressions without need to add information checks
|
# TODO: find a way to report unmatched suppressions without need to add information checks
|
||||||
- name: Self check (unusedFunction / no test)
|
- name: Self check (unusedFunction / no test)
|
||||||
run: |
|
run: |
|
||||||
./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__GNUC__ -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 --inconclusive --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.notest/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr
|
./cppcheck -q --template=selfcheck --error-exitcode=1 --library=cppcheck-lib --library=qt -D__CPPCHECK__ -D__GNUC__ -DQT_VERSION=0x050000 -DQ_MOC_OUTPUT_REVISION=67 --inconclusive --enable=unusedFunction --exception-handling -rp=. --project=cmake.output.notest/compile_commands.json --suppressions-list=.selfcheck_unused_suppressions --inline-suppr
|
||||||
env:
|
env:
|
||||||
DISABLE_VALUEFLOW: 1
|
DISABLE_VALUEFLOW: 1
|
||||||
|
|
2
Makefile
2
Makefile
|
@ -561,7 +561,7 @@ $(libcppdir)/tokenlist.o: lib/tokenlist.cpp externals/simplecpp/simplecpp.h lib/
|
||||||
$(libcppdir)/utils.o: lib/utils.cpp lib/config.h lib/utils.h
|
$(libcppdir)/utils.o: lib/utils.cpp lib/config.h lib/utils.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/utils.o $(libcppdir)/utils.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/utils.o $(libcppdir)/utils.cpp
|
||||||
|
|
||||||
$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h
|
$(libcppdir)/valueflow.o: lib/valueflow.cpp lib/analyzer.h lib/astutils.h lib/calculate.h lib/check.h lib/checkuninitvar.h lib/color.h lib/config.h lib/ctu.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/importproject.h lib/infer.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/programmemory.h lib/reverseanalyzer.h lib/settings.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/valueptr.h
|
||||||
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/valueflow.o $(libcppdir)/valueflow.cpp
|
$(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/valueflow.o $(libcppdir)/valueflow.cpp
|
||||||
|
|
||||||
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
|
cli/cmdlineparser.o: cli/cmdlineparser.cpp cli/cmdlineparser.h cli/cppcheckexecutor.h cli/filelister.h externals/tinyxml2/tinyxml2.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/timer.h lib/utils.h
|
||||||
|
|
|
@ -6,7 +6,7 @@ macro(use_cxx11)
|
||||||
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||||
endif ()
|
endif ()
|
||||||
else ()
|
else ()
|
||||||
set (CMAKE_CXX_STANDARD 11)
|
set (CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to use")
|
||||||
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
set (CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
if (POLICY CMP0025)
|
if (POLICY CMP0025)
|
||||||
cmake_policy(SET CMP0025 NEW)
|
cmake_policy(SET CMP0025 NEW)
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Cppcheck - A tool for static C/C++ code analysis
|
||||||
|
* Copyright (C) 2007-2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef sourcelocationH
|
||||||
|
#define sourcelocationH
|
||||||
|
|
||||||
|
#ifdef __CPPCHECK__
|
||||||
|
#define CPPCHECK_HAS_SOURCE_LOCATION 0
|
||||||
|
#define CPPCHECK_HAS_SOURCE_LOCATION_TS 0
|
||||||
|
#elif defined(__has_include)
|
||||||
|
#if __has_include(<source_location>) && __cplusplus >= 202003L
|
||||||
|
#define CPPCHECK_HAS_SOURCE_LOCATION 1
|
||||||
|
#else
|
||||||
|
#define CPPCHECK_HAS_SOURCE_LOCATION 0
|
||||||
|
#endif
|
||||||
|
#if __has_include(<experimental/source_location>) && __cplusplus >= 201402L
|
||||||
|
#define CPPCHECK_HAS_SOURCE_LOCATION_TS 1
|
||||||
|
#else
|
||||||
|
#define CPPCHECK_HAS_SOURCE_LOCATION_TS 0
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define CPPCHECK_HAS_SOURCE_LOCATION 0
|
||||||
|
#define CPPCHECK_HAS_SOURCE_LOCATION_TS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CPPCHECK_HAS_SOURCE_LOCATION
|
||||||
|
#include <source_location>
|
||||||
|
using SourceLocation = std::source_location;
|
||||||
|
#elif CPPCHECK_HAS_SOURCE_LOCATION_TS
|
||||||
|
#include <experimental/source_location>
|
||||||
|
using SourceLocation = std::experimental::source_location;
|
||||||
|
#else
|
||||||
|
struct SourceLocation {
|
||||||
|
static SourceLocation current() {
|
||||||
|
return SourceLocation();
|
||||||
|
}
|
||||||
|
std::uint_least32_t m_line = 0;
|
||||||
|
std::uint_least32_t m_column = 0;
|
||||||
|
const char* m_file_name = "";
|
||||||
|
const char* m_function_name = "";
|
||||||
|
std::uint_least32_t line() const {
|
||||||
|
return m_line;
|
||||||
|
}
|
||||||
|
std::uint_least32_t column() const {
|
||||||
|
return m_column;
|
||||||
|
}
|
||||||
|
const char* file_name() const {
|
||||||
|
return m_file_name;
|
||||||
|
}
|
||||||
|
const char* function_name() const {
|
||||||
|
return m_function_name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -93,6 +93,7 @@
|
||||||
#include "programmemory.h"
|
#include "programmemory.h"
|
||||||
#include "reverseanalyzer.h"
|
#include "reverseanalyzer.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
#include "sourcelocation.h"
|
||||||
#include "standards.h"
|
#include "standards.h"
|
||||||
#include "symboldatabase.h"
|
#include "symboldatabase.h"
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
|
@ -137,6 +138,38 @@ static void bailoutInternal(const std::string& type, TokenList *tokenlist, Error
|
||||||
|
|
||||||
#define bailoutIncompleteVar(tokenlist, errorLogger, tok, what) bailout2("valueFlowBailoutIncompleteVar", tokenlist, errorLogger, tok, what)
|
#define bailoutIncompleteVar(tokenlist, errorLogger, tok, what) bailout2("valueFlowBailoutIncompleteVar", tokenlist, errorLogger, tok, what)
|
||||||
|
|
||||||
|
static std::string debugString(const ValueFlow::Value& v)
|
||||||
|
{
|
||||||
|
std::string kind;
|
||||||
|
switch (v.valueKind) {
|
||||||
|
|
||||||
|
case ValueFlow::Value::ValueKind::Impossible:
|
||||||
|
case ValueFlow::Value::ValueKind::Known:
|
||||||
|
kind = "always";
|
||||||
|
break;
|
||||||
|
case ValueFlow::Value::ValueKind::Inconclusive:
|
||||||
|
kind = "inconclusive";
|
||||||
|
break;
|
||||||
|
case ValueFlow::Value::ValueKind::Possible:
|
||||||
|
kind = "possible";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return kind + " " + v.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setSourceLocation(ValueFlow::Value& v,
|
||||||
|
SourceLocation ctx,
|
||||||
|
const Token* tok,
|
||||||
|
SourceLocation local = SourceLocation::current())
|
||||||
|
{
|
||||||
|
std::string file = ctx.file_name();
|
||||||
|
if (file.empty())
|
||||||
|
return;
|
||||||
|
std::string s = Path::stripDirectoryPart(file) + ":" + MathLib::toString(ctx.line()) + ": " + ctx.function_name() +
|
||||||
|
" => " + local.function_name() + ": " + debugString(v);
|
||||||
|
v.debugPath.emplace_back(tok, s);
|
||||||
|
}
|
||||||
|
|
||||||
static void changeKnownToPossible(std::list<ValueFlow::Value> &values, int indirect=-1)
|
static void changeKnownToPossible(std::list<ValueFlow::Value> &values, int indirect=-1)
|
||||||
{
|
{
|
||||||
for (ValueFlow::Value& v: values) {
|
for (ValueFlow::Value& v: values) {
|
||||||
|
@ -619,7 +652,10 @@ static ValueFlow::Value truncateImplicitConversion(Token* parent, const ValueFlo
|
||||||
}
|
}
|
||||||
|
|
||||||
/** set ValueFlow value and perform calculations if possible */
|
/** set ValueFlow value and perform calculations if possible */
|
||||||
static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* settings)
|
static void setTokenValue(Token* tok,
|
||||||
|
ValueFlow::Value value,
|
||||||
|
const Settings* settings,
|
||||||
|
SourceLocation loc = SourceLocation::current())
|
||||||
{
|
{
|
||||||
// Skip setting values that are too big since its ambiguous
|
// Skip setting values that are too big since its ambiguous
|
||||||
if (!value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) &&
|
if (!value.isImpossible() && value.isIntValue() && value.intvalue < 0 && astIsUnsigned(tok) &&
|
||||||
|
@ -629,6 +665,9 @@ static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* se
|
||||||
if (!value.isImpossible() && value.isIntValue())
|
if (!value.isImpossible() && value.isIntValue())
|
||||||
value = truncateImplicitConversion(tok->astParent(), value, settings);
|
value = truncateImplicitConversion(tok->astParent(), value, settings);
|
||||||
|
|
||||||
|
if (settings->debugnormal)
|
||||||
|
setSourceLocation(value, loc, tok);
|
||||||
|
|
||||||
if (!tok->addValue(value))
|
if (!tok->addValue(value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1907,43 +1946,58 @@ ValuePtr<Analyzer> makeReverseAnalyzer(const Token* exprTok, const ValueFlow::Va
|
||||||
static Analyzer::Result valueFlowForward(Token* startToken,
|
static Analyzer::Result valueFlowForward(Token* startToken,
|
||||||
const Token* endToken,
|
const Token* endToken,
|
||||||
const Token* exprTok,
|
const Token* exprTok,
|
||||||
const ValueFlow::Value& value,
|
ValueFlow::Value value,
|
||||||
TokenList* const tokenlist)
|
TokenList* const tokenlist,
|
||||||
|
SourceLocation loc = SourceLocation::current())
|
||||||
{
|
{
|
||||||
return valueFlowGenericForward(startToken, endToken, makeAnalyzer(exprTok, value, tokenlist), tokenlist->getSettings());
|
if (tokenlist->getSettings()->debugnormal)
|
||||||
|
setSourceLocation(value, loc, startToken);
|
||||||
|
return valueFlowGenericForward(startToken,
|
||||||
|
endToken,
|
||||||
|
makeAnalyzer(exprTok, std::move(value), tokenlist),
|
||||||
|
tokenlist->getSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
static Analyzer::Result valueFlowForward(Token* startToken,
|
static Analyzer::Result valueFlowForward(Token* startToken,
|
||||||
const Token* endToken,
|
const Token* endToken,
|
||||||
const Token* exprTok,
|
const Token* exprTok,
|
||||||
const std::list<ValueFlow::Value>& values,
|
std::list<ValueFlow::Value> values,
|
||||||
TokenList* const tokenlist)
|
TokenList* const tokenlist,
|
||||||
|
SourceLocation loc = SourceLocation::current())
|
||||||
{
|
{
|
||||||
Analyzer::Result result{};
|
Analyzer::Result result{};
|
||||||
for (const ValueFlow::Value& v : values) {
|
for (ValueFlow::Value& v : values) {
|
||||||
result.update(valueFlowForward(startToken, endToken, exprTok, v, tokenlist));
|
result.update(valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, loc));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ValueOrValues>
|
template<class ValueOrValues>
|
||||||
static Analyzer::Result valueFlowForward(Token* startToken, const Token* exprTok, const ValueOrValues& v, TokenList* tokenlist)
|
static Analyzer::Result valueFlowForward(Token* startToken,
|
||||||
|
const Token* exprTok,
|
||||||
|
ValueOrValues v,
|
||||||
|
TokenList* tokenlist,
|
||||||
|
SourceLocation loc = SourceLocation::current())
|
||||||
{
|
{
|
||||||
const Token* endToken = nullptr;
|
const Token* endToken = nullptr;
|
||||||
const Function* f = Scope::nestedInFunction(startToken->scope());
|
const Function* f = Scope::nestedInFunction(startToken->scope());
|
||||||
if (f && f->functionScope)
|
if (f && f->functionScope)
|
||||||
endToken = f->functionScope->bodyEnd;
|
endToken = f->functionScope->bodyEnd;
|
||||||
return valueFlowForward(startToken, endToken, exprTok, v, tokenlist);
|
return valueFlowForward(startToken, endToken, exprTok, std::move(v), tokenlist, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Analyzer::Result valueFlowForwardRecursive(Token* top,
|
static Analyzer::Result valueFlowForwardRecursive(Token* top,
|
||||||
const Token* exprTok,
|
const Token* exprTok,
|
||||||
const std::list<ValueFlow::Value>& values,
|
std::list<ValueFlow::Value> values,
|
||||||
TokenList* const tokenlist)
|
TokenList* const tokenlist,
|
||||||
|
SourceLocation loc = SourceLocation::current())
|
||||||
{
|
{
|
||||||
Analyzer::Result result{};
|
Analyzer::Result result{};
|
||||||
for (const ValueFlow::Value& v : values) {
|
for (ValueFlow::Value& v : values) {
|
||||||
result.update(valueFlowGenericForward(top, makeAnalyzer(exprTok, v, tokenlist), tokenlist->getSettings()));
|
if (tokenlist->getSettings()->debugnormal)
|
||||||
|
setSourceLocation(v, loc, top);
|
||||||
|
result.update(
|
||||||
|
valueFlowGenericForward(top, makeAnalyzer(exprTok, std::move(v), tokenlist), tokenlist->getSettings()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1951,10 +2005,13 @@ static Analyzer::Result valueFlowForwardRecursive(Token* top,
|
||||||
static void valueFlowReverse(Token* tok,
|
static void valueFlowReverse(Token* tok,
|
||||||
const Token* const endToken,
|
const Token* const endToken,
|
||||||
const Token* const varToken,
|
const Token* const varToken,
|
||||||
const std::list<ValueFlow::Value>& values,
|
std::list<ValueFlow::Value> values,
|
||||||
TokenList* tokenlist)
|
TokenList* tokenlist,
|
||||||
|
SourceLocation loc = SourceLocation::current())
|
||||||
{
|
{
|
||||||
for (const ValueFlow::Value& v : values) {
|
for (ValueFlow::Value& v : values) {
|
||||||
|
if (tokenlist->getSettings()->debugnormal)
|
||||||
|
setSourceLocation(v, loc, tok);
|
||||||
valueFlowGenericReverse(tok, endToken, makeReverseAnalyzer(varToken, v, tokenlist), tokenlist->getSettings());
|
valueFlowGenericReverse(tok, endToken, makeReverseAnalyzer(varToken, v, tokenlist), tokenlist->getSettings());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1966,12 +2023,13 @@ static void valueFlowReverse(TokenList* tokenlist,
|
||||||
ValueFlow::Value val,
|
ValueFlow::Value val,
|
||||||
const ValueFlow::Value& val2,
|
const ValueFlow::Value& val2,
|
||||||
ErrorLogger* /*errorLogger*/,
|
ErrorLogger* /*errorLogger*/,
|
||||||
const Settings* = nullptr)
|
const Settings* = nullptr,
|
||||||
|
SourceLocation loc = SourceLocation::current())
|
||||||
{
|
{
|
||||||
std::list<ValueFlow::Value> values = {val};
|
std::list<ValueFlow::Value> values = {val};
|
||||||
if (val2.varId != 0)
|
if (val2.varId != 0)
|
||||||
values.push_back(val2);
|
values.push_back(val2);
|
||||||
valueFlowReverse(tok, nullptr, varToken, values, tokenlist);
|
valueFlowReverse(tok, nullptr, varToken, values, tokenlist, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isConditionKnown(const Token* tok, bool then)
|
static bool isConditionKnown(const Token* tok, bool then)
|
||||||
|
@ -4740,7 +4798,11 @@ static const Token* findIncompleteVar(const Token* start, const Token* end)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ValueFlow::Value makeConditionValue(long long val, const Token* condTok, bool assume)
|
static ValueFlow::Value makeConditionValue(long long val,
|
||||||
|
const Token* condTok,
|
||||||
|
bool assume,
|
||||||
|
const Settings* settings = nullptr,
|
||||||
|
SourceLocation loc = SourceLocation::current())
|
||||||
{
|
{
|
||||||
ValueFlow::Value v(val);
|
ValueFlow::Value v(val);
|
||||||
v.setKnown();
|
v.setKnown();
|
||||||
|
@ -4749,6 +4811,8 @@ static ValueFlow::Value makeConditionValue(long long val, const Token* condTok,
|
||||||
v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is true");
|
v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is true");
|
||||||
else
|
else
|
||||||
v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is false");
|
v.errorPath.emplace_back(condTok, "Assuming condition '" + condTok->expressionString() + "' is false");
|
||||||
|
if (settings && settings->debugnormal)
|
||||||
|
setSourceLocation(v, loc, condTok);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5559,26 +5623,29 @@ struct ConditionHandler {
|
||||||
const Token* stop,
|
const Token* stop,
|
||||||
const Token* exprTok,
|
const Token* exprTok,
|
||||||
const std::list<ValueFlow::Value>& values,
|
const std::list<ValueFlow::Value>& values,
|
||||||
TokenList* tokenlist) const
|
TokenList* tokenlist,
|
||||||
|
SourceLocation loc = SourceLocation::current()) const
|
||||||
{
|
{
|
||||||
return valueFlowForward(start->next(), stop, exprTok, values, tokenlist);
|
return valueFlowForward(start->next(), stop, exprTok, values, tokenlist, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual Analyzer::Result forward(Token* top,
|
virtual Analyzer::Result forward(Token* top,
|
||||||
const Token* exprTok,
|
const Token* exprTok,
|
||||||
const std::list<ValueFlow::Value>& values,
|
const std::list<ValueFlow::Value>& values,
|
||||||
TokenList* tokenlist) const
|
TokenList* tokenlist,
|
||||||
|
SourceLocation loc = SourceLocation::current()) const
|
||||||
{
|
{
|
||||||
return valueFlowForwardRecursive(top, exprTok, values, tokenlist);
|
return valueFlowForwardRecursive(top, exprTok, values, tokenlist, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void reverse(Token* start,
|
virtual void reverse(Token* start,
|
||||||
const Token* endToken,
|
const Token* endToken,
|
||||||
const Token* exprTok,
|
const Token* exprTok,
|
||||||
const std::list<ValueFlow::Value>& values,
|
const std::list<ValueFlow::Value>& values,
|
||||||
TokenList* tokenlist) const
|
TokenList* tokenlist,
|
||||||
|
SourceLocation loc = SourceLocation::current()) const
|
||||||
{
|
{
|
||||||
return valueFlowReverse(start, endToken, exprTok, values, tokenlist);
|
return valueFlowReverse(start, endToken, exprTok, values, tokenlist, loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void traverseCondition(TokenList* tokenlist,
|
void traverseCondition(TokenList* tokenlist,
|
||||||
|
@ -8353,23 +8420,12 @@ static void valueFlowDebug(TokenList* tokenlist, ErrorLogger* errorLogger)
|
||||||
for (Token* tok = tokenlist->front(); tok; tok = tok->next()) {
|
for (Token* tok = tokenlist->front(); tok; tok = tok->next()) {
|
||||||
if (tok->getTokenDebug() != TokenDebug::ValueFlow)
|
if (tok->getTokenDebug() != TokenDebug::ValueFlow)
|
||||||
continue;
|
continue;
|
||||||
|
if (tok->astParent() && tok->astParent()->getTokenDebug() == TokenDebug::ValueFlow)
|
||||||
|
continue;
|
||||||
for (const ValueFlow::Value& v : tok->values()) {
|
for (const ValueFlow::Value& v : tok->values()) {
|
||||||
std::string kind;
|
std::string msg = "The value is " + debugString(v);
|
||||||
switch (v.valueKind) {
|
|
||||||
|
|
||||||
case ValueFlow::Value::ValueKind::Impossible:
|
|
||||||
case ValueFlow::Value::ValueKind::Known:
|
|
||||||
kind = "always";
|
|
||||||
break;
|
|
||||||
case ValueFlow::Value::ValueKind::Inconclusive:
|
|
||||||
kind = "inconclusive";
|
|
||||||
break;
|
|
||||||
case ValueFlow::Value::ValueKind::Possible:
|
|
||||||
kind = "possible";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
std::string msg = "The value is " + kind + " " + v.toString();
|
|
||||||
ErrorPath errorPath = v.errorPath;
|
ErrorPath errorPath = v.errorPath;
|
||||||
|
errorPath.insert(errorPath.end(), v.debugPath.begin(), v.debugPath.end());
|
||||||
errorPath.emplace_back(tok, "");
|
errorPath.emplace_back(tok, "");
|
||||||
errorLogger->reportErr({errorPath, tokenlist, Severity::debug, "valueFlow", msg, CWE{0}, Certainty::normal});
|
errorLogger->reportErr({errorPath, tokenlist, Severity::debug, "valueFlow", msg, CWE{0}, Certainty::normal});
|
||||||
}
|
}
|
||||||
|
|
|
@ -342,6 +342,8 @@ namespace ValueFlow {
|
||||||
|
|
||||||
ErrorPath errorPath;
|
ErrorPath errorPath;
|
||||||
|
|
||||||
|
ErrorPath debugPath;
|
||||||
|
|
||||||
/** For calculated values - varId that calculated value depends on */
|
/** For calculated values - varId that calculated value depends on */
|
||||||
nonneg int varId;
|
nonneg int varId;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue