diff --git a/cfg/microsoft_sal.cfg b/cfg/microsoft_sal.cfg
index 847eaff93..33b963044 100644
--- a/cfg/microsoft_sal.cfg
+++ b/cfg/microsoft_sal.cfg
@@ -108,7 +108,7 @@
-
+
diff --git a/lib/token.cpp b/lib/token.cpp
index 7f4fe9c2f..20efdae3d 100644
--- a/lib/token.cpp
+++ b/lib/token.cpp
@@ -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;
}
diff --git a/lib/token.h b/lib/token.h
index 53cfb8df0..2dd3315d5 100644
--- a/lib/token.h
+++ b/lib/token.h
@@ -97,6 +97,17 @@ struct TokenImpl {
// Pointer to a template in the template simplifier
std::set 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);
}
diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp
index d8efd9572..9753e1028 100644
--- a/lib/tokenize.cpp
+++ b/lib/tokenize.cpp
@@ -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())
diff --git a/lib/tokenize.h b/lib/tokenize.h
index f7bf19a36..9a263d14a 100644
--- a/lib/tokenize.h
+++ b/lib/tokenize.h
@@ -651,6 +651,11 @@ private:
*/
void simplifyAttribute();
+ /**
+ * Remove \__cppcheck\__ ((?))
+ */
+ void simplifyCppcheckAttribute();
+
/**
* Remove keywords "volatile", "inline", "register", and "restrict"
*/
diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp
index 6e26af491..003428145 100644
--- a/lib/valueflow.cpp
+++ b/lib/valueflow.cpp
@@ -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 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(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 argValues;
+ if (isLow)
+ argValues.emplace_back(low);
+ if (isHigh)
+ argValues.emplace_back(high);
+
+ if (!argValues.empty())
+ valueFlowForward(const_cast(functionScope->bodyStart->next()),
+ functionScope->bodyEnd,
+ &arg,
+ arg.declarationId(),
+ argValues,
+ false,
+ false,
+ tokenlist,
+ errorLogger,
+ settings);
}
}
}
diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp
index 307b3e164..b5d59b88c 100644
--- a/test/testvalueflow.cpp
+++ b/test/testvalueflow.cpp
@@ -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);
}