From 1d95d1908dd5c704fd39414de99ea9a459b12994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20St=C3=B6neberg?= Date: Sat, 20 Aug 2022 12:14:55 +0200 Subject: [PATCH] refs #10663 - sped up `Library::detectContainerOrIterator()` by iterating the containers only once (#4380) --- Makefile | 2 +- lib/checkstl.cpp | 2 +- lib/checkunusedvar.cpp | 2 +- lib/library.cpp | 40 ++++++++++++++++++-------- lib/library.h | 6 +++- test/testlibrary.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 16 deletions(-) diff --git a/Makefile b/Makefile index 903439e4c..91a99c887 100644 --- a/Makefile +++ b/Makefile @@ -682,7 +682,7 @@ test/testio.o: test/testio.cpp lib/check.h lib/checkio.h lib/color.h lib/config. test/testleakautovar.o: test/testleakautovar.cpp externals/simplecpp/simplecpp.h externals/tinyxml2/tinyxml2.h lib/check.h lib/checkleakautovar.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testleakautovar.o test/testleakautovar.cpp -test/testlibrary.o: test/testlibrary.cpp externals/tinyxml2/tinyxml2.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h +test/testlibrary.o: test/testlibrary.cpp externals/tinyxml2/tinyxml2.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h test/testsuite.h test/testutils.h $(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o test/testlibrary.o test/testlibrary.cpp test/testmathlib.o: test/testmathlib.cpp lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/mathlib.h lib/suppressions.h test/testsuite.h diff --git a/lib/checkstl.cpp b/lib/checkstl.cpp index d54b71928..f9fc7271b 100644 --- a/lib/checkstl.cpp +++ b/lib/checkstl.cpp @@ -1421,7 +1421,7 @@ void CheckStl::stlBoundaries() if (!var || !var->scope() || !var->scope()->isExecutable()) continue; - const Library::Container* container = mSettings->library.detectContainer(var->typeStartToken(), true); + const Library::Container* container = mSettings->library.detectIterator(var->typeStartToken()); if (!container || container->opLessAllowed) continue; diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index 9321f76ed..7b6db527d 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -715,7 +715,7 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const else if (mTokenizer->isC() || i->typeEndToken()->isStandardType() || isRecordTypeWithoutSideEffects(i->type()) || - mSettings->library.detectContainer(i->typeStartToken(), /*iterator*/ false) || + mSettings->library.detectContainer(i->typeStartToken()) || i->isStlType()) type = Variables::standard; if (type == Variables::none || isPartOfClassStructUnion(i->typeStartToken())) diff --git a/lib/library.cpp b/lib/library.cpp index ba656b6ac..c22d76c3c 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -1133,7 +1133,7 @@ bool Library::isScopeNoReturn(const Token *end, std::string *unknownFunc) const return false; } -const Library::Container* Library::detectContainer(const Token* typeStart, bool iterator) const +const Library::Container* Library::detectContainerInternal(const Token* typeStart, DetectContainer detect, bool* isIterator) const { for (const std::pair & c : containers) { const Container& container = c.second; @@ -1143,14 +1143,25 @@ const Library::Container* Library::detectContainer(const Token* typeStart, bool if (!Token::Match(typeStart, container.startPattern2.c_str())) continue; - if (!iterator && container.endPattern.empty()) // If endPattern is undefined, it will always match, but itEndPattern has to be defined. + // If endPattern is undefined, it will always match, but itEndPattern has to be defined. + if (detect != IteratorOnly && container.endPattern.empty()) { + if (isIterator) + *isIterator = false; return &container; + } for (const Token* tok = typeStart; tok && !tok->varId(); tok = tok->next()) { if (tok->link()) { - const std::string& endPattern = iterator ? container.itEndPattern : container.endPattern; - if (Token::Match(tok->link(), endPattern.c_str())) + if (detect != ContainerOnly && Token::Match(tok->link(), container.itEndPattern.c_str())) { + if (isIterator) + *isIterator = true; return &container; + } + if (detect != IteratorOnly && Token::Match(tok->link(), container.endPattern.c_str())) { + if (isIterator) + *isIterator = false; + return &container; + } break; } } @@ -1158,17 +1169,22 @@ const Library::Container* Library::detectContainer(const Token* typeStart, bool return nullptr; } +const Library::Container* Library::detectContainer(const Token* typeStart) const +{ + return detectContainerInternal(typeStart, ContainerOnly); +} + +const Library::Container* Library::detectIterator(const Token* typeStart) const +{ + return detectContainerInternal(typeStart, IteratorOnly); +} + const Library::Container* Library::detectContainerOrIterator(const Token* typeStart, bool* isIterator) const { - const Library::Container* c = detectContainer(typeStart); - if (c) { - if (isIterator) - *isIterator = false; - return c; - } - c = detectContainer(typeStart, true); + bool res; + const Library::Container* c = detectContainerInternal(typeStart, Both, &res); if (c && isIterator) - *isIterator = true; + *isIterator = res; return c; } diff --git a/lib/library.h b/lib/library.h index 51e370394..9a5e87a58 100644 --- a/lib/library.h +++ b/lib/library.h @@ -283,7 +283,8 @@ public: static Action actionFrom(const std::string& actionName); }; std::map containers; - const Container* detectContainer(const Token* typeStart, bool iterator = false) const; + const Container* detectContainer(const Token* typeStart) const; + const Container* detectIterator(const Token* typeStart) const; const Container* detectContainerOrIterator(const Token* typeStart, bool* isIterator = nullptr) const; class ArgumentChecks { @@ -647,6 +648,9 @@ private: const std::map::const_iterator it = data.find(name); return (it == data.end()) ? nullptr : &it->second; } + + enum DetectContainer { ContainerOnly, IteratorOnly, Both }; + const Library::Container* detectContainerInternal(const Token* typeStart, DetectContainer detect, bool* isIterator = nullptr) const; }; CPPCHECKLIB const Library::Container * getLibraryContainer(const Token * tok); diff --git a/test/testlibrary.cpp b/test/testlibrary.cpp index 6b168ebbb..6d5ca08c5 100644 --- a/test/testlibrary.cpp +++ b/test/testlibrary.cpp @@ -21,6 +21,7 @@ #include "settings.h" #include "standards.h" #include "testsuite.h" +#include "testutils.h" #include "token.h" #include "tokenize.h" #include "tokenlist.h" @@ -865,6 +866,70 @@ private: ASSERT_EQUALS(C.size_templateArgNo, -1); ASSERT_EQUALS(C.stdStringLike, true); ASSERT_EQUALS(C.arrayLike_indexOp, true); + + { + givenACodeSampleToTokenize var("std::A a;"); + ASSERT_EQUALS(&A, library.detectContainer(var.tokens())); + ASSERT(!library.detectIterator(var.tokens())); + bool isIterator; + ASSERT_EQUALS(&A, library.detectContainerOrIterator(var.tokens(), &isIterator)); + ASSERT(!isIterator); + } + + { + givenACodeSampleToTokenize var("std::A::size_type a_s;"); + ASSERT(!library.detectContainer(var.tokens())); + ASSERT(!library.detectIterator(var.tokens())); + ASSERT(!library.detectContainerOrIterator(var.tokens())); + } + + { + givenACodeSampleToTokenize var("std::A::iterator a_it;"); + ASSERT(!library.detectContainer(var.tokens())); + ASSERT_EQUALS(&A, library.detectIterator(var.tokens())); + bool isIterator; + ASSERT_EQUALS(&A, library.detectContainerOrIterator(var.tokens(), &isIterator)); + ASSERT(isIterator); + } + + { + givenACodeSampleToTokenize var("std::B b;"); + ASSERT_EQUALS(&B, library.detectContainer(var.tokens())); + ASSERT(!library.detectIterator(var.tokens())); + bool isIterator; + ASSERT_EQUALS(&B, library.detectContainerOrIterator(var.tokens(), &isIterator)); + ASSERT(!isIterator); + } + + { + givenACodeSampleToTokenize var("std::B::size_type b_s;"); + ASSERT(!library.detectContainer(var.tokens())); + ASSERT(!library.detectIterator(var.tokens())); + ASSERT(!library.detectContainerOrIterator(var.tokens())); + } + + { + givenACodeSampleToTokenize var("std::B::iterator b_it;"); + ASSERT(!library.detectContainer(var.tokens())); + ASSERT_EQUALS(&B, library.detectIterator(var.tokens())); + bool isIterator; + ASSERT_EQUALS(&B, library.detectContainerOrIterator(var.tokens(), &isIterator)); + ASSERT(isIterator); + } + + { + givenACodeSampleToTokenize var("C c;"); + ASSERT(!library.detectContainer(var.tokens())); + ASSERT(!library.detectIterator(var.tokens())); + ASSERT(!library.detectContainerOrIterator(var.tokens())); + } + + { + givenACodeSampleToTokenize var("D d;"); + ASSERT(!library.detectContainer(var.tokens())); + ASSERT(!library.detectIterator(var.tokens())); + ASSERT(!library.detectContainerOrIterator(var.tokens())); + } } void version() const {