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:
shaneasd 2020-04-13 02:35:54 +08:00 committed by GitHub
parent 97f5c5767e
commit 82c09f243b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 111 additions and 5 deletions

View File

@ -1246,6 +1246,7 @@ void CheckUnusedVar::checkFunctionVariableUsage()
} }
// warn // warn
if(!expr->variable() || !expr->variable()->isMaybeUnused())
unreadVariableError(tok, expr->expressionString(), false); 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) {
if (!usage._var->isMaybeUnused()) {
unusedVariableError(usage._var->nameToken(), varname); 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);

View File

@ -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

View File

@ -193,7 +193,8 @@ class CPPCHECKLIB Variable {
fIsStlString = (1 << 11), /** @brief std::string|wstring|basic_string&lt;T&gt;|u16string|u32string */ fIsStlString = (1 << 11), /** @brief std::string|wstring|basic_string&lt;T&gt;|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;
} }

View File

@ -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;

View File

@ -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() == ":")

View File

@ -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 {}"