Properly differentiate arrays of pointers and pointers to arrays.

This commit is contained in:
Simon Martin 2015-08-25 21:19:19 +02:00
parent 83c4afa694
commit 6fb19b02d0
15 changed files with 49 additions and 25 deletions

View File

@ -41,6 +41,13 @@ bool CheckAutoVariables::isPtrArg(const Token *tok)
return (var && var->isArgument() && var->isPointer());
}
bool CheckAutoVariables::isArrayArg(const Token *tok)
{
const Variable *var = tok->variable();
return (var && var->isArgument() && var->isArray());
}
bool CheckAutoVariables::isRefPtrArg(const Token *tok)
{
const Variable *var = tok->variable();
@ -183,7 +190,7 @@ void CheckAutoVariables::autoVariables()
errorAutoVariableAssignment(tok->next(), false);
}
tok = tok->tokAt(4);
} else if (Token::Match(tok, "[;{}] %var% [") && Token::Match(tok->linkAt(2), "] = & %var%") && isPtrArg(tok->next()) && isAutoVar(tok->linkAt(2)->tokAt(3))) {
} else if (Token::Match(tok, "[;{}] %var% [") && Token::Match(tok->linkAt(2), "] = & %var%") && isArrayArg(tok->next()) && isAutoVar(tok->linkAt(2)->tokAt(3))) {
const Token* const varTok = tok->linkAt(2)->tokAt(3);
if (checkRvalueExpression(varTok))
errorAutoVariableAssignment(tok->next(), false);

View File

@ -68,6 +68,7 @@ public:
private:
static bool isPtrArg(const Token *tok);
static bool isArrayArg(const Token *tok);
static bool isRefPtrArg(const Token *tok);
static bool isNonReferenceArg(const Token *tok);
static bool isAutoVar(const Token *tok);

View File

@ -2382,7 +2382,9 @@ void CheckOther::checkIncompleteArrayFill()
continue;
if (MathLib::toLongNumber(tok->linkAt(1)->strAt(-1)) == var->dimension(0)) {
const unsigned int size = _tokenizer->sizeOfType(var->typeStartToken());
unsigned int size = _tokenizer->sizeOfType(var->typeStartToken());
if (size == 0 && var->typeStartToken()->next()->str() == "*")
size = _settings->sizeof_pointer;
if ((size != 1 && size != 100 && size != 0) || var->isPointer()) {
if (printWarning)
incompleteArrayFillError(tok, var->name(), tok->str(), false);

View File

@ -72,8 +72,10 @@ void CheckUninitVar::checkScope(const Scope* scope)
continue;
}
if (i->isArray()) {
if (i->isArray() || i->isPointerToArray()) {
const Token *tok = i->nameToken()->next();
if (i->isPointerToArray())
tok = tok->next();
while (Token::simpleMatch(tok->link(), "] ["))
tok = tok->link()->next();
if (Token::simpleMatch(tok->link(), "] ="))

View File

@ -1435,6 +1435,9 @@ const Token * Variable::declEndToken() const
void Variable::evaluate(const Library* lib)
{
if (_name)
setFlag(fIsArray, arrayDimensions(lib));
const Token* tok = _start;
while (tok && tok->previous() && tok->previous()->isName())
tok = tok->previous();
@ -1448,7 +1451,7 @@ void Variable::evaluate(const Library* lib)
else if (tok->str() == "const")
setFlag(fIsConst, true);
else if (tok->str() == "*") {
setFlag(fIsPointer, true);
setFlag(fIsPointer, !isArray() || Token::Match(tok->previous(), "( * %name% )"));
setFlag(fIsConst, false); // Points to const, isn't necessarily const itself
} else if (tok->str() == "&") {
if (isReference())
@ -1470,8 +1473,6 @@ void Variable::evaluate(const Library* lib)
while (_end && _end->previous() && _end->str() == "const")
_end = _end->previous();
if (_name)
setFlag(fIsArray, arrayDimensions(lib));
if (_start) {
setFlag(fIsClass, !_start->isStandardType() && !isPointer() && !isReference());
setFlag(fIsStlType, Token::simpleMatch(_start, "std ::"));

View File

@ -374,7 +374,7 @@ public:
* @return true if array, false if not
*/
bool isArray() const {
return getFlag(fIsArray);
return getFlag(fIsArray) && !getFlag(fIsPointer);
}
/**
@ -385,6 +385,14 @@ public:
return getFlag(fIsPointer);
}
/**
* Is variable a pointer to an array
* @return true if pointer to array, false otherwise
*/
bool isPointerToArray() const {
return isPointer() && getFlag(fIsArray);
}
/**
* Is array or pointer variable.
* @return true if pointer or array, false otherwise

View File

@ -6964,12 +6964,6 @@ bool Tokenizer::simplifyRedundantParentheses()
ret = true;
}
if (Token::Match(tok->previous(), "%type% ( * %name% ) [") && tok->previous()->isStandardType()) {
tok->link()->deleteThis();
tok->deleteThis();
ret = true;
}
if (Token::Match(tok->previous(), "*|& ( %name% )")) {
// We may have a variable declaration looking like "type_name *(var_name)"
Token *tok2 = tok->tokAt(-2);

View File

@ -328,11 +328,11 @@ private:
void testautovar11() { // #4641 - fp, assign local struct member address to function parameter
check("struct A {\n"
" char *data[10];\n"
" char (*data)[10];\n"
"};\n"
"void foo(char** p) {\n"
" struct A a = bar();\n"
" *p = &a.data[0];\n"
" *p = &(*a.data)[0];\n"
"}");
ASSERT_EQUALS("", errout.str());
@ -542,13 +542,13 @@ private:
" long *pKoeff[256];\n"
" delete[] pKoeff;\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Deallocation of an auto-variable results in undefined behaviour.\n", "", errout.str());
ASSERT_EQUALS("[test.cpp:3]: (error) Deallocation of an auto-variable results in undefined behaviour.\n", errout.str());
check("int main() {\n"
" long *pKoeff[256];\n"
" free (pKoeff);\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Deallocation of an auto-variable results in undefined behaviour.\n", "", errout.str());
ASSERT_EQUALS("[test.cpp:3]: (error) Deallocation of an auto-variable results in undefined behaviour.\n", errout.str());
check("void foo() {\n"
" const intPtr& intref = Getter();\n"

View File

@ -2283,7 +2283,7 @@ private:
"{\n"
"public:\n"
" John() { }\n"
" A *a[5];\n"
" A (*a)[5];\n"
"};");
ASSERT_EQUALS("[test.cpp:5]: (warning) Member variable 'John::a' is not initialized in the constructor.\n", errout.str());
}

View File

@ -5288,7 +5288,7 @@ private:
" Foo a[5];\n"
" memset(a, 'a', 5);\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) Array 'a' is filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*a)'?\n", "", errout.str());
TODO_ASSERT_EQUALS("[test.cpp:4]: (warning, inconclusive) Array 'a' is filled incompletely. Did you forget to multiply the size given to 'memset()' with 'sizeof(*a)'?\n", "", errout.str());
check("void f() {\n"
" Foo a[5];\n" // Size of foo is unknown

View File

@ -1453,7 +1453,7 @@ private:
"type4 t4;";
// The expected result..
const char expected[] = "char * t1 [ 10 ] ; "
const char expected[] = "char ( * t1 ) [ 10 ] ; "
"char ( * ( * tp1 ) [ 2 ] ) [ 10 ] ; "
"char ( & t2 ) [ 10 ] ; "
"char ( & t3 ) [ x ] ; "

View File

@ -496,14 +496,15 @@ private:
void test_isVariableDeclarationIdentifiesOfArrayPointers() {
reset();
givenACodeSampleToTokenize arr("A *a[5];");
givenACodeSampleToTokenize arr("A (*a)[5];");
bool result = si.isVariableDeclaration(arr.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("a", vartok->str());
ASSERT_EQUALS("A", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, Public, 0, 0, &settings.library);
ASSERT(true == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isArray());
ASSERT(true == v.isPointerToArray());
ASSERT(false == v.isReference());
}

View File

@ -3300,7 +3300,7 @@ private:
}
void removeParentheses18() {
ASSERT_EQUALS("float * a [ 2 ] ;", tokenizeAndStringify("float(*a)[2];", false));
ASSERT_EQUALS("float ( * a ) [ 2 ] ;", tokenizeAndStringify("float(*a)[2];", false));
}
void removeParentheses19() {

View File

@ -641,6 +641,14 @@ private:
" return j;\n"
"}");
ASSERT_EQUALS("", errout.str());
// Ticket #5646
checkUninitVar("float foo() {\n"
" float source[2] = {3.1, 3.1};\n"
" float (*sink)[2] = &source;\n"
" return (*sink)[0];\n"
"}");
ASSERT_EQUALS("", errout.str());
}
// Handling of unknown types. Assume they are POD in C.

View File

@ -1977,9 +1977,9 @@ private:
void varid_pointerToArray() {
ASSERT_EQUALS("\n\n##file 0\n"
"1: int * a1@1 [ 10 ] ;\n"
"1: int ( * a1@1 ) [ 10 ] ;\n"
"2: void f1 ( ) {\n"
"3: int * a2@2 [ 10 ] ;\n"
"3: int ( * a2@2 ) [ 10 ] ;\n"
"4: int ( & a3@3 ) [ 10 ] ;\n"
"5: }\n"
"6: struct A {\n"