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_maybenull_z_(s)" value=""/>
|
||||||
<define name="_Ret_writes_bytes_to_maybenull_(s, c)" value=""/>
|
<define name="_Ret_writes_bytes_to_maybenull_(s, c)" value=""/>
|
||||||
<!-- Other Common Annotations -->
|
<!-- 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="_Out_range_(low, hi)" value=""/>
|
||||||
<define name="_Ret_range_(low, hi)" value=""/>
|
<define name="_Ret_range_(low, hi)" value=""/>
|
||||||
<define name="_Deref_in_range_(low, hi)" value=""/>
|
<define name="_Deref_in_range_(low, hi)" value=""/>
|
||||||
|
|
|
@ -1867,4 +1867,36 @@ TokenImpl::~TokenImpl()
|
||||||
for (auto templateSimplifierPointer : mTemplateSimplifierPointers) {
|
for (auto templateSimplifierPointer : mTemplateSimplifierPointers) {
|
||||||
templateSimplifierPointer->token = nullptr;
|
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
|
// Pointer to a template in the template simplifier
|
||||||
std::set<TemplateSimplifier::TokenAndName*> mTemplateSimplifierPointers;
|
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()
|
TokenImpl()
|
||||||
: mVarId(0)
|
: mVarId(0)
|
||||||
, mFileIndex(0)
|
, mFileIndex(0)
|
||||||
|
@ -114,6 +125,7 @@ struct TokenImpl {
|
||||||
, mValues(nullptr)
|
, mValues(nullptr)
|
||||||
, mBits(0)
|
, mBits(0)
|
||||||
, mTemplateSimplifierPointers()
|
, mTemplateSimplifierPointers()
|
||||||
|
, mCppcheckAttributes(nullptr)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
~TokenImpl();
|
~TokenImpl();
|
||||||
|
@ -498,6 +510,12 @@ public:
|
||||||
void isAttributeNodiscard(const bool value) {
|
void isAttributeNodiscard(const bool value) {
|
||||||
setFlag(fIsAttributeNodiscard, 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 {
|
bool isControlFlowKeyword() const {
|
||||||
return getFlag(fIsControlFlowKeyword);
|
return getFlag(fIsControlFlowKeyword);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4207,6 +4207,9 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
|
||||||
// remove __attribute__((?))
|
// remove __attribute__((?))
|
||||||
simplifyAttribute();
|
simplifyAttribute();
|
||||||
|
|
||||||
|
// simplify cppcheck attributes __cppcheck_?__(?)
|
||||||
|
simplifyCppcheckAttribute();
|
||||||
|
|
||||||
// Combine tokens..
|
// Combine tokens..
|
||||||
combineOperators();
|
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()
|
void Tokenizer::simplifyCPPAttribute()
|
||||||
{
|
{
|
||||||
if (mSettings->standards.cpp < Standards::CPP11 || isC())
|
if (mSettings->standards.cpp < Standards::CPP11 || isC())
|
||||||
|
|
|
@ -651,6 +651,11 @@ private:
|
||||||
*/
|
*/
|
||||||
void simplifyAttribute();
|
void simplifyAttribute();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove \__cppcheck\__ ((?))
|
||||||
|
*/
|
||||||
|
void simplifyCppcheckAttribute();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove keywords "volatile", "inline", "register", and "restrict"
|
* 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)
|
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) {
|
for (const Scope *functionScope : symboldatabase->functionScopes) {
|
||||||
if (!functionScope->bodyStart)
|
if (!functionScope->bodyStart)
|
||||||
continue;
|
continue;
|
||||||
|
@ -5416,18 +5414,37 @@ static void valueFlowSafeFunctions(TokenList *tokenlist, SymbolDatabase *symbold
|
||||||
if (!function)
|
if (!function)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!function->isSafe(settings))
|
const bool all = function->isSafe(settings) && settings->platformType != cppcheck::Platform::PlatformType::Unspecified;
|
||||||
continue;
|
|
||||||
|
|
||||||
for (const Variable &arg : function->argumentList) {
|
for (const Variable &arg : function->argumentList) {
|
||||||
MathLib::bigint minValue, maxValue;
|
if (!arg.nameToken())
|
||||||
if (!getMinMaxValues(arg.valueType(), *settings, &minValue, &maxValue))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::list<ValueFlow::Value> argValues;
|
MathLib::bigint low, high;
|
||||||
argValues.emplace_back(minValue);
|
bool isLow = arg.nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, &low);
|
||||||
argValues.emplace_back(maxValue);
|
bool isHigh = arg.nameToken()->getCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, &high);
|
||||||
|
|
||||||
|
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()),
|
valueFlowForward(const_cast<Token *>(functionScope->bodyStart->next()),
|
||||||
functionScope->bodyEnd,
|
functionScope->bodyEnd,
|
||||||
&arg,
|
&arg,
|
||||||
|
|
|
@ -3919,6 +3919,14 @@ private:
|
||||||
ASSERT_EQUALS(2, values.size());
|
ASSERT_EQUALS(2, values.size());
|
||||||
ASSERT_EQUALS(-0x8000, values.front().intvalue);
|
ASSERT_EQUALS(-0x8000, values.front().intvalue);
|
||||||
ASSERT_EQUALS(0x7fff, values.back().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