diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index ccfd66118..ae363eca6 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -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); diff --git a/lib/checkautovariables.h b/lib/checkautovariables.h index 6d111f470..f9aaab535 100644 --- a/lib/checkautovariables.h +++ b/lib/checkautovariables.h @@ -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); diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 7b5f34266..ad4a8ef9e 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -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); diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 586e3c93b..642e219cc 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -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(), "] =")) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index a7524d5cf..c65256d60 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -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 ::")); diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index e994be2d0..0379cdd0a 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -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 diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index b944423d7..d2b4e119b 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -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); diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index a8bf0c94b..6353c0e9e 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -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" diff --git a/test/testconstructors.cpp b/test/testconstructors.cpp index 766884d57..654e9fcda 100644 --- a/test/testconstructors.cpp +++ b/test/testconstructors.cpp @@ -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()); } diff --git a/test/testother.cpp b/test/testother.cpp index 5adb8af20..a6544dc85 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -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 diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 0a9590dec..352944b4d 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -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 ] ; " diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 43dd849a0..a5f1fd618 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -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()); } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 47f89858e..acdf1e308 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -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() { diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index ce7482d14..9ffc2c377 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -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. diff --git a/test/testvarid.cpp b/test/testvarid.cpp index c473b2c24..0dbeb0013 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -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"