Annotations: Add annotation __cppcheck_in_range__(low,high)

This commit is contained in:
Daniel Marjamäki 2019-07-12 11:09:24 +02:00
parent d223d73cdb
commit 68cc7516a1
7 changed files with 133 additions and 20 deletions

View File

@ -108,7 +108,7 @@
<define name="_Ret_writes_maybenull_z_(s)" value=""/>
<define name="_Ret_writes_bytes_to_maybenull_(s, c)" value=""/>
<!-- Other Common Annotations -->
<define name="_In_range_(low, hi)" value=""/>
<define name="_In_range_(low, hi)" value="__cppcheck_in_range__(low, hi)"/>
<define name="_Out_range_(low, hi)" value=""/>
<define name="_Ret_range_(low, hi)" value=""/>
<define name="_Deref_in_range_(low, hi)" value=""/>

View File

@ -1867,4 +1867,36 @@ TokenImpl::~TokenImpl()
for (auto templateSimplifierPointer : mTemplateSimplifierPointers) {
templateSimplifierPointer->token = nullptr;
}
while (mCppcheckAttributes) {
struct CppcheckAttributes *c = mCppcheckAttributes;
mCppcheckAttributes = mCppcheckAttributes->next;
delete c;
}
}
void TokenImpl::setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint value)
{
struct CppcheckAttributes *attr = mCppcheckAttributes;
while (attr && attr->type != type)
attr = attr->next;
if (attr)
attr->value = value;
else {
attr = new CppcheckAttributes;
attr->type = type;
attr->value = value;
attr->next = mCppcheckAttributes;
mCppcheckAttributes = attr;
}
}
bool TokenImpl::getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *value) const
{
struct CppcheckAttributes *attr = mCppcheckAttributes;
while (attr && attr->type != type)
attr = attr->next;
if (attr)
*value = attr->value;
return attr != nullptr;
}

View File

@ -97,6 +97,17 @@ struct TokenImpl {
// Pointer to a template in the template simplifier
std::set<TemplateSimplifier::TokenAndName*> mTemplateSimplifierPointers;
// __cppcheck_in_range__
struct CppcheckAttributes {
enum Type {LOW,HIGH} type;
MathLib::bigint value;
struct CppcheckAttributes *next;
};
struct CppcheckAttributes *mCppcheckAttributes;
void setCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint value);
bool getCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint *value) const;
TokenImpl()
: mVarId(0)
, mFileIndex(0)
@ -114,6 +125,7 @@ struct TokenImpl {
, mValues(nullptr)
, mBits(0)
, mTemplateSimplifierPointers()
, mCppcheckAttributes(nullptr)
{}
~TokenImpl();
@ -498,6 +510,12 @@ public:
void isAttributeNodiscard(const bool value) {
setFlag(fIsAttributeNodiscard, value);
}
void setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint value) {
mImpl->setCppcheckAttribute(type, value);
}
bool getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint *value) const {
return mImpl->getCppcheckAttribute(type, value);
}
bool isControlFlowKeyword() const {
return getFlag(fIsControlFlowKeyword);
}

View File

@ -4207,6 +4207,9 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
// remove __attribute__((?))
simplifyAttribute();
// simplify cppcheck attributes __cppcheck_?__(?)
simplifyCppcheckAttribute();
// Combine tokens..
combineOperators();
@ -9788,6 +9791,36 @@ void Tokenizer::simplifyAttribute()
}
}
void Tokenizer::simplifyCppcheckAttribute()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->str() != "(")
continue;
if (!tok->previous())
continue;
const std::string &attr = tok->previous()->str();
if (attr.compare(0, 11, "__cppcheck_") != 0) // TODO: starts_with("__cppcheck_")
continue;
if (attr.compare(attr.size()-2, 2, "__") != 0) // TODO: ends_with("__")
continue;
if (attr == "__cppcheck_in_range__") {
Token *vartok = tok->link();
while (Token::Match(vartok->next(), "%name%|*|&|::"))
vartok = vartok->next();
if (vartok->isName() && Token::Match(tok, "( %num% , %num% )")) {
vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(tok->next()->str()));
vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(tok->strAt(3)));
}
}
// Delete cppcheck attribute..
tok = tok->previous();
Token::eraseTokens(tok, tok->linkAt(1)->next());
tok->deleteThis();
}
}
void Tokenizer::simplifyCPPAttribute()
{
if (mSettings->standards.cpp < Standards::CPP11 || isC())

View File

@ -651,6 +651,11 @@ private:
*/
void simplifyAttribute();
/**
* Remove \__cppcheck\__ ((?))
*/
void simplifyCppcheckAttribute();
/**
* Remove keywords "volatile", "inline", "register", and "restrict"
*/

View File

@ -5407,8 +5407,6 @@ static bool getMinMaxValues(const std::string &typestr, const Settings *settings
static void valueFlowSafeFunctions(TokenList *tokenlist, SymbolDatabase *symboldatabase, ErrorLogger *errorLogger, const Settings *settings)
{
if (settings->platformType == cppcheck::Platform::PlatformType::Unspecified)
return;
for (const Scope *functionScope : symboldatabase->functionScopes) {
if (!functionScope->bodyStart)
continue;
@ -5416,28 +5414,47 @@ static void valueFlowSafeFunctions(TokenList *tokenlist, SymbolDatabase *symbold
if (!function)
continue;
if (!function->isSafe(settings))
continue;
const bool all = function->isSafe(settings) && settings->platformType != cppcheck::Platform::PlatformType::Unspecified;
for (const Variable &arg : function->argumentList) {
MathLib::bigint minValue, maxValue;
if (!getMinMaxValues(arg.valueType(), *settings, &minValue, &maxValue))
if (!arg.nameToken())
continue;
std::list<ValueFlow::Value> argValues;
argValues.emplace_back(minValue);
argValues.emplace_back(maxValue);
MathLib::bigint low, high;
bool isLow = arg.nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, &low);
bool isHigh = arg.nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, &high);
valueFlowForward(const_cast<Token *>(functionScope->bodyStart->next()),
functionScope->bodyEnd,
&arg,
arg.declarationId(),
argValues,
false,
false,
tokenlist,
errorLogger,
settings);
if (!isLow && !isHigh && !all)
continue;
if ((!isLow || !isHigh) && all) {
MathLib::bigint minValue, maxValue;
if (getMinMaxValues(arg.valueType(), *settings, &minValue, &maxValue)) {
if (!isLow)
low = minValue;
if (!isHigh)
high = maxValue;
isLow = isHigh = true;
}
}
std::list<ValueFlow::Value> argValues;
if (isLow)
argValues.emplace_back(low);
if (isHigh)
argValues.emplace_back(high);
if (!argValues.empty())
valueFlowForward(const_cast<Token *>(functionScope->bodyStart->next()),
functionScope->bodyEnd,
&arg,
arg.declarationId(),
argValues,
false,
false,
tokenlist,
errorLogger,
settings);
}
}
}

View File

@ -3919,6 +3919,14 @@ private:
ASSERT_EQUALS(2, values.size());
ASSERT_EQUALS(-0x8000, values.front().intvalue);
ASSERT_EQUALS(0x7fff, values.back().intvalue);
code = "void f(__cppcheck_in_range__(0,100) short x) {\n"
" return x + 0;\n"
"}";
values = tokenValues(code, "+", &s);
ASSERT_EQUALS(2, values.size());
ASSERT_EQUALS(0, values.front().intvalue);
ASSERT_EQUALS(100, values.back().intvalue);
}