Maybeunusedsupport (#2570)
* Add rudimentary support for [[maybe_unused]] * Add more test cases. use the symboldatabase rather than reparsing. Fix travis error. * test review actions * change var to usage._var
This commit is contained in:
parent
97f5c5767e
commit
82c09f243b
|
@ -1246,7 +1246,8 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
}
|
}
|
||||||
|
|
||||||
// warn
|
// warn
|
||||||
unreadVariableError(tok, expr->expressionString(), false);
|
if(!expr->variable() || !expr->variable()->isMaybeUnused())
|
||||||
|
unreadVariableError(tok, expr->expressionString(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1281,9 +1282,11 @@ void CheckUnusedVar::checkFunctionVariableUsage()
|
||||||
allocatedButUnusedVariableError(usage._lastAccess, varname);
|
allocatedButUnusedVariableError(usage._lastAccess, varname);
|
||||||
|
|
||||||
// variable has not been written, read, or modified
|
// variable has not been written, read, or modified
|
||||||
else if (usage.unused() && !usage._modified)
|
else if (usage.unused() && !usage._modified) {
|
||||||
unusedVariableError(usage._var->nameToken(), varname);
|
if (!usage._var->isMaybeUnused()) {
|
||||||
|
unusedVariableError(usage._var->nameToken(), varname);
|
||||||
|
}
|
||||||
|
}
|
||||||
// variable has not been written but has been modified
|
// variable has not been written but has been modified
|
||||||
else if (usage._modified && !usage._write && !usage._allocateMemory && var && !var->isStlType())
|
else if (usage._modified && !usage._write && !usage._allocateMemory && var && !var->isStlType())
|
||||||
unassignedVariableError(usage._var->nameToken(), varname);
|
unassignedVariableError(usage._var->nameToken(), varname);
|
||||||
|
|
|
@ -1889,6 +1889,10 @@ void Variable::evaluate(const Settings* settings)
|
||||||
setFlag(fIsReference, true); // Set also fIsReference
|
setFlag(fIsReference, true); // Set also fIsReference
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tok->isMaybeUnused()) {
|
||||||
|
setFlag(fIsMaybeUnused, true);
|
||||||
|
}
|
||||||
|
|
||||||
if (tok->str() == "<" && tok->link())
|
if (tok->str() == "<" && tok->link())
|
||||||
tok = tok->link();
|
tok = tok->link();
|
||||||
else
|
else
|
||||||
|
|
|
@ -193,7 +193,8 @@ class CPPCHECKLIB Variable {
|
||||||
fIsStlString = (1 << 11), /** @brief std::string|wstring|basic_string<T>|u16string|u32string */
|
fIsStlString = (1 << 11), /** @brief std::string|wstring|basic_string<T>|u16string|u32string */
|
||||||
fIsFloatType = (1 << 12), /** @brief Floating point type */
|
fIsFloatType = (1 << 12), /** @brief Floating point type */
|
||||||
fIsVolatile = (1 << 13), /** @brief volatile */
|
fIsVolatile = (1 << 13), /** @brief volatile */
|
||||||
fIsSmartPointer = (1 << 14) /** @brief std::shared_ptr|unique_ptr */
|
fIsSmartPointer = (1 << 14),/** @brief std::shared_ptr|unique_ptr */
|
||||||
|
fIsMaybeUnused = (1 << 15), /** @brief marked [[maybe_unused]] */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -618,6 +619,10 @@ public:
|
||||||
return type() && type()->isEnumType();
|
return type() && type()->isEnumType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isMaybeUnused() const {
|
||||||
|
return getFlag(fIsMaybeUnused);
|
||||||
|
}
|
||||||
|
|
||||||
const ValueType *valueType() const {
|
const ValueType *valueType() const {
|
||||||
return mValueType;
|
return mValueType;
|
||||||
}
|
}
|
||||||
|
|
|
@ -541,6 +541,12 @@ public:
|
||||||
void isAttributeNodiscard(const bool value) {
|
void isAttributeNodiscard(const bool value) {
|
||||||
setFlag(fIsAttributeNodiscard, value);
|
setFlag(fIsAttributeNodiscard, value);
|
||||||
}
|
}
|
||||||
|
bool isMaybeUnused() const {
|
||||||
|
return getFlag(fIsMaybeUnused);
|
||||||
|
}
|
||||||
|
void isMaybeUnused(const bool value) {
|
||||||
|
setFlag(fIsMaybeUnused, value);
|
||||||
|
}
|
||||||
void setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint value) {
|
void setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint value) {
|
||||||
mImpl->setCppcheckAttribute(type, value);
|
mImpl->setCppcheckAttribute(type, value);
|
||||||
}
|
}
|
||||||
|
@ -1155,6 +1161,7 @@ private:
|
||||||
fIncompleteVar = (1 << 25),
|
fIncompleteVar = (1 << 25),
|
||||||
fConstexpr = (1 << 26),
|
fConstexpr = (1 << 26),
|
||||||
fExternC = (1 << 27),
|
fExternC = (1 << 27),
|
||||||
|
fIsMaybeUnused = (1 << 28), // [[maybe_unsed]]
|
||||||
};
|
};
|
||||||
|
|
||||||
Token::Type mTokType;
|
Token::Type mTokType;
|
||||||
|
|
|
@ -10246,6 +10246,11 @@ void Tokenizer::simplifyCPPAttribute()
|
||||||
else
|
else
|
||||||
head->previous()->isAttributeNodiscard(true);
|
head->previous()->isAttributeNodiscard(true);
|
||||||
}
|
}
|
||||||
|
} else if (Token::simpleMatch(tok->tokAt(2), "maybe_unused")) {
|
||||||
|
Token* head = tok->tokAt(5);
|
||||||
|
while (isCPPAttribute(head))
|
||||||
|
head = head->tokAt(5);
|
||||||
|
head->isMaybeUnused(true);
|
||||||
} else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
|
} else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
|
||||||
const Token *vartok = tok->tokAt(4);
|
const Token *vartok = tok->tokAt(4);
|
||||||
if (vartok->str() == ":")
|
if (vartok->str() == ":")
|
||||||
|
|
|
@ -148,6 +148,7 @@ private:
|
||||||
TEST_CASE(localvarconst1);
|
TEST_CASE(localvarconst1);
|
||||||
TEST_CASE(localvarconst2);
|
TEST_CASE(localvarconst2);
|
||||||
TEST_CASE(localvarreturn); // ticket #9167
|
TEST_CASE(localvarreturn); // ticket #9167
|
||||||
|
TEST_CASE(localvarmaybeunused);
|
||||||
|
|
||||||
TEST_CASE(localvarthrow); // ticket #3687
|
TEST_CASE(localvarthrow); // ticket #3687
|
||||||
|
|
||||||
|
@ -4160,6 +4161,87 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void localvarmaybeunused() {
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] int x;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("[[nodiscard]] int getX() { return 4; }\n"
|
||||||
|
"int main() {\n"
|
||||||
|
" [[maybe_unused]] int x = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("[[nodiscard]] int getX() { return 4; }\n"
|
||||||
|
"int main() {\n"
|
||||||
|
" [[maybe_unused]] int x = getX();\n"
|
||||||
|
" x = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("[[nodiscard]] int getX() { return 4; }\n"
|
||||||
|
"int main() {\n"
|
||||||
|
" [[maybe_unused]] int x = getX();\n"
|
||||||
|
" x = getX();\n"
|
||||||
|
" std::cout << x;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] const int x = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] const int& x = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] const int* x = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] int& x = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] int* x = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] auto x = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] auto&& x = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] int x[] = getX();\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] constexpr volatile static int x = 1;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("[[maybe_unused]] inline int x = 1;");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
functionVariableUsage("int main() {\n"
|
||||||
|
" [[maybe_unused]] [[anotherattribute]] const int* = 1;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void localvarthrow() { // ticket #3687
|
void localvarthrow() { // ticket #3687
|
||||||
functionVariableUsage("void foo() {\n"
|
functionVariableUsage("void foo() {\n"
|
||||||
" try {}"
|
" try {}"
|
||||||
|
|
Loading…
Reference in New Issue