Merge pull request #651 from simartin/array_ptr
Properly differentiate arrays of pointers and pointers to arrays.
This commit is contained in:
commit
81a56293ae
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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(), "] ="))
|
||||||
|
|
|
@ -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 ::"));
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 ] ; "
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue