diff --git a/Makefile b/Makefile index c01dc8df126..261f73feae0 100644 --- a/Makefile +++ b/Makefile @@ -221,6 +221,7 @@ LIBOBJ = $(libcppdir)/valueflow.o \ $(libcppdir)/ctu.o \ $(libcppdir)/errorlogger.o \ $(libcppdir)/errortypes.o \ + $(libcppdir)/findtoken.o \ $(libcppdir)/forwardanalyzer.o \ $(libcppdir)/fwdanalysis.o \ $(libcppdir)/importproject.o \ @@ -571,6 +572,9 @@ $(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml2/tinyxml2.h li $(libcppdir)/errortypes.o: lib/errortypes.cpp lib/config.h lib/errortypes.h lib/utils.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/errortypes.cpp +$(libcppdir)/findtoken.o: lib/findtoken.cpp lib/astutils.h lib/config.h lib/errortypes.h lib/findtoken.h lib/library.h lib/mathlib.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/utils.h lib/vfvalue.h + $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/findtoken.cpp + $(libcppdir)/forwardanalyzer.o: lib/forwardanalyzer.cpp lib/addoninfo.h lib/analyzer.h lib/astutils.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/forwardanalyzer.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/smallvector.h lib/sourcelocation.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenlist.h lib/utils.h lib/valueptr.h lib/vfvalue.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $(libcppdir)/forwardanalyzer.cpp diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 8175a977e79..ef3d83c89aa 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -3115,7 +3115,7 @@ namespace { template const Token* operator()(const Token* start, const Token* end, F f) const { - return findTokenSkipDeadCode(library, start, end, f, *evaluate); + return findTokenSkipDeadCode(library, start, end, std::move(f), *evaluate); } }; } diff --git a/lib/cppcheck.vcxproj b/lib/cppcheck.vcxproj index 6074eb664cb..b77deac42a4 100644 --- a/lib/cppcheck.vcxproj +++ b/lib/cppcheck.vcxproj @@ -66,6 +66,7 @@ + @@ -140,6 +141,7 @@ + diff --git a/lib/findtoken.cpp b/lib/findtoken.cpp new file mode 100644 index 00000000000..5e1be685190 --- /dev/null +++ b/lib/findtoken.cpp @@ -0,0 +1,143 @@ +/* + * 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 "findtoken.h" + +#include "astutils.h" +#include "token.h" + +template )> +static bool findTokensSkipDeadCodeImpl(const Library& library, + T* start, + const Token* end, + const std::function& pred, + const std::function& found, + const std::function(const Token*)>& evaluate, + bool skipUnevaluated) +{ + for (T* tok = start; precedes(tok, end); tok = tok->next()) { + if (pred(tok)) { + if (found(tok)) + return true; + } + if (Token::Match(tok, "if|for|while (") && Token::simpleMatch(tok->linkAt(1), ") {")) { + const Token* condTok = getCondTok(tok); + if (!condTok) + continue; + auto result = evaluate(condTok); + if (result.empty()) + continue; + if (internal::findTokensSkipDeadCodeImpl(library, tok->next(), tok->linkAt(1), pred, found, evaluate, skipUnevaluated)) + return true; + T* thenStart = tok->linkAt(1)->next(); + T* elseStart = nullptr; + if (Token::simpleMatch(thenStart->link(), "} else {")) + elseStart = thenStart->link()->tokAt(2); + + auto r = result.front(); + if (r == 0) { + if (elseStart) { + if (internal::findTokensSkipDeadCodeImpl(library, elseStart, elseStart->link(), pred, found, evaluate, skipUnevaluated)) + return true; + if (isReturnScope(elseStart->link(), library)) + return true; + tok = elseStart->link(); + } else { + tok = thenStart->link(); + } + } else { + if (internal::findTokensSkipDeadCodeImpl(library, thenStart, thenStart->link(), pred, found, evaluate, skipUnevaluated)) + return true; + if (isReturnScope(thenStart->link(), library)) + return true; + tok = thenStart->link(); + } + } else if (Token::Match(tok->astParent(), "&&|?|%oror%") && astIsLHS(tok)) { + auto result = evaluate(tok); + if (result.empty()) + continue; + const bool cond = result.front() != 0; + T* next = nullptr; + if ((cond && Token::simpleMatch(tok->astParent(), "||")) || + (!cond && Token::simpleMatch(tok->astParent(), "&&"))) { + next = nextAfterAstRightmostLeaf(tok->astParent()); + } else if (Token::simpleMatch(tok->astParent(), "?")) { + T* colon = tok->astParent()->astOperand2(); + if (!cond) { + next = colon; + } else { + if (internal::findTokensSkipDeadCodeImpl(library, tok->astParent()->next(), colon, pred, found, evaluate, skipUnevaluated)) + return true; + next = nextAfterAstRightmostLeaf(colon); + } + } + if (next) + tok = next; + } else if (Token::simpleMatch(tok, "} else {")) { + const Token* condTok = getCondTokFromEnd(tok); + if (!condTok) + continue; + auto result = evaluate(condTok); + if (result.empty()) + continue; + if (isReturnScope(tok->link(), library)) + return true; + auto r = result.front(); + if (r != 0) { + tok = tok->linkAt(2); + } + } else if (Token::simpleMatch(tok, "[") && Token::Match(tok->link(), "] (|{")) { + T* afterCapture = tok->link()->next(); + if (Token::simpleMatch(afterCapture, "(") && afterCapture->link()) + tok = afterCapture->link()->next(); + else + tok = afterCapture; + } + if (skipUnevaluated && isUnevaluated(tok)) { + T *next = tok->linkAt(1); + if (!next) + continue; + tok = next; + } + } + return false; +} + +namespace internal { + bool findTokensSkipDeadCodeImpl(const Library& library, + Token* start, + const Token* end, + const std::function& pred, + const std::function& found, + const std::function(const Token*)>& evaluate, + bool skipUnevaluated) + { + return ::findTokensSkipDeadCodeImpl(library, start, end, pred, found, evaluate, skipUnevaluated); + } + + bool findTokensSkipDeadCodeImpl(const Library& library, + const Token* start, + const Token* end, + const std::function& pred, + const std::function& found, + const std::function(const Token*)>& evaluate, + bool skipUnevaluated) + { + return ::findTokensSkipDeadCodeImpl(library, start, end, pred, found, evaluate, skipUnevaluated); + } +} diff --git a/lib/findtoken.h b/lib/findtoken.h index b82c4416293..1927fb484b4 100644 --- a/lib/findtoken.h +++ b/lib/findtoken.h @@ -74,105 +74,22 @@ T* findToken(T* start, const Token* end, const Predicate& pred) return result; } -template )> -bool findTokensSkipDeadCodeImpl(const Library& library, - T* start, - const Token* end, - const Predicate& pred, - Found found, - const Evaluate& evaluate, - bool skipUnevaluated) -{ - for (T* tok = start; precedes(tok, end); tok = tok->next()) { - if (pred(tok)) { - if (found(tok)) - return true; - } - if (Token::Match(tok, "if|for|while (") && Token::simpleMatch(tok->linkAt(1), ") {")) { - const Token* condTok = getCondTok(tok); - if (!condTok) - continue; - auto result = evaluate(condTok); - if (result.empty()) - continue; - if (findTokensSkipDeadCodeImpl(library, tok->next(), tok->linkAt(1), pred, found, evaluate, skipUnevaluated)) - return true; - T* thenStart = tok->linkAt(1)->next(); - T* elseStart = nullptr; - if (Token::simpleMatch(thenStart->link(), "} else {")) - elseStart = thenStart->link()->tokAt(2); - - auto r = result.front(); - if (r == 0) { - if (elseStart) { - if (findTokensSkipDeadCodeImpl(library, elseStart, elseStart->link(), pred, found, evaluate, skipUnevaluated)) - return true; - if (isReturnScope(elseStart->link(), library)) - return true; - tok = elseStart->link(); - } else { - tok = thenStart->link(); - } - } else { - if (findTokensSkipDeadCodeImpl(library, thenStart, thenStart->link(), pred, found, evaluate, skipUnevaluated)) - return true; - if (isReturnScope(thenStart->link(), library)) - return true; - tok = thenStart->link(); - } - } else if (Token::Match(tok->astParent(), "&&|?|%oror%") && astIsLHS(tok)) { - auto result = evaluate(tok); - if (result.empty()) - continue; - const bool cond = result.front() != 0; - T* next = nullptr; - if ((cond && Token::simpleMatch(tok->astParent(), "||")) || - (!cond && Token::simpleMatch(tok->astParent(), "&&"))) { - next = nextAfterAstRightmostLeaf(tok->astParent()); - } else if (Token::simpleMatch(tok->astParent(), "?")) { - T* colon = tok->astParent()->astOperand2(); - if (!cond) { - next = colon; - } else { - if (findTokensSkipDeadCodeImpl(library, tok->astParent()->next(), colon, pred, found, evaluate, skipUnevaluated)) - return true; - next = nextAfterAstRightmostLeaf(colon); - } - } - if (next) - tok = next; - } else if (Token::simpleMatch(tok, "} else {")) { - const Token* condTok = getCondTokFromEnd(tok); - if (!condTok) - continue; - auto result = evaluate(condTok); - if (result.empty()) - continue; - if (isReturnScope(tok->link(), library)) - return true; - auto r = result.front(); - if (r != 0) { - tok = tok->linkAt(2); - } - } else if (Token::simpleMatch(tok, "[") && Token::Match(tok->link(), "] (|{")) { - T* afterCapture = tok->link()->next(); - if (Token::simpleMatch(afterCapture, "(") && afterCapture->link()) - tok = afterCapture->link()->next(); - else - tok = afterCapture; - } - if (skipUnevaluated && isUnevaluated(tok)) { - T *next = tok->linkAt(1); - if (!next) - continue; - tok = next; - } - } - return false; +namespace internal { + bool findTokensSkipDeadCodeImpl(const Library &library, + Token *start, + const Token *end, + const std::function &pred, + const std::function& found, + const std::function(const Token *)> &evaluate, + bool skipUnevaluated); + + bool findTokensSkipDeadCodeImpl(const Library &library, + const Token *start, + const Token *end, + const std::function &pred, + const std::function& found, + const std::function(const Token *)> &evaluate, + bool skipUnevaluated); } template )> @@ -183,7 +100,7 @@ std::vector findTokensSkipDeadCode(const Library& library, const Evaluate& evaluate) { std::vector result; - (void)findTokensSkipDeadCodeImpl( + (void)internal::findTokensSkipDeadCodeImpl( library, start, end, @@ -211,7 +128,7 @@ std::vector findTokensSkipDeadAndUnevaluatedCode(const Library& library, const Evaluate& evaluate) { std::vector result; - (void)findTokensSkipDeadCodeImpl( + (void)internal::findTokensSkipDeadCodeImpl( library, start, end, @@ -236,7 +153,7 @@ template