Improve check: Warn about virtual function calls in constructor/destructor
This commit is contained in:
parent
e492932f19
commit
1046ca2120
|
@ -64,11 +64,6 @@ static const char * getFunctionTypeName(Function::Type type)
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isPureWithoutBody(Function const & func)
|
|
||||||
{
|
|
||||||
return func.isPure() && !func.hasBody();
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
|
CheckClass::CheckClass(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
|
||||||
|
@ -2200,15 +2195,15 @@ void CheckClass::selfInitializationError(const Token* tok, const std::string& va
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
// Check for pure virtual function calls
|
// Check for virtual function calls in constructor/destructor
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
void CheckClass::checkPureVirtualFunctionCall()
|
void CheckClass::checkVirtualFunctionCallInConstructor()
|
||||||
{
|
{
|
||||||
if (! _settings->isEnabled(Settings::WARNING))
|
if (! _settings->isEnabled(Settings::WARNING))
|
||||||
return;
|
return;
|
||||||
const std::size_t functions = symbolDatabase->functionScopes.size();
|
const std::size_t functions = symbolDatabase->functionScopes.size();
|
||||||
std::map<const Function *, std::list<const Token *> > callsPureVirtualFunctionMap;
|
std::map<const Function *, std::list<const Token *> > virtualFunctionCallsMap;
|
||||||
for (std::size_t i = 0; i < functions; ++i) {
|
for (std::size_t i = 0; i < functions; ++i) {
|
||||||
const Scope * scope = symbolDatabase->functionScopes[i];
|
const Scope * scope = symbolDatabase->functionScopes[i];
|
||||||
if (scope->function == nullptr || !scope->function->hasBody() ||
|
if (scope->function == nullptr || !scope->function->hasBody() ||
|
||||||
|
@ -2216,106 +2211,127 @@ void CheckClass::checkPureVirtualFunctionCall()
|
||||||
scope->function->isDestructor()))
|
scope->function->isDestructor()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const std::list<const Token *> & pureVirtualFunctionCalls=callsPureVirtualFunction(*scope->function,callsPureVirtualFunctionMap);
|
const std::list<const Token *> & virtualFunctionCalls = getVirtualFunctionCalls(*scope->function, virtualFunctionCallsMap);
|
||||||
for (std::list<const Token *>::const_iterator pureCallIter=pureVirtualFunctionCalls.begin();
|
for (std::list<const Token *>::const_iterator it = virtualFunctionCalls.begin(); it != virtualFunctionCalls.end(); ++it) {
|
||||||
pureCallIter!=pureVirtualFunctionCalls.end();
|
const Token * callToken = *it;
|
||||||
++pureCallIter) {
|
std::list<const Token *> callstack;
|
||||||
const Token & pureCall=**pureCallIter;
|
callstack.push_back(callToken);
|
||||||
std::list<const Token *> pureFuncStack;
|
getFirstVirtualFunctionCallStack(virtualFunctionCallsMap, callToken, callstack);
|
||||||
pureFuncStack.push_back(&pureCall);
|
if (callstack.empty())
|
||||||
getFirstPureVirtualFunctionCallStack(callsPureVirtualFunctionMap, pureCall, pureFuncStack);
|
continue;
|
||||||
if (!pureFuncStack.empty())
|
if (callstack.back()->function()->isPure())
|
||||||
callsPureVirtualFunctionError(*scope->function, pureFuncStack, pureFuncStack.back()->str());
|
pureVirtualFunctionCallInConstructorError(scope->function, callstack, callstack.back()->str());
|
||||||
|
else
|
||||||
|
virtualFunctionCallInConstructorError(scope->function, callstack, callstack.back()->str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::list<const Token *> & CheckClass::callsPureVirtualFunction(const Function & function,
|
const std::list<const Token *> & CheckClass::getVirtualFunctionCalls(const Function & function,
|
||||||
std::map<const Function *, std::list<const Token *> > & callsPureVirtualFunctionMap)
|
std::map<const Function *, std::list<const Token *> > & virtualFunctionCallsMap)
|
||||||
{
|
{
|
||||||
std::pair<std::map<const Function *, std::list<const Token *> >::iterator, bool > found =
|
const std::map<const Function *, std::list<const Token *> >::const_iterator found = virtualFunctionCallsMap.find(&function);
|
||||||
callsPureVirtualFunctionMap.insert(std::pair<const Function *, std::list< const Token *> >(&function, std::list<const Token *>()));
|
if (found != virtualFunctionCallsMap.end())
|
||||||
std::list<const Token *> & pureFunctionCalls = found.first->second;
|
return found->second;
|
||||||
if (found.second) {
|
|
||||||
if (function.hasBody()) {
|
|
||||||
for (const Token *tok = function.arg->link();
|
|
||||||
tok && tok != function.functionScope->classEnd;
|
|
||||||
tok = tok->next()) {
|
|
||||||
if (function.type != Function::eConstructor &&
|
|
||||||
function.type != Function::eCopyConstructor &&
|
|
||||||
function.type != Function::eMoveConstructor &&
|
|
||||||
function.type != Function::eDestructor) {
|
|
||||||
if ((Token::simpleMatch(tok, ") {") &&
|
|
||||||
tok->link() &&
|
|
||||||
Token::Match(tok->link()->previous(), "if|switch")) ||
|
|
||||||
Token::simpleMatch(tok, "else {")
|
|
||||||
) {
|
|
||||||
// Assume pure virtual function call is prevented by "if|else|switch" condition
|
|
||||||
tok = tok->linkAt(1);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tok->scope()->type == Scope::eLambda)
|
|
||||||
tok = tok->scope()->classEnd->next();
|
|
||||||
|
|
||||||
const Function * callFunction = tok->function();
|
virtualFunctionCallsMap[&function] = std::list<const Token *>();
|
||||||
if (!callFunction ||
|
std::list<const Token *> & virtualFunctionCalls = virtualFunctionCallsMap.find(&function)->second;
|
||||||
function.nestedIn != callFunction->nestedIn ||
|
|
||||||
(tok->previous() && tok->previous()->str() == "."))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (tok->previous() &&
|
if (!function.hasBody())
|
||||||
tok->previous()->str() == "(") {
|
return virtualFunctionCalls;
|
||||||
const Token * prev = tok->previous();
|
|
||||||
if (prev->previous() &&
|
|
||||||
(_settings->library.ignorefunction(tok->str())
|
|
||||||
|| _settings->library.ignorefunction(prev->previous()->str())))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isPureWithoutBody(*callFunction)) {
|
for (const Token *tok = function.arg->link(); tok != function.functionScope->classEnd; tok = tok->next()) {
|
||||||
pureFunctionCalls.push_back(tok);
|
if (function.type != Function::eConstructor &&
|
||||||
continue;
|
function.type != Function::eCopyConstructor &&
|
||||||
}
|
function.type != Function::eMoveConstructor &&
|
||||||
|
function.type != Function::eDestructor) {
|
||||||
const std::list<const Token *> & pureFunctionCallsOfTok = callsPureVirtualFunction(*callFunction,
|
if ((Token::simpleMatch(tok, ") {") && tok->link() && Token::Match(tok->link()->previous(), "if|switch")) ||
|
||||||
callsPureVirtualFunctionMap);
|
Token::simpleMatch(tok, "else {")) {
|
||||||
if (!pureFunctionCallsOfTok.empty()) {
|
// Assume pure virtual function call is prevented by "if|else|switch" condition
|
||||||
pureFunctionCalls.push_back(tok);
|
tok = tok->linkAt(1);
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (tok->scope()->type == Scope::eLambda)
|
||||||
|
tok = tok->scope()->classEnd->next();
|
||||||
|
|
||||||
|
const Function * callFunction = tok->function();
|
||||||
|
if (!callFunction ||
|
||||||
|
function.nestedIn != callFunction->nestedIn ||
|
||||||
|
(tok->previous() && tok->previous()->str() == "."))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (tok->previous() &&
|
||||||
|
tok->previous()->str() == "(") {
|
||||||
|
const Token * prev = tok->previous();
|
||||||
|
if (prev->previous() &&
|
||||||
|
(_settings->library.ignorefunction(tok->str())
|
||||||
|
|| _settings->library.ignorefunction(prev->previous()->str())))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callFunction->isVirtual()) {
|
||||||
|
virtualFunctionCalls.push_back(tok);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::list<const Token *> & virtualFunctionCallsOfTok = getVirtualFunctionCalls(*callFunction, virtualFunctionCallsMap);
|
||||||
|
if (!virtualFunctionCallsOfTok.empty())
|
||||||
|
virtualFunctionCalls.push_back(tok);
|
||||||
}
|
}
|
||||||
return pureFunctionCalls;
|
return virtualFunctionCalls;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckClass::getFirstPureVirtualFunctionCallStack(
|
void CheckClass::getFirstVirtualFunctionCallStack(
|
||||||
std::map<const Function *, std::list<const Token *> > & callsPureVirtualFunctionMap,
|
std::map<const Function *, std::list<const Token *> > & virtualFunctionCallsMap,
|
||||||
const Token & pureCall,
|
const Token * callToken,
|
||||||
std::list<const Token *> & pureFuncStack)
|
std::list<const Token *> & callstack)
|
||||||
{
|
{
|
||||||
if (isPureWithoutBody(*pureCall.function())) {
|
const Function *callFunction = callToken->function();
|
||||||
pureFuncStack.push_back(pureCall.function()->token);
|
if (callFunction->isVirtual() && (!callFunction->isPure() || !callFunction->hasBody())) {
|
||||||
|
callstack.push_back(callFunction->token);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::map<const Function *, std::list<const Token *> >::const_iterator found = callsPureVirtualFunctionMap.find(pureCall.function());
|
std::map<const Function *, std::list<const Token *> >::const_iterator found = virtualFunctionCallsMap.find(callFunction);
|
||||||
if (found == callsPureVirtualFunctionMap.end() ||
|
if (found == virtualFunctionCallsMap.end() || found->second.empty()) {
|
||||||
found->second.empty()) {
|
callstack.clear();
|
||||||
pureFuncStack.clear();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const Token & firstPureCall = **found->second.begin();
|
const Token * firstCall = *found->second.begin();
|
||||||
pureFuncStack.push_back(&firstPureCall);
|
callstack.push_back(firstCall);
|
||||||
getFirstPureVirtualFunctionCallStack(callsPureVirtualFunctionMap, firstPureCall, pureFuncStack);
|
getFirstVirtualFunctionCallStack(virtualFunctionCallsMap, firstCall, callstack);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckClass::callsPureVirtualFunctionError(
|
void CheckClass::virtualFunctionCallInConstructorError(
|
||||||
const Function & scopeFunction,
|
const Function * scopeFunction,
|
||||||
|
const std::list<const Token *> & tokStack,
|
||||||
|
const std::string &funcname)
|
||||||
|
{
|
||||||
|
const char * scopeFunctionTypeName = scopeFunction ? getFunctionTypeName(scopeFunction->type) : "constructor";
|
||||||
|
|
||||||
|
ErrorPath errorPath;
|
||||||
|
for (std::list<const Token *>::const_iterator it = tokStack.begin(); it != tokStack.end(); ++it)
|
||||||
|
errorPath.push_back(ErrorPathItem(*it, "Calling " + (*it)->str()));
|
||||||
|
if (!errorPath.empty())
|
||||||
|
errorPath.back().second = funcname + " is a virtual method";
|
||||||
|
|
||||||
|
reportError(errorPath, Severity::warning, "virtualCallInConstructor", "Call of virtual function '" + funcname + "' in " + scopeFunctionTypeName + ".\n"
|
||||||
|
"Call of pure virtual function '" + funcname + "' in " + scopeFunctionTypeName + ". Dynamic binding is not used.", CWE(0U), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckClass::pureVirtualFunctionCallInConstructorError(
|
||||||
|
const Function * scopeFunction,
|
||||||
const std::list<const Token *> & tokStack,
|
const std::list<const Token *> & tokStack,
|
||||||
const std::string &purefuncname)
|
const std::string &purefuncname)
|
||||||
{
|
{
|
||||||
const char * scopeFunctionTypeName = getFunctionTypeName(scopeFunction.type);
|
const char * scopeFunctionTypeName = scopeFunction ? getFunctionTypeName(scopeFunction->type) : "constructor";
|
||||||
|
|
||||||
|
ErrorPath errorPath;
|
||||||
|
for (std::list<const Token *>::const_iterator it = tokStack.begin(); it != tokStack.end(); ++it)
|
||||||
|
errorPath.push_back(ErrorPathItem(*it, "Calling " + (*it)->str()));
|
||||||
|
if (!errorPath.empty())
|
||||||
|
errorPath.back().second = purefuncname + " is a pure virtual method without body";
|
||||||
|
|
||||||
reportError(tokStack, Severity::warning, "pureVirtualCall", "Call of pure virtual function '" + purefuncname + "' in " + scopeFunctionTypeName + ".\n"
|
reportError(tokStack, Severity::warning, "pureVirtualCall", "Call of pure virtual function '" + purefuncname + "' in " + scopeFunctionTypeName + ".\n"
|
||||||
"Call of pure virtual function '" + purefuncname + "' in " + scopeFunctionTypeName + ". The call will fail during runtime.", CWE(0U), false);
|
"Call of pure virtual function '" + purefuncname + "' in " + scopeFunctionTypeName + ". The call will fail during runtime.", CWE(0U), false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ public:
|
||||||
checkClass.virtualDestructor();
|
checkClass.virtualDestructor();
|
||||||
checkClass.checkConst();
|
checkClass.checkConst();
|
||||||
checkClass.copyconstructors();
|
checkClass.copyconstructors();
|
||||||
checkClass.checkPureVirtualFunctionCall();
|
checkClass.checkVirtualFunctionCallInConstructor();
|
||||||
|
|
||||||
checkClass.checkDuplInheritedMembers();
|
checkClass.checkDuplInheritedMembers();
|
||||||
checkClass.checkExplicitConstructors();
|
checkClass.checkExplicitConstructors();
|
||||||
|
@ -143,8 +143,8 @@ public:
|
||||||
|
|
||||||
void copyconstructors();
|
void copyconstructors();
|
||||||
|
|
||||||
/** @brief call of pure virtual function */
|
/** @brief call of virtual function in constructor/destructor */
|
||||||
void checkPureVirtualFunctionCall();
|
void checkVirtualFunctionCallInConstructor();
|
||||||
|
|
||||||
/** @brief Check duplicated inherited members */
|
/** @brief Check duplicated inherited members */
|
||||||
void checkDuplInheritedMembers();
|
void checkDuplInheritedMembers();
|
||||||
|
@ -184,7 +184,8 @@ private:
|
||||||
void initializerListError(const Token *tok1,const Token *tok2, const std::string & classname, const std::string &varname);
|
void initializerListError(const Token *tok1,const Token *tok2, const std::string & classname, const std::string &varname);
|
||||||
void suggestInitializationList(const Token *tok, const std::string& varname);
|
void suggestInitializationList(const Token *tok, const std::string& varname);
|
||||||
void selfInitializationError(const Token* tok, const std::string& varname);
|
void selfInitializationError(const Token* tok, const std::string& varname);
|
||||||
void callsPureVirtualFunctionError(const Function & scopeFunction, const std::list<const Token *> & tokStack, const std::string &purefuncname);
|
void pureVirtualFunctionCallInConstructorError(const Function * scopeFunction, const std::list<const Token *> & tokStack, const std::string &purefuncname);
|
||||||
|
void virtualFunctionCallInConstructorError(const Function * scopeFunction, const std::list<const Token *> & tokStack, const std::string &funcname);
|
||||||
void duplInheritedMembersError(const Token* tok1, const Token* tok2, const std::string &derivedname, const std::string &basename, const std::string &variablename, bool derivedIsStruct, bool baseIsStruct);
|
void duplInheritedMembersError(const Token* tok1, const Token* tok2, const std::string &derivedname, const std::string &basename, const std::string &variablename, bool derivedIsStruct, bool baseIsStruct);
|
||||||
void copyCtorAndEqOperatorError(const Token *tok, const std::string &classname, bool isStruct, bool hasCopyCtor);
|
void copyCtorAndEqOperatorError(const Token *tok, const std::string &classname, bool isStruct, bool hasCopyCtor);
|
||||||
void unsafeClassDivZeroError(const Token *tok, const std::string &className, const std::string &methodName, const std::string &varName);
|
void unsafeClassDivZeroError(const Token *tok, const std::string &className, const std::string &methodName, const std::string &varName);
|
||||||
|
@ -219,6 +220,8 @@ private:
|
||||||
c.duplInheritedMembersError(nullptr, nullptr, "class", "class", "variable", false, false);
|
c.duplInheritedMembersError(nullptr, nullptr, "class", "class", "variable", false, false);
|
||||||
c.copyCtorAndEqOperatorError(nullptr, "class", false, false);
|
c.copyCtorAndEqOperatorError(nullptr, "class", false, false);
|
||||||
c.unsafeClassDivZeroError(nullptr, "Class", "dostuff", "x");
|
c.unsafeClassDivZeroError(nullptr, "Class", "dostuff", "x");
|
||||||
|
c.pureVirtualFunctionCallInConstructorError(nullptr, std::list<const Token *>(), "f");
|
||||||
|
c.virtualFunctionCallInConstructorError(nullptr, std::list<const Token *>(), "f");
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string myName() {
|
static std::string myName() {
|
||||||
|
@ -317,22 +320,22 @@ private:
|
||||||
/**
|
/**
|
||||||
* @brief gives a list of tokens where pure virtual functions are called directly or indirectly
|
* @brief gives a list of tokens where pure virtual functions are called directly or indirectly
|
||||||
* @param function function to be checked
|
* @param function function to be checked
|
||||||
* @param callsPureVirtualFunctionMap map of results for already checked functions
|
* @param virtualFunctionCallsMap map of results for already checked functions
|
||||||
* @return list of tokens where pure virtual functions are called
|
* @return list of tokens where pure virtual functions are called
|
||||||
*/
|
*/
|
||||||
const std::list<const Token *> & callsPureVirtualFunction(
|
const std::list<const Token *> & getVirtualFunctionCalls(
|
||||||
const Function & function,
|
const Function & function,
|
||||||
std::map<const Function *, std::list<const Token *> > & callsPureVirtualFunctionMap);
|
std::map<const Function *, std::list<const Token *> > & virtualFunctionCallsMap);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief looks for the first pure virtual function call stack
|
* @brief looks for the first pure virtual function call stack
|
||||||
* @param callsPureVirtualFunctionMap map of results obtained from callsPureVirtualFunction
|
* @param virtualFunctionCallsMap map of results obtained from getVirtualFunctionCalls
|
||||||
* @param pureCall token where pure virtual function is called directly or indirectly
|
* @param callToken token where pure virtual function is called directly or indirectly
|
||||||
* @param[in,out] pureFuncStack list to append the stack
|
* @param[in,out] pureFuncStack list to append the stack
|
||||||
*/
|
*/
|
||||||
void getFirstPureVirtualFunctionCallStack(
|
void getFirstVirtualFunctionCallStack(
|
||||||
std::map<const Function *, std::list<const Token *> > & callsPureVirtualFunctionMap,
|
std::map<const Function *, std::list<const Token *> > & virtualFunctionCallsMap,
|
||||||
const Token & pureCall,
|
const Token *callToken,
|
||||||
std::list<const Token *> & pureFuncStack);
|
std::list<const Token *> & pureFuncStack);
|
||||||
|
|
||||||
static bool canNotCopy(const Scope *scope);
|
static bool canNotCopy(const Scope *scope);
|
||||||
|
|
|
@ -180,6 +180,7 @@ private:
|
||||||
TEST_CASE(initializerListUsage);
|
TEST_CASE(initializerListUsage);
|
||||||
TEST_CASE(selfInitialization);
|
TEST_CASE(selfInitialization);
|
||||||
|
|
||||||
|
TEST_CASE(virtualFunctionCallInConstructor);
|
||||||
TEST_CASE(pureVirtualFunctionCall);
|
TEST_CASE(pureVirtualFunctionCall);
|
||||||
TEST_CASE(pureVirtualFunctionCallOtherClass);
|
TEST_CASE(pureVirtualFunctionCallOtherClass);
|
||||||
TEST_CASE(pureVirtualFunctionCallWithBody);
|
TEST_CASE(pureVirtualFunctionCallWithBody);
|
||||||
|
@ -6297,7 +6298,7 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkPureVirtualFunctionCall(const char code[], Settings *s = 0, bool inconclusive = true) {
|
void checkVirtualFunctionCall(const char code[], Settings *s = 0, bool inconclusive = true) {
|
||||||
// Clear the error log
|
// Clear the error log
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
|
@ -6316,200 +6317,211 @@ private:
|
||||||
tokenizer.simplifyTokenList2();
|
tokenizer.simplifyTokenList2();
|
||||||
|
|
||||||
CheckClass checkClass(&tokenizer, s, this);
|
CheckClass checkClass(&tokenizer, s, this);
|
||||||
checkClass.checkPureVirtualFunctionCall();
|
checkClass.checkVirtualFunctionCallInConstructor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void virtualFunctionCallInConstructor() {
|
||||||
|
checkVirtualFunctionCall("class A\n"
|
||||||
|
"{\n"
|
||||||
|
" virtual int f() { return 1; }\n"
|
||||||
|
" A();\n"
|
||||||
|
"};\n"
|
||||||
|
"A::A()\n"
|
||||||
|
"{f();}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:3]: (warning) Call of virtual function 'f' in constructor.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void pureVirtualFunctionCall() {
|
void pureVirtualFunctionCall() {
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
" A();\n"
|
" A();\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A()\n"
|
"A::A()\n"
|
||||||
"{pure();}\n");
|
"{pure();}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" virtual int pure()=0;\n"
|
" virtual int pure()=0;\n"
|
||||||
" A();\n"
|
" A();\n"
|
||||||
" int m;\n"
|
" int m;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A():m(A::pure())\n"
|
"A::A():m(A::pure())\n"
|
||||||
"{}\n");
|
"{}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" virtual void pure()=0; \n"
|
" virtual void pure()=0; \n"
|
||||||
" virtual ~A(); \n"
|
" virtual ~A(); \n"
|
||||||
" int m; \n"
|
" int m; \n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::~A()\n"
|
"A::~A()\n"
|
||||||
"{pure();}\n");
|
"{pure();}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor.\n", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
" void nonpure()\n"
|
" void nonpure()\n"
|
||||||
" {pure();}\n"
|
" {pure();}\n"
|
||||||
" A(); \n"
|
" A(); \n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A()\n"
|
"A::A()\n"
|
||||||
"{nonpure();}\n");
|
"{nonpure();}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:5] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:5] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" virtual int pure()=0;\n"
|
" virtual int pure()=0;\n"
|
||||||
" int nonpure()\n"
|
" int nonpure()\n"
|
||||||
" {return pure();}\n"
|
" {return pure();}\n"
|
||||||
" A(); \n"
|
" A(); \n"
|
||||||
" int m;\n"
|
" int m;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A():m(nonpure())\n"
|
"A::A():m(nonpure())\n"
|
||||||
"{}\n");
|
"{}\n");
|
||||||
TODO_ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:5] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", "", errout.str());
|
TODO_ASSERT_EQUALS("[test.cpp:9] -> [test.cpp:5] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", "", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" virtual void pure()=0; \n"
|
" virtual void pure()=0; \n"
|
||||||
" void nonpure()\n"
|
" void nonpure()\n"
|
||||||
" {pure();}\n"
|
" {pure();}\n"
|
||||||
" virtual ~A();\n"
|
" virtual ~A();\n"
|
||||||
" int m;\n"
|
" int m;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::~A()\n"
|
"A::~A()\n"
|
||||||
"{nonpure();}\n");
|
"{nonpure();}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:10] -> [test.cpp:5] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:10] -> [test.cpp:5] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor.\n", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
" A(bool b);\n"
|
" A(bool b);\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A(bool b)\n"
|
"A::A(bool b)\n"
|
||||||
"{if (b) pure();}\n");
|
"{if (b) pure();}\n");
|
||||||
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:7] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in constructor.\n", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
" virtual ~A();\n"
|
" virtual ~A();\n"
|
||||||
" int m;\n"
|
" int m;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::~A()\n"
|
"A::~A()\n"
|
||||||
"{if (b) pure();}");
|
"{if (b) pure();}");
|
||||||
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:8] -> [test.cpp:3]: (warning) Call of pure virtual function 'pure' in destructor.\n", errout.str());
|
||||||
|
|
||||||
// #5831
|
// #5831
|
||||||
checkPureVirtualFunctionCall("class abc {\n"
|
checkVirtualFunctionCall("class abc {\n"
|
||||||
"public:\n"
|
"public:\n"
|
||||||
" virtual ~abc() throw() {}\n"
|
" virtual ~abc() throw() {}\n"
|
||||||
" virtual void def(void* g) throw () = 0;\n"
|
" virtual void def(void* g) throw () = 0;\n"
|
||||||
"};");
|
"};");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
// #4992
|
// #4992
|
||||||
checkPureVirtualFunctionCall("class CMyClass {\n"
|
checkVirtualFunctionCall("class CMyClass {\n"
|
||||||
" std::function< void(void) > m_callback;\n"
|
" std::function< void(void) > m_callback;\n"
|
||||||
"public:\n"
|
"public:\n"
|
||||||
" CMyClass() {\n"
|
" CMyClass() {\n"
|
||||||
" m_callback = [this]() { return VirtualMethod(); };\n"
|
" m_callback = [this]() { return VirtualMethod(); };\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" virtual void VirtualMethod() = 0;\n"
|
" virtual void VirtualMethod() = 0;\n"
|
||||||
"};");
|
"};");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void pureVirtualFunctionCallOtherClass() {
|
void pureVirtualFunctionCallOtherClass() {
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
" A(const A & a);\n"
|
" A(const A & a);\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A(const A & a)\n"
|
"A::A(const A & a)\n"
|
||||||
"{a.pure();}\n");
|
"{a.pure();}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
" A();\n"
|
" A();\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"class B\n"
|
"class B\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A()\n"
|
"A::A()\n"
|
||||||
"{B b; b.pure();}\n");
|
"{B b; b.pure();}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void pureVirtualFunctionCallWithBody() {
|
void pureVirtualFunctionCallWithBody() {
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
"{\n"
|
"{\n"
|
||||||
" virtual void pureWithBody()=0;\n"
|
" virtual void pureWithBody()=0;\n"
|
||||||
" A();\n"
|
" A();\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A()\n"
|
"A::A()\n"
|
||||||
"{pureWithBody();}\n"
|
"{pureWithBody();}\n"
|
||||||
"void A::pureWithBody()\n"
|
"void A::pureWithBody()\n"
|
||||||
"{}\n");
|
"{}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" virtual void pureWithBody()=0;\n"
|
" virtual void pureWithBody()=0;\n"
|
||||||
" void nonpure()\n"
|
" void nonpure()\n"
|
||||||
" {pureWithBody();}\n"
|
" {pureWithBody();}\n"
|
||||||
" A(); \n"
|
" A(); \n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A()\n"
|
"A::A()\n"
|
||||||
"{nonpure();}\n"
|
"{nonpure();}\n"
|
||||||
"void A::pureWithBody()\n"
|
"void A::pureWithBody()\n"
|
||||||
"{}\n");
|
"{}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pureVirtualFunctionCallPrevented() {
|
void pureVirtualFunctionCallPrevented() {
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
" void nonpure(bool bCallPure)\n"
|
" void nonpure(bool bCallPure)\n"
|
||||||
" { if (bCallPure) pure();}\n"
|
" { if (bCallPure) pure();}\n"
|
||||||
" A(); \n"
|
" A(); \n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A()\n"
|
"A::A()\n"
|
||||||
"{nonpure(false);}\n");
|
"{nonpure(false);}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
" void nonpure(bool bCallPure)\n"
|
" void nonpure(bool bCallPure)\n"
|
||||||
" { if (!bCallPure) ; else pure();}\n"
|
" { if (!bCallPure) ; else pure();}\n"
|
||||||
" A(); \n"
|
" A(); \n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A()\n"
|
"A::A()\n"
|
||||||
"{nonpure(false);}\n");
|
"{nonpure(false);}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
checkPureVirtualFunctionCall("class A\n"
|
checkVirtualFunctionCall("class A\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" virtual void pure()=0;\n"
|
" virtual void pure()=0;\n"
|
||||||
" void nonpure(bool bCallPure)\n"
|
" void nonpure(bool bCallPure)\n"
|
||||||
" {\n"
|
" {\n"
|
||||||
" switch (bCallPure) {\n"
|
" switch (bCallPure) {\n"
|
||||||
" case true: pure(); break;\n"
|
" case true: pure(); break;\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" }\n"
|
" }\n"
|
||||||
" A(); \n"
|
" A(); \n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"A::A()\n"
|
"A::A()\n"
|
||||||
"{nonpure(false);}\n");
|
"{nonpure(false);}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue