Annotations: Add annotation __cppcheck_in_range__(low,high)
This commit is contained in:
parent
d223d73cdb
commit
68cc7516a1
|
@ -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=""/>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
18
lib/token.h
18
lib/token.h
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -651,6 +651,11 @@ private:
|
|||
*/
|
||||
void simplifyAttribute();
|
||||
|
||||
/**
|
||||
* Remove \__cppcheck\__ ((?))
|
||||
*/
|
||||
void simplifyCppcheckAttribute();
|
||||
|
||||
/**
|
||||
* Remove keywords "volatile", "inline", "register", and "restrict"
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue