Merge pull request #651 from simartin/array_ptr

Properly differentiate arrays of pointers and pointers to arrays.
This commit is contained in:
amai2012 2015-08-26 10:29:14 +02:00
commit 81a56293ae
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()); 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) bool CheckAutoVariables::isRefPtrArg(const Token *tok)
{ {
const Variable *var = tok->variable(); const Variable *var = tok->variable();
@ -183,7 +190,7 @@ void CheckAutoVariables::autoVariables()
errorAutoVariableAssignment(tok->next(), false); errorAutoVariableAssignment(tok->next(), false);
} }
tok = tok->tokAt(4); 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); const Token* const varTok = tok->linkAt(2)->tokAt(3);
if (checkRvalueExpression(varTok)) if (checkRvalueExpression(varTok))
errorAutoVariableAssignment(tok->next(), false); errorAutoVariableAssignment(tok->next(), false);

View File

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

View File

@ -2382,7 +2382,9 @@ void CheckOther::checkIncompleteArrayFill()
continue; continue;
if (MathLib::toLongNumber(tok->linkAt(1)->strAt(-1)) == var->dimension(0)) { 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 ((size != 1 && size != 100 && size != 0) || var->isPointer()) {
if (printWarning) if (printWarning)
incompleteArrayFillError(tok, var->name(), tok->str(), false); incompleteArrayFillError(tok, var->name(), tok->str(), false);

View File

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

View File

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

View File

@ -374,7 +374,7 @@ public:
* @return true if array, false if not * @return true if array, false if not
*/ */
bool isArray() const { bool isArray() const {
return getFlag(fIsArray); return getFlag(fIsArray) && !getFlag(fIsPointer);
} }
/** /**
@ -385,6 +385,14 @@ public:
return getFlag(fIsPointer); 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. * Is array or pointer variable.
* @return true if pointer or array, false otherwise * @return true if pointer or array, false otherwise

View File

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

View File

@ -328,11 +328,11 @@ private:
void testautovar11() { // #4641 - fp, assign local struct member address to function parameter void testautovar11() { // #4641 - fp, assign local struct member address to function parameter
check("struct A {\n" check("struct A {\n"
" char *data[10];\n" " char (*data)[10];\n"
"};\n" "};\n"
"void foo(char** p) {\n" "void foo(char** p) {\n"
" struct A a = bar();\n" " struct A a = bar();\n"
" *p = &a.data[0];\n" " *p = &(*a.data)[0];\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); ASSERT_EQUALS("", errout.str());
@ -542,13 +542,13 @@ private:
" long *pKoeff[256];\n" " long *pKoeff[256];\n"
" delete[] pKoeff;\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" check("int main() {\n"
" long *pKoeff[256];\n" " long *pKoeff[256];\n"
" free (pKoeff);\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" check("void foo() {\n"
" const intPtr& intref = Getter();\n" " const intPtr& intref = Getter();\n"

View File

@ -2283,7 +2283,7 @@ private:
"{\n" "{\n"
"public:\n" "public:\n"
" John() { }\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()); 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" " Foo a[5];\n"
" memset(a, '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" check("void f() {\n"
" Foo a[5];\n" // Size of foo is unknown " Foo a[5];\n" // Size of foo is unknown

View File

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

View File

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

View File

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

View File

@ -641,6 +641,14 @@ private:
" return j;\n" " return j;\n"
"}"); "}");
ASSERT_EQUALS("", errout.str()); 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. // Handling of unknown types. Assume they are POD in C.

View File

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