Fixed #5638 (is there any plan to check noexcept correctness?)
This commit is contained in:
parent
4ae204e46b
commit
847d28d283
|
@ -176,3 +176,48 @@ void CheckExceptionSafety::checkCatchExceptionByValue()
|
|||
catchExceptionByValueError(i->classDef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// void func() noexcept { throw x; }
|
||||
//--------------------------------------------------------------------------
|
||||
void CheckExceptionSafety::noexceptThrows()
|
||||
{
|
||||
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
|
||||
const std::size_t functions = symbolDatabase->functionScopes.size();
|
||||
for (std::size_t i = 0; i < functions; ++i) {
|
||||
const Scope * scope = symbolDatabase->functionScopes[i];
|
||||
// onlycheck noexcept functions
|
||||
if (scope->function && scope->function->isNoExcept &&
|
||||
(!scope->function->noexceptArg || scope->function->noexceptArg->str() == "true")) {
|
||||
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
|
||||
if (tok->str() != "throw") {
|
||||
noexceptThrowError(tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// void func() throw() { throw x; }
|
||||
//--------------------------------------------------------------------------
|
||||
void CheckExceptionSafety::nothrowThrows()
|
||||
{
|
||||
const SymbolDatabase* const symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||
|
||||
const std::size_t functions = symbolDatabase->functionScopes.size();
|
||||
for (std::size_t i = 0; i < functions; ++i) {
|
||||
const Scope * scope = symbolDatabase->functionScopes[i];
|
||||
// onlycheck throw() functions
|
||||
if (scope->function && scope->function->isThrow && !scope->function->throwArg) {
|
||||
for (const Token *tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) {
|
||||
if (tok->str() != "throw") {
|
||||
nothrowThrowError(tok);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,8 @@ public:
|
|||
checkExceptionSafety.deallocThrow();
|
||||
checkExceptionSafety.checkRethrowCopy();
|
||||
checkExceptionSafety.checkCatchExceptionByValue();
|
||||
checkExceptionSafety.noexceptThrows();
|
||||
checkExceptionSafety.nothrowThrows();
|
||||
}
|
||||
|
||||
/** Don't throw exceptions in destructors */
|
||||
|
@ -75,6 +77,12 @@ public:
|
|||
/** @brief %Check for exceptions that are caught by value instead of by reference */
|
||||
void checkCatchExceptionByValue();
|
||||
|
||||
/** @brief %Check for noexcept functions that throw */
|
||||
void noexceptThrows();
|
||||
|
||||
/** @brief %Check for throw() functions that throw */
|
||||
void nothrowThrows();
|
||||
|
||||
private:
|
||||
/** Don't throw exceptions in destructors */
|
||||
void destructorsError(const Token * const tok) {
|
||||
|
@ -100,6 +108,16 @@ private:
|
|||
"as a (const) reference which is usually recommended in C++.");
|
||||
}
|
||||
|
||||
/** Don't throw exceptions in noexcept functions */
|
||||
void noexceptThrowError(const Token * const tok) {
|
||||
reportError(tok, Severity::error, "exceptThrowInNoexecptFunction", "Exception thrown in noexcept function.");
|
||||
}
|
||||
|
||||
/** Don't throw exceptions in throw() functions */
|
||||
void nothrowThrowError(const Token * const tok) {
|
||||
reportError(tok, Severity::error, "exceptThrowInNoThrowFunction", "Exception thrown in throw() function.");
|
||||
}
|
||||
|
||||
/** Generate all possible errors (for --errorlist) */
|
||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
||||
CheckExceptionSafety c(0, settings, errorLogger);
|
||||
|
@ -107,6 +125,8 @@ private:
|
|||
c.deallocThrowError(0, "p");
|
||||
c.rethrowCopyError(0, "varname");
|
||||
c.catchExceptionByValueError(0);
|
||||
c.noexceptThrowError(0);
|
||||
c.nothrowThrowError(0);
|
||||
}
|
||||
|
||||
/** Short description of class (for --doc) */
|
||||
|
@ -120,7 +140,9 @@ private:
|
|||
"* Throwing exceptions in destructors\n"
|
||||
"* Throwing exception during invalid state\n"
|
||||
"* Throwing a copy of a caught exception instead of rethrowing the original exception\n"
|
||||
"* Exception caught by value instead of by reference\n";
|
||||
"* Exception caught by value instead of by reference\n"
|
||||
"* Throwing exception in noexcept function\n"
|
||||
"* Throwing exception in nothrow() function\n";
|
||||
}
|
||||
};
|
||||
/// @}
|
||||
|
|
|
@ -458,6 +458,72 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
scope->functionList.push_back(function);
|
||||
}
|
||||
|
||||
// noexcept;
|
||||
// const noexcept;
|
||||
else if (Token::Match(end, ") const| noexcept ;")) {
|
||||
function.isNoExcept = true;
|
||||
|
||||
if (end->next()->str() == "const")
|
||||
tok = end->tokAt(3);
|
||||
else
|
||||
tok = end->tokAt(2);
|
||||
|
||||
scope->functionList.push_back(function);
|
||||
}
|
||||
|
||||
// noexcept const;
|
||||
else if (Token::simpleMatch(end, ") noexcept const ;")) {
|
||||
function.isNoExcept = true;
|
||||
|
||||
tok = end->tokAt(3);
|
||||
|
||||
scope->functionList.push_back(function);
|
||||
}
|
||||
|
||||
// noexcept(...);
|
||||
// noexcept(...) const;
|
||||
else if (Token::simpleMatch(end, ") noexcept (") &&
|
||||
Token::Match(end->linkAt(2), ") const| ;")) {
|
||||
function.isNoExcept = true;
|
||||
|
||||
if (end->linkAt(2)->strAt(1) == "const")
|
||||
tok = end->linkAt(2)->tokAt(2);
|
||||
else
|
||||
tok = end->linkAt(2)->next();
|
||||
|
||||
scope->functionList.push_back(function);
|
||||
}
|
||||
|
||||
// const noexcept(...);
|
||||
else if (Token::simpleMatch(end, ") const noexcept (") &&
|
||||
Token::simpleMatch(end->linkAt(3), ") ;")) {
|
||||
function.isNoExcept = true;
|
||||
|
||||
tok = end->linkAt(3)->next();
|
||||
|
||||
scope->functionList.push_back(function);
|
||||
}
|
||||
|
||||
// throw()
|
||||
// const throw()
|
||||
else if (Token::Match(end, ") const| throw (") &&
|
||||
(end->next()->str() == "const" ? Token::Match(end->linkAt(3), ") ;") :
|
||||
Token::Match(end->linkAt(2), ") ;"))) {
|
||||
function.isThrow = true;
|
||||
|
||||
if (end->next()->str() == "const") {
|
||||
if (end->strAt(4) != ")")
|
||||
function.throwArg = end->tokAt(4);
|
||||
tok = end->linkAt(3)->next();
|
||||
} else {
|
||||
if (end->strAt(3) != ")")
|
||||
function.throwArg = end->tokAt(3);
|
||||
tok = end->linkAt(2)->next();
|
||||
}
|
||||
|
||||
scope->functionList.push_back(function);
|
||||
}
|
||||
|
||||
// pure virtual function
|
||||
else if (Token::Match(end, ") const| = %any% ;")) {
|
||||
function.isPure = true;
|
||||
|
@ -481,6 +547,28 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
function.isInline = true;
|
||||
function.hasBody = true;
|
||||
|
||||
if (Token::Match(end, ") const| noexcept")) {
|
||||
int arg = 2;
|
||||
|
||||
if (end->strAt(1) == "const")
|
||||
arg++;
|
||||
|
||||
if (end->strAt(arg) == "(")
|
||||
function.noexceptArg = end->tokAt(arg + 1);
|
||||
|
||||
function.isNoExcept = true;
|
||||
} else if (Token::Match(end, ") const| throw (")) {
|
||||
int arg = 3;
|
||||
|
||||
if (end->strAt(1) == "const")
|
||||
arg++;
|
||||
|
||||
if (end->strAt(arg) != ")")
|
||||
function.throwArg = end->tokAt(arg);
|
||||
|
||||
function.isThrow = true;
|
||||
}
|
||||
|
||||
// find start of function '{'
|
||||
while (end && end->str() != "{" && end->str() != ";")
|
||||
end = end->next();
|
||||
|
@ -549,11 +637,13 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
if (isFunction(tok, scope, &funcStart, &argStart)) {
|
||||
bool retFuncPtr = Token::simpleMatch(argStart->link(), ") ) (");
|
||||
const Token* scopeBegin = argStart->link()->next();
|
||||
|
||||
if (retFuncPtr)
|
||||
scopeBegin = scopeBegin->next()->link()->next();
|
||||
if (scopeBegin->isName()) { // Jump behind 'const' or unknown Macro
|
||||
scopeBegin = scopeBegin->next();
|
||||
if (scopeBegin->str() == "throw")
|
||||
scopeBegin = scopeBegin->next();
|
||||
|
||||
if (scopeBegin->link() && scopeBegin->str() == "(") // Jump behind unknown macro of type THROW(...)
|
||||
scopeBegin = scopeBegin->link()->next();
|
||||
}
|
||||
|
@ -576,6 +666,29 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
else {
|
||||
Function* function = addGlobalFunction(scope, tok, argStart, funcStart);
|
||||
function->retFuncPtr = retFuncPtr;
|
||||
|
||||
// global functions can't be const but we have tests that are
|
||||
if (Token::Match(argStart->link(), ") const| noexcept")) {
|
||||
int arg = 2;
|
||||
|
||||
if (argStart->link()->strAt(1) == "const")
|
||||
arg++;
|
||||
|
||||
if (argStart->link()->strAt(arg) == "(")
|
||||
function->noexceptArg = argStart->link()->tokAt(arg + 1);
|
||||
|
||||
function->isNoExcept = true;
|
||||
} else if (Token::Match(argStart->link(), ") const| throw (")) {
|
||||
int arg = 3;
|
||||
|
||||
if (argStart->link()->strAt(1) == "const")
|
||||
arg++;
|
||||
|
||||
if (argStart->link()->strAt(arg) != ")")
|
||||
function->throwArg = argStart->link()->tokAt(arg);
|
||||
|
||||
function->isThrow = true;
|
||||
}
|
||||
}
|
||||
|
||||
// syntax error?
|
||||
|
@ -598,6 +711,28 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
|||
if (newFunc) {
|
||||
Function* func = addGlobalFunctionDecl(scope, tok, argStart, funcStart);
|
||||
func->retFuncPtr = retFuncPtr;
|
||||
|
||||
if (Token::Match(argStart->link(), ") const| noexcept")) {
|
||||
int arg = 2;
|
||||
|
||||
if (argStart->link()->strAt(1) == "const")
|
||||
arg++;
|
||||
|
||||
if (argStart->link()->strAt(arg) == "(")
|
||||
func->noexceptArg = argStart->link()->tokAt(arg + 1);
|
||||
|
||||
func->isNoExcept = true;
|
||||
} else if (Token::Match(argStart->link(), ") const| throw (")) {
|
||||
int arg = 3;
|
||||
|
||||
if (argStart->link()->strAt(1) == "const")
|
||||
arg++;
|
||||
|
||||
if (argStart->link()->strAt(arg) != ")")
|
||||
func->throwArg = argStart->link()->tokAt(arg);
|
||||
|
||||
func->isThrow = true;
|
||||
}
|
||||
}
|
||||
|
||||
tok = scopeBegin;
|
||||
|
@ -965,11 +1100,16 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
|
|||
tok->strAt(-1) == "::" || tok->strAt(-1) == "~" || // or a scope qualifier in front of tok
|
||||
outerScope->isClassOrStruct())) { // or a ctor/dtor
|
||||
const Token* tok2 = tok->next()->link()->next();
|
||||
if ((Token::Match(tok2, "const| ;|{|=") ||
|
||||
if (tok2 &&
|
||||
(Token::Match(tok2, "const| ;|{|=") ||
|
||||
(Token::Match(tok2, "%var% ;|{") && tok2->isUpperCaseName()) ||
|
||||
(Token::Match(tok2, "%var% (") && tok2->isUpperCaseName() && tok2->next()->link()->strAt(1) == "{") ||
|
||||
Token::Match(tok2, ": ::| %var% (|::|<|{") ||
|
||||
Token::Match(tok2, "= delete|default ;"))) {
|
||||
Token::Match(tok2, "= delete|default ;") ||
|
||||
Token::Match(tok2, "const| noexcept const| {|:|;") ||
|
||||
(Token::Match(tok2, "const| noexcept|throw (") &&
|
||||
tok2->str() == "const" ? (tok2->tokAt(2) && Token::Match(tok2->tokAt(2)->link(), ") const| {|:|;")) :
|
||||
(tok2->next() && Token::Match(tok2->next()->link(), ") const| {|:|;"))))) {
|
||||
*funcStart = tok;
|
||||
*argStart = tok->next();
|
||||
return true;
|
||||
|
@ -980,7 +1120,8 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
|
|||
else if (Token::Match(tok, "%var% <") && Token::simpleMatch(tok->next()->link(), "> (")) {
|
||||
const Token* tok2 = tok->next()->link()->next()->link();
|
||||
if (Token::Match(tok2, ") const| ;|{|=") ||
|
||||
Token::Match(tok2, ") : ::| %var% (|::|<|{")) {
|
||||
Token::Match(tok2, ") : ::| %var% (|::|<|{") ||
|
||||
Token::Match(tok->next()->link()->next()->link(), ") const| noexcept {|;|(")) {
|
||||
*funcStart = tok;
|
||||
*argStart = tok2->link();
|
||||
return true;
|
||||
|
@ -1772,8 +1913,12 @@ void SymbolDatabase::printOut(const char *title) const
|
|||
std::cout << " isExplicit: " << (func->isExplicit ? "true" : "false") << std::endl;
|
||||
std::cout << " isDefault: " << (func->isDefault ? "true" : "false") << std::endl;
|
||||
std::cout << " isDelete: " << (func->isDelete ? "true" : "false") << std::endl;
|
||||
std::cout << " isNoExcept: " << (func->isNoExcept ? "true" : "false") << std::endl;
|
||||
std::cout << " isThrow: " << (func->isThrow ? "true" : "false") << std::endl;
|
||||
std::cout << " isOperator: " << (func->isOperator ? "true" : "false") << std::endl;
|
||||
std::cout << " retFuncPtr: " << (func->retFuncPtr ? "true" : "false") << std::endl;
|
||||
std::cout << " noexceptArg: " << (func->noexceptArg ? func->noexceptArg->str() : "none") << std::endl;
|
||||
std::cout << " throwArg: " << (func->throwArg ? func->throwArg->str() : "none") << std::endl;
|
||||
std::cout << " tokenDef: " << func->tokenDef->str() << " " <<_tokenizer->list.fileLine(func->tokenDef) << std::endl;
|
||||
std::cout << " argDef: " << _tokenizer->list.fileLine(func->argDef) << std::endl;
|
||||
if (!func->isConstructor() && !func->isDestructor())
|
||||
|
|
|
@ -544,8 +544,12 @@ public:
|
|||
isExplicit(false),
|
||||
isDefault(false),
|
||||
isDelete(false),
|
||||
isNoExcept(false),
|
||||
isThrow(false),
|
||||
isOperator(false),
|
||||
retFuncPtr(false) {
|
||||
retFuncPtr(false),
|
||||
noexceptArg(nullptr),
|
||||
throwArg(nullptr) {
|
||||
}
|
||||
|
||||
const std::string &name() const {
|
||||
|
@ -610,8 +614,12 @@ public:
|
|||
bool isExplicit; // is explicit
|
||||
bool isDefault; // is default
|
||||
bool isDelete; // is delete
|
||||
bool isNoExcept; // is noexcept
|
||||
bool isThrow; // is throw
|
||||
bool isOperator; // is operator
|
||||
bool retFuncPtr; // returns function pointer
|
||||
const Token *noexceptArg;
|
||||
const Token *throwArg;
|
||||
|
||||
static bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth);
|
||||
|
||||
|
|
|
@ -3352,9 +3352,6 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
|
|||
// Simplify the operator "?:"
|
||||
simplifyConditionOperator();
|
||||
|
||||
// remove exception specifications..
|
||||
removeExceptionSpecifications();
|
||||
|
||||
// Collapse operator name tokens into single token
|
||||
// operator = => operator=
|
||||
simplifyOperatorName();
|
||||
|
@ -3680,7 +3677,7 @@ void Tokenizer::removeMacrosInGlobalScope()
|
|||
if (tok->str() == "(") {
|
||||
tok = tok->link();
|
||||
if (Token::Match(tok, ") %type% {") &&
|
||||
!Token::Match(tok->next(), "const|namespace|class|struct|union"))
|
||||
!Token::Match(tok->next(), "const|namespace|class|struct|union|noexcept"))
|
||||
tok->deleteNext();
|
||||
}
|
||||
|
||||
|
@ -8620,30 +8617,6 @@ void Tokenizer::simplifyComma()
|
|||
}
|
||||
|
||||
|
||||
void Tokenizer::removeExceptionSpecifications()
|
||||
{
|
||||
if (isC())
|
||||
return;
|
||||
|
||||
for (Token* tok = list.front(); tok; tok = tok->next()) {
|
||||
if (Token::Match(tok, ") const| throw|noexcept (")) {
|
||||
if (tok->next()->str() == "const") {
|
||||
Token::eraseTokens(tok->next(), tok->linkAt(3));
|
||||
tok = tok->next();
|
||||
} else
|
||||
Token::eraseTokens(tok, tok->linkAt(2));
|
||||
tok->deleteNext();
|
||||
} else if (Token::Match(tok, ") const| noexcept ;|{|const")) {
|
||||
if (tok->next()->str() == "const")
|
||||
tok->next()->deleteNext();
|
||||
else
|
||||
tok->deleteNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Tokenizer::validate() const
|
||||
{
|
||||
std::stack<const Token *> linktok;
|
||||
|
|
|
@ -42,6 +42,8 @@ private:
|
|||
TEST_CASE(rethrowCopy4);
|
||||
TEST_CASE(rethrowCopy5);
|
||||
TEST_CASE(catchExceptionByValue);
|
||||
TEST_CASE(noexceptThrow);
|
||||
TEST_CASE(nothrowThrow);
|
||||
}
|
||||
|
||||
void check(const char code[], bool inconclusive = false) {
|
||||
|
@ -308,6 +310,20 @@ private:
|
|||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void noexceptThrow() {
|
||||
check("void func1() noexcept { throw 1; }\n"
|
||||
"void func2() noexcept(true) { throw 1; }\n"
|
||||
"void func3() noexcept(false) { throw 1; }\n");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (error) Exception thrown in noexcept function.\n"
|
||||
"[test.cpp:2]: (error) Exception thrown in noexcept function.\n", errout.str());
|
||||
}
|
||||
|
||||
void nothrowThrow() {
|
||||
check("void func1() throw() { throw 1; }\n"
|
||||
"void func2() throw(int) { throw 1; }\n");
|
||||
ASSERT_EQUALS("[test.cpp:1]: (error) Exception thrown in throw() function.\n", errout.str());
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestExceptionSafety)
|
||||
|
|
|
@ -217,6 +217,11 @@ private:
|
|||
|
||||
TEST_CASE(findFunction1);
|
||||
TEST_CASE(findFunction2); // mismatch: parameter passed by address => reference argument
|
||||
|
||||
TEST_CASE(noexceptFunction1);
|
||||
TEST_CASE(noexceptFunction2);
|
||||
TEST_CASE(noexceptFunction3);
|
||||
TEST_CASE(noexceptFunction4);
|
||||
}
|
||||
|
||||
void array() const {
|
||||
|
@ -1980,6 +1985,104 @@ private:
|
|||
ASSERT_EQUALS(true, callfunc != nullptr); // not null
|
||||
ASSERT_EQUALS(false, (callfunc && callfunc->function())); // callfunc->function() should be null
|
||||
}
|
||||
|
||||
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \
|
||||
ASSERT_EQUALS(true, x != nullptr); \
|
||||
if (x) ASSERT_EQUALS(true, x->isNoExcept);
|
||||
|
||||
void noexceptFunction1() {
|
||||
GET_SYMBOL_DB("void func1() noexcept;\n"
|
||||
"void func2() noexcept { }\n"
|
||||
"void func3() noexcept(true);\n"
|
||||
"void func4() noexcept(true) { }\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
ASSERT_EQUALS(true, db != nullptr); // not null
|
||||
|
||||
if (db) {
|
||||
FUNC(func1);
|
||||
FUNC(func2);
|
||||
FUNC(func3);
|
||||
FUNC(func4);
|
||||
}
|
||||
}
|
||||
|
||||
void noexceptFunction2() {
|
||||
GET_SYMBOL_DB("template <class T> void self_assign(T& t) noexcept(noexcept(t = t)) {t = t; }\n");
|
||||
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
ASSERT_EQUALS(true, db != nullptr); // not null
|
||||
|
||||
if (db) {
|
||||
FUNC(self_assign);
|
||||
}
|
||||
}
|
||||
|
||||
#define CLASS_FUNC(x, y) const Function *x = findFunctionByName(#x, y); \
|
||||
ASSERT_EQUALS(true, x != nullptr); \
|
||||
if (x) ASSERT_EQUALS(true, x->isNoExcept);
|
||||
|
||||
void noexceptFunction3() {
|
||||
GET_SYMBOL_DB("struct Fred {\n"
|
||||
" void func1() noexcept;\n"
|
||||
" void func2() noexcept { }\n"
|
||||
" void func3() noexcept(true);\n"
|
||||
" void func4() noexcept(true) { }\n"
|
||||
" void func5() const noexcept;\n"
|
||||
" void func6() const noexcept { }\n"
|
||||
" void func7() const noexcept(true);\n"
|
||||
" void func8() const noexcept(true) { }\n"
|
||||
" void func9() noexcept const;\n"
|
||||
" void func10() noexcept const { }\n"
|
||||
" void func11() noexcept(true) const;\n"
|
||||
" void func12() noexcept(true) const { }\n"
|
||||
"};");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
ASSERT_EQUALS(true, db != nullptr); // not null
|
||||
|
||||
if (db) {
|
||||
const Scope *fred = db->findScopeByName("Fred");
|
||||
ASSERT_EQUALS(true, fred != nullptr);
|
||||
if (fred) {
|
||||
CLASS_FUNC(func1, fred);
|
||||
CLASS_FUNC(func2, fred);
|
||||
CLASS_FUNC(func3, fred);
|
||||
CLASS_FUNC(func4, fred);
|
||||
CLASS_FUNC(func5, fred);
|
||||
CLASS_FUNC(func6, fred);
|
||||
CLASS_FUNC(func7, fred);
|
||||
CLASS_FUNC(func8, fred);
|
||||
CLASS_FUNC(func9, fred);
|
||||
CLASS_FUNC(func10, fred);
|
||||
CLASS_FUNC(func11, fred);
|
||||
CLASS_FUNC(func12, fred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void noexceptFunction4() {
|
||||
GET_SYMBOL_DB("class A {\n"
|
||||
"public:\n"
|
||||
" A(A&& a) {\n"
|
||||
" throw std::runtime_error(\"err\");\n"
|
||||
" }\n"
|
||||
"};\n"
|
||||
"class B {\n"
|
||||
" A a;\n"
|
||||
" B(B&& b) noexcept\n"
|
||||
" :a(std::move(b.a)) { }\n"
|
||||
"};\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
ASSERT_EQUALS(true, db != nullptr); // not null
|
||||
|
||||
if (db) {
|
||||
const Scope *b = db->findScopeByName("B");
|
||||
ASSERT_EQUALS(true, b != nullptr);
|
||||
if (b) {
|
||||
CLASS_FUNC(B, b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestSymbolDatabase)
|
||||
|
|
|
@ -424,13 +424,6 @@ private:
|
|||
TEST_CASE(createLinks);
|
||||
TEST_CASE(signed1);
|
||||
|
||||
TEST_CASE(removeExceptionSpecification1);
|
||||
TEST_CASE(removeExceptionSpecification2);
|
||||
TEST_CASE(removeExceptionSpecification3);
|
||||
TEST_CASE(removeExceptionSpecification4);
|
||||
TEST_CASE(removeExceptionSpecification5);
|
||||
TEST_CASE(removeExceptionSpecification6); // #4617
|
||||
|
||||
TEST_CASE(simplifyString);
|
||||
TEST_CASE(simplifyConst);
|
||||
TEST_CASE(switchCase);
|
||||
|
@ -6860,133 +6853,6 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void removeExceptionSpecification1() {
|
||||
const char code[] = "class A\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" void f() throw (std::runtime_error);\n"
|
||||
"};\n"
|
||||
"void A::f() throw (std::runtime_error)\n"
|
||||
"{ }";
|
||||
|
||||
const char expected[] = "class A\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
"void f ( ) ;\n"
|
||||
"} ;\n"
|
||||
"void A :: f ( )\n"
|
||||
"{ }";
|
||||
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
|
||||
}
|
||||
|
||||
void removeExceptionSpecification2() {
|
||||
const char code[] = "class A\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
" int value;\n"
|
||||
"public:\n"
|
||||
" A::A() throw ()\n"
|
||||
" : value(0)\n"
|
||||
" { }\n"
|
||||
"};\n";
|
||||
|
||||
const char expected[] = "class A\n"
|
||||
"{\n"
|
||||
"private:\n"
|
||||
"int value ;\n"
|
||||
"public:\n"
|
||||
"A :: A ( )\n"
|
||||
": value ( 0 )\n"
|
||||
"{ }\n"
|
||||
"} ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
|
||||
}
|
||||
|
||||
void removeExceptionSpecification3() {
|
||||
const char code[] = "namespace A {\n"
|
||||
" struct B {\n"
|
||||
" B() throw ()\n"
|
||||
" { }\n"
|
||||
" };\n"
|
||||
"};\n";
|
||||
|
||||
const char expected[] = "namespace A {\n"
|
||||
"struct B {\n"
|
||||
"B ( )\n"
|
||||
"{ }\n"
|
||||
"} ;\n"
|
||||
"} ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
|
||||
}
|
||||
|
||||
void removeExceptionSpecification4() {
|
||||
const char code[] = "namespace {\n"
|
||||
" void B() throw ();\n"
|
||||
"};";
|
||||
|
||||
const char expected[] = "namespace {\n"
|
||||
"void B ( ) ;\n"
|
||||
"} ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
|
||||
}
|
||||
|
||||
void removeExceptionSpecification5() {
|
||||
ASSERT_EQUALS("void foo ( struct S ) ;",
|
||||
tokenizeAndStringify("void foo (struct S) throw();"));
|
||||
ASSERT_EQUALS("void foo ( struct S , int ) ;",
|
||||
tokenizeAndStringify("void foo (struct S, int) throw();"));
|
||||
ASSERT_EQUALS("void foo ( int , struct S ) ;",
|
||||
tokenizeAndStringify("void foo (int, struct S) throw();"));
|
||||
ASSERT_EQUALS("void foo ( struct S1 , struct S2 ) ;",
|
||||
tokenizeAndStringify("void foo (struct S1, struct S2) throw();"));
|
||||
}
|
||||
|
||||
void removeExceptionSpecification6() { // #4617
|
||||
ASSERT_EQUALS("void foo ( ) ;",
|
||||
tokenizeAndStringify("void foo () noexcept;"));
|
||||
ASSERT_EQUALS("void foo ( ) { }",
|
||||
tokenizeAndStringify("void foo () noexcept { }"));
|
||||
ASSERT_EQUALS("void foo ( ) ;",
|
||||
tokenizeAndStringify("void foo () noexcept(true);"));
|
||||
ASSERT_EQUALS("void foo ( ) { }",
|
||||
tokenizeAndStringify("void foo () noexcept(true) { }"));
|
||||
ASSERT_EQUALS("void foo ( ) ;",
|
||||
tokenizeAndStringify("void foo () noexcept(noexcept(true));"));
|
||||
ASSERT_EQUALS("void foo ( ) { }",
|
||||
tokenizeAndStringify("void foo () noexcept(noexcept(true)) { }"));
|
||||
|
||||
ASSERT_EQUALS("void foo ( ) const ;",
|
||||
tokenizeAndStringify("void foo () const noexcept;"));
|
||||
ASSERT_EQUALS("void foo ( ) const { }",
|
||||
tokenizeAndStringify("void foo () const noexcept { }"));
|
||||
ASSERT_EQUALS("void foo ( ) const ;",
|
||||
tokenizeAndStringify("void foo () const noexcept(true);"));
|
||||
ASSERT_EQUALS("void foo ( ) const { }",
|
||||
tokenizeAndStringify("void foo () const noexcept(true) { }"));
|
||||
ASSERT_EQUALS("void foo ( ) const ;",
|
||||
tokenizeAndStringify("void foo () const noexcept(noexcept(true));"));
|
||||
ASSERT_EQUALS("void foo ( ) const { }",
|
||||
tokenizeAndStringify("void foo () const noexcept(noexcept(true)) { }"));
|
||||
|
||||
ASSERT_EQUALS("void foo ( ) const ;",
|
||||
tokenizeAndStringify("void foo () noexcept const;"));
|
||||
ASSERT_EQUALS("void foo ( ) const { }",
|
||||
tokenizeAndStringify("void foo () noexcept const { }"));
|
||||
ASSERT_EQUALS("void foo ( ) const ;",
|
||||
tokenizeAndStringify("void foo () noexcept(true) const;"));
|
||||
ASSERT_EQUALS("void foo ( ) const { }",
|
||||
tokenizeAndStringify("void foo () noexcept(true) const { }"));
|
||||
ASSERT_EQUALS("void foo ( ) const ;",
|
||||
tokenizeAndStringify("void foo () noexcept(noexcept(true)) const;"));
|
||||
ASSERT_EQUALS("void foo ( ) const { }",
|
||||
tokenizeAndStringify("void foo () noexcept(noexcept(true)) const { }"));
|
||||
}
|
||||
|
||||
|
||||
void simplifyString() {
|
||||
errout.str("");
|
||||
Settings settings;
|
||||
|
|
Loading…
Reference in New Issue