Merge pull request #5129 from chrchr-github/chr_action_yield2

Detect container action and yield functions (2)
This commit is contained in:
chrchr-github 2023-06-16 22:47:19 +02:00 committed by GitHub
commit e31cd05ae9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 33 deletions

View File

@ -498,6 +498,11 @@
<ref name="CONTAINER-YIELDS"/>
</attribute>
</optional>
<optional>
<attribute name="returnType">
<data type="string"/>
</attribute>
</optional>
<empty/>
</element>
</zeroOrMore>

View File

@ -6600,15 +6600,6 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<not-uninit/>
</arg>
</function>
<!-- bool empty() const; // until C++11 -->
<!-- constexpr bool empty() const noexcept; // since C++11 until C++20 -->
<!-- [[nodiscard]] constexpr bool empty() const noexcept; // since C++20 -->
<function name="std::array::empty,std::deque::empty,std::list::empty,std::forward_list::empty,std::map::empty,std::unordered_map::empty,std::queue::empty,std::set::empty,std::unordered_set::empty,std::stack::empty,std::string::empty,std::wstring::empty,std::basic_string::empty,std::vector::empty,std::span::empty">
<use-retval/>
<const/>
<returnValue type="bool"/>
<noreturn>false</noreturn>
</function>
<!-- void std::deque::push_back( const T& value ); -->
<!-- void std::deque::push_back( T&& value ); // since C++11 -->
<!-- void std::deque::push_front( const T& value ); -->
@ -6676,7 +6667,7 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<not-uninit/>
</arg>
</function>
<function name="std::deque::size,std::deque::max_size,std::list::size,std::list::max_size,std::map::size,std::map::max_size,std::unordered_map::size,std::unordered_map::max_size,std::queue::size,std::set::size,std::set::max_size,std::unordered_set::size,std::unordered_set::max_size,std::stack::size,std::string::size,std::wstring::size,std::vector::size,std::vector::capacity,std::vector::max_size,std::array::size,std::array::max_size,std::span::size,std::span::size_bytes">
<function name="std::deque::max_size,std::list::max_size,std::map::max_size,std::unordered_map::max_size,std::set::max_size,std::unordered_set::max_size,std::vector::capacity,std::vector::max_size,std::span::size,std::span::size_bytes">
<use-retval/>
<const/>
<returnValue type="std::size_t"/>
@ -6969,12 +6960,6 @@ The obsolete function 'gets' is called. With 'gets' you'll get a buffer overrun
<valid>0:</valid>
</arg>
</function>
<function name="std::string::length,std::wstring::length,std::basic_string::size,std::basic_string::length">
<const/>
<use-retval/>
<returnValue type="std::size_t"/>
<noreturn>false</noreturn>
</function>
<function name="std::string::substr">
<use-retval/>
<returnValue type="std::string"/>
@ -8589,8 +8574,8 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init
<size>
<function name="resize" action="resize"/>
<function name="clear" action="clear"/>
<function name="size" yields="size"/>
<function name="empty" yields="empty"/>
<function name="size" yields="size" returnType="std::size_t"/>
<function name="empty" yields="empty" returnType="bool"/>
<function name="erase" action="erase"/>
<function name="insert" action="insert" yields="iterator"/>
<function name="emplace" action="push" yields="iterator"/>
@ -8640,7 +8625,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init
</container>
<container id="stdArray" startPattern="std :: array &lt;" inherits="stdContainer" opLessAllowed="true">
<size templateParameter="1">
<function name="max_size" yields="size"/>
<function name="max_size" yields="size" returnType="std::size_t"/>
</size>
<access indexOperator="array-like">
<function name="at" yields="at_index"/>
@ -8750,6 +8735,7 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init
<function name="replace" action="change"/>
<function name="reserve" action="change-internal"/>
<function name="shrink_to_fit" action="change-internal"/>
<function name="length" yields="size" returnType="std::size_t"/>
</size>
<access indexOperator="array-like">
<function name="at" yields="at_index"/>
@ -8757,7 +8743,6 @@ initializer list (7) string& replace (const_iterator i1, const_iterator i2, init
<function name="back" yields="item"/>
<function name="data" yields="buffer"/>
<function name="c_str" yields="buffer-nt"/>
<function name="length" yields="size"/>
<function name="find" action="find"/>
<function name="rfind" action="find"/>
<function name="find_last_of" action="find"/>

View File

@ -484,6 +484,10 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, yieldName);
}
const char* const returnType = functionNode->Attribute("returnType");
if (returnType)
container.functions[functionName].returnType = returnType;
container.functions[functionName].action = action;
container.functions[functionName].yield = yield;
}
@ -905,6 +909,10 @@ Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, co
return Error(ErrorCode::BAD_ATTRIBUTE_VALUE, yieldName);
}
func.containerYield = yield;
const char* const returnType = functionnode->Attribute("returnType");
if (returnType)
func.returnType = returnType;
} else
unknown_elements.insert(functionnodename);
}
@ -1358,17 +1366,18 @@ const Library::NonOverlappingData* Library::getNonOverlappingData(const Token *f
Library::UseRetValType Library::getUseRetValType(const Token *ftok) const
{
if (Token::simpleMatch(ftok->astParent(), ".")) {
using Yield = Library::Container::Yield;
using Action = Library::Container::Action;
const Yield yield = astContainerYield(ftok->astParent()->astOperand1());
if (yield == Yield::START_ITERATOR || yield == Yield::END_ITERATOR || yield == Yield::AT_INDEX ||
yield == Yield::SIZE || yield == Yield::EMPTY || yield == Yield::BUFFER || yield == Yield::BUFFER_NT ||
((yield == Yield::ITEM || yield == Yield::ITERATOR) && astContainerAction(ftok->astParent()->astOperand1()) == Action::NO_ACTION))
return Library::UseRetValType::DEFAULT;
}
if (isNotLibraryFunction(ftok))
if (isNotLibraryFunction(ftok)) {
if (Token::simpleMatch(ftok->astParent(), ".")) {
const Token* contTok = ftok->astParent()->astOperand1();
using Yield = Library::Container::Yield;
const Yield yield = astContainerYield(contTok);
if (yield == Yield::START_ITERATOR || yield == Yield::END_ITERATOR || yield == Yield::AT_INDEX ||
yield == Yield::SIZE || yield == Yield::EMPTY || yield == Yield::BUFFER || yield == Yield::BUFFER_NT ||
((yield == Yield::ITEM || yield == Yield::ITERATOR) && astContainerAction(contTok) == Library::Container::Action::NO_ACTION))
return Library::UseRetValType::DEFAULT;
}
return Library::UseRetValType::NONE;
}
const std::unordered_map<std::string, Function>::const_iterator it = functions.find(getFunctionName(ftok));
if (it != functions.cend())
return it->second.useretval;
@ -1385,8 +1394,14 @@ const std::string& Library::returnValue(const Token *ftok) const
const std::string& Library::returnValueType(const Token *ftok) const
{
if (isNotLibraryFunction(ftok))
if (isNotLibraryFunction(ftok)) {
if (Token::simpleMatch(ftok->astParent(), ".") && ftok->astParent()->astOperand1()) {
const Token* contTok = ftok->astParent()->astOperand1();
if (contTok->valueType() && contTok->valueType()->container)
return contTok->valueType()->container->getReturnType(ftok->str());
}
return emptyString;
}
const std::map<std::string, std::string>::const_iterator it = mReturnValueType.find(getFunctionName(ftok));
return it != mReturnValueType.cend() ? it->second : emptyString;
}
@ -1479,8 +1494,15 @@ bool Library::isFunctionConst(const Token *ftok) const
{
if (ftok->function() && ftok->function()->isConst())
return true;
if (isNotLibraryFunction(ftok))
if (isNotLibraryFunction(ftok)) {
if (Token::simpleMatch(ftok->astParent(), ".")) {
using Yield = Library::Container::Yield;
const Yield yield = astContainerYield(ftok->astParent()->astOperand1());
if (yield == Yield::EMPTY || yield == Yield::SIZE || yield == Yield::BUFFER_NT)
return true;
}
return false;
}
const std::unordered_map<std::string, Function>::const_iterator it = functions.find(getFunctionName(ftok));
return (it != functions.cend() && it->second.isconst);
}
@ -1489,8 +1511,15 @@ bool Library::isnoreturn(const Token *ftok) const
{
if (ftok->function() && ftok->function()->isAttributeNoreturn())
return true;
if (isNotLibraryFunction(ftok))
if (isNotLibraryFunction(ftok)) {
if (Token::simpleMatch(ftok->astParent(), ".")) {
const Token* contTok = ftok->astParent()->astOperand1();
if (astContainerAction(contTok) != Library::Container::Action::NO_ACTION ||
astContainerYield(contTok) != Library::Container::Yield::NO_YIELD)
return false;
}
return false;
}
const std::unordered_map<std::string, FalseTrueMaybe>::const_iterator it = mNoReturn.find(getFunctionName(ftok));
if (it == mNoReturn.end())
return false;

View File

@ -251,6 +251,7 @@ public:
struct Function {
Action action;
Yield yield;
std::string returnType;
};
struct RangeItemRecordTypeItem {
std::string name;
@ -284,6 +285,11 @@ public:
return Yield::NO_YIELD;
}
const std::string& getReturnType(const std::string& function) const {
auto i = functions.find(function);
return (i != functions.end()) ? i->second.returnType : emptyString;
}
static Yield yieldFrom(const std::string& yieldName);
static Action actionFrom(const std::string& actionName);
};
@ -359,6 +365,7 @@ public:
bool formatstr_secure;
Container::Action containerAction;
Container::Yield containerYield;
std::string returnType;
Function()
: use(false),
leakignore(false),