Implemented support for rvalue references (C++11):
- Split up && when it is part of an rvalue reference declaration - Added support into symbol database - Current implementation sets Variable::isReference() to true also for rvalue references - they can probably be treated like normal references in many checks. Changed behaviour of symbol database: Insert argument Variable of functions that are not implemented into SymbolDatabase::_variableList
This commit is contained in:
parent
ba8cca8fa9
commit
188096665c
|
@ -839,10 +839,6 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
// add all function parameters
|
// add all function parameters
|
||||||
std::list<Function>::const_iterator func;
|
std::list<Function>::const_iterator func;
|
||||||
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
|
for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) {
|
||||||
// ignore function without implementations
|
|
||||||
if (!func->hasBody)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::list<Variable>::const_iterator arg;
|
std::list<Variable>::const_iterator arg;
|
||||||
for (arg = func->argumentList.begin(); arg != func->argumentList.end(); ++arg) {
|
for (arg = func->argumentList.begin(); arg != func->argumentList.end(); ++arg) {
|
||||||
// check for named parameters
|
// check for named parameters
|
||||||
|
@ -997,8 +993,14 @@ void Variable::evaluate()
|
||||||
else if (tok->str() == "*") {
|
else if (tok->str() == "*") {
|
||||||
setFlag(fIsPointer, true);
|
setFlag(fIsPointer, true);
|
||||||
setFlag(fIsConst, false); // Points to const, isn't necessarily const itself
|
setFlag(fIsConst, false); // Points to const, isn't necessarily const itself
|
||||||
} else if (tok->str() == "&")
|
} else if (tok->str() == "&") {
|
||||||
|
if (isReference())
|
||||||
|
setFlag(fIsRValueRef, true);
|
||||||
setFlag(fIsReference, true);
|
setFlag(fIsReference, true);
|
||||||
|
} else if (tok->str() == "&&") { // Before simplification, && isn't split up
|
||||||
|
setFlag(fIsRValueRef, true);
|
||||||
|
setFlag(fIsReference, true); // Set also fIsReference
|
||||||
|
}
|
||||||
|
|
||||||
if (tok->str() == "<")
|
if (tok->str() == "<")
|
||||||
tok->findClosingBracket(tok);
|
tok->findClosingBracket(tok);
|
||||||
|
@ -1567,6 +1569,7 @@ void SymbolDatabase::printVariable(const Variable *var, const char *indent) cons
|
||||||
std::cout << indent << " isArray: " << (var->isArray() ? "true" : "false") << std::endl;
|
std::cout << indent << " isArray: " << (var->isArray() ? "true" : "false") << std::endl;
|
||||||
std::cout << indent << " isPointer: " << (var->isPointer() ? "true" : "false") << std::endl;
|
std::cout << indent << " isPointer: " << (var->isPointer() ? "true" : "false") << std::endl;
|
||||||
std::cout << indent << " isReference: " << (var->isReference() ? "true" : "false") << std::endl;
|
std::cout << indent << " isReference: " << (var->isReference() ? "true" : "false") << std::endl;
|
||||||
|
std::cout << indent << " isRValueRef: " << (var->isRValueReference() ? "true" : "false") << std::endl;
|
||||||
std::cout << indent << " hasDefault: " << (var->hasDefault() ? "true" : "false") << std::endl;
|
std::cout << indent << " hasDefault: " << (var->hasDefault() ? "true" : "false") << std::endl;
|
||||||
std::cout << indent << "_type: ";
|
std::cout << indent << "_type: ";
|
||||||
if (var->type()) {
|
if (var->type()) {
|
||||||
|
@ -2281,7 +2284,7 @@ static const Token* skipScopeIdentifiers(const Token* tok)
|
||||||
|
|
||||||
static const Token* skipPointers(const Token* tok)
|
static const Token* skipPointers(const Token* tok)
|
||||||
{
|
{
|
||||||
while (Token::Match(tok, "*|&")) {
|
while (Token::Match(tok, "*|&|&&")) {
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,8 @@ class CPPCHECKLIB Variable {
|
||||||
fIsArray = (1 << 5), /** @brief array variable */
|
fIsArray = (1 << 5), /** @brief array variable */
|
||||||
fIsPointer = (1 << 6), /** @brief pointer variable */
|
fIsPointer = (1 << 6), /** @brief pointer variable */
|
||||||
fIsReference = (1 << 7), /** @brief reference variable */
|
fIsReference = (1 << 7), /** @brief reference variable */
|
||||||
fHasDefault = (1 << 8) /** @brief function argument with default value */
|
fIsRValueRef = (1 << 8), /** @brief rvalue reference variable */
|
||||||
|
fHasDefault = (1 << 9) /** @brief function argument with default value */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -341,6 +342,14 @@ public:
|
||||||
return getFlag(fIsReference);
|
return getFlag(fIsReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is reference variable.
|
||||||
|
* @return true if reference, false otherwise
|
||||||
|
*/
|
||||||
|
bool isRValueReference() const {
|
||||||
|
return getFlag(fIsRValueRef);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does variable have a default value.
|
* Does variable have a default value.
|
||||||
* @return true if has a default falue, false if not
|
* @return true if has a default falue, false if not
|
||||||
|
|
|
@ -1964,10 +1964,21 @@ bool Tokenizer::tokenize(std::istream &code,
|
||||||
|
|
||||||
simplifyEmptyNamespaces();
|
simplifyEmptyNamespaces();
|
||||||
|
|
||||||
bool valid = validate();
|
if (!validate())
|
||||||
if (valid)
|
return false;
|
||||||
createSymbolDatabase();
|
|
||||||
return valid;
|
createSymbolDatabase();
|
||||||
|
|
||||||
|
// Use symbol database to identify rvalue references. Split && to & &. This is safe, since it doesn't delete any tokens (which might be referenced by symbol database)
|
||||||
|
for (std::size_t i = 0; i < _symbolDatabase->getVariableListSize(); i++) {
|
||||||
|
const Variable* var = _symbolDatabase->getVariableFromVarId(i);
|
||||||
|
if (var && var->isRValueReference()) {
|
||||||
|
const_cast<Token*>(var->typeEndToken())->str("&");
|
||||||
|
const_cast<Token*>(var->typeEndToken())->insertToken("&");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -2555,7 +2566,7 @@ static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::stri
|
||||||
bool ok = tok2->findClosingBracket(tok2);
|
bool ok = tok2->findClosingBracket(tok2);
|
||||||
if (!ok || !tok2)
|
if (!ok || !tok2)
|
||||||
break;
|
break;
|
||||||
} else if (tok2->str() == "&") {
|
} else if (tok2->str() == "&" || tok2->str() == "&&") {
|
||||||
ref = true;
|
ref = true;
|
||||||
} else if (tok2->str() != "*" && tok2->str() != "::") {
|
} else if (tok2->str() != "*" && tok2->str() != "::") {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -118,6 +118,7 @@ private:
|
||||||
TEST_CASE(isVariableDeclarationIdentifiesReference);
|
TEST_CASE(isVariableDeclarationIdentifiesReference);
|
||||||
TEST_CASE(isVariableDeclarationDoesNotIdentifyTemplateClass);
|
TEST_CASE(isVariableDeclarationDoesNotIdentifyTemplateClass);
|
||||||
TEST_CASE(isVariableDeclarationPointerConst);
|
TEST_CASE(isVariableDeclarationPointerConst);
|
||||||
|
TEST_CASE(isVariableDeclarationRValueRef);
|
||||||
|
|
||||||
TEST_CASE(staticMemberVar);
|
TEST_CASE(staticMemberVar);
|
||||||
|
|
||||||
|
@ -527,6 +528,18 @@ private:
|
||||||
ASSERT(false == v.isReference());
|
ASSERT(false == v.isReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void isVariableDeclarationRValueRef() {
|
||||||
|
reset();
|
||||||
|
givenACodeSampleToTokenize var("int&& i;");
|
||||||
|
bool result = si.isVariableDeclaration(var.tokens(), vartok, typetok);
|
||||||
|
ASSERT_EQUALS(true, result);
|
||||||
|
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0);
|
||||||
|
ASSERT(false == v.isArray());
|
||||||
|
ASSERT(false == v.isPointer());
|
||||||
|
ASSERT(true == v.isReference());
|
||||||
|
ASSERT(true == v.isRValueReference());
|
||||||
|
}
|
||||||
|
|
||||||
void staticMemberVar() {
|
void staticMemberVar() {
|
||||||
GET_SYMBOL_DB("class Foo {\n"
|
GET_SYMBOL_DB("class Foo {\n"
|
||||||
" static const double d;\n"
|
" static const double d;\n"
|
||||||
|
@ -756,6 +769,8 @@ private:
|
||||||
ASSERT(foo_int && foo_int->tokenDef->str() == "foo");
|
ASSERT(foo_int && foo_int->tokenDef->str() == "foo");
|
||||||
ASSERT(foo_int && !foo_int->hasBody);
|
ASSERT(foo_int && !foo_int->hasBody);
|
||||||
ASSERT(foo_int && foo_int->tokenDef->strAt(2) == "int");
|
ASSERT(foo_int && foo_int->tokenDef->strAt(2) == "int");
|
||||||
|
|
||||||
|
ASSERT(&foo_int->argumentList.front() == db->getVariableFromVarId(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -272,6 +272,7 @@ private:
|
||||||
TEST_CASE(varid_templateNamespaceFuncPtr); // #4172
|
TEST_CASE(varid_templateNamespaceFuncPtr); // #4172
|
||||||
TEST_CASE(varid_variadicFunc);
|
TEST_CASE(varid_variadicFunc);
|
||||||
TEST_CASE(varid_typename); // #4644
|
TEST_CASE(varid_typename); // #4644
|
||||||
|
TEST_CASE(varid_rvalueref);
|
||||||
|
|
||||||
TEST_CASE(varidclass1);
|
TEST_CASE(varidclass1);
|
||||||
TEST_CASE(varidclass2);
|
TEST_CASE(varidclass2);
|
||||||
|
@ -4312,6 +4313,22 @@ private:
|
||||||
"1: typename A a@1 ;\n", tokenizeDebugListing("typename A a;"));
|
"1: typename A a@1 ;\n", tokenizeDebugListing("typename A a;"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void varid_rvalueref() {
|
||||||
|
ASSERT_EQUALS("\n\n##file 0\n"
|
||||||
|
"1: int & & a@1 ;\n", tokenizeDebugListing("int&& a;"));
|
||||||
|
|
||||||
|
ASSERT_EQUALS("\n\n##file 0\n"
|
||||||
|
"1: void foo ( int & & a@1 ) { }\n", tokenizeDebugListing("void foo(int&& a) {}"));
|
||||||
|
|
||||||
|
ASSERT_EQUALS("\n\n##file 0\n"
|
||||||
|
"1: class C {\n"
|
||||||
|
"2: C ( int & & a@1 ) ;\n"
|
||||||
|
"3: } ;\n",
|
||||||
|
tokenizeDebugListing("class C {\n"
|
||||||
|
" C(int&& a);\n"
|
||||||
|
"};"));
|
||||||
|
}
|
||||||
|
|
||||||
void varidclass1() {
|
void varidclass1() {
|
||||||
const std::string actual = tokenizeDebugListing(
|
const std::string actual = tokenizeDebugListing(
|
||||||
"class Fred\n"
|
"class Fred\n"
|
||||||
|
|
Loading…
Reference in New Issue