This commit is contained in:
parent
e6576dd949
commit
f72db74817
|
@ -221,13 +221,15 @@ void CheckClass::constructors()
|
||||||
if (!usage.assign && !usage.init)
|
if (!usage.assign && !usage.init)
|
||||||
continue;
|
continue;
|
||||||
const Scope* varScope1 = var.nameToken()->scope();
|
const Scope* varScope1 = var.nameToken()->scope();
|
||||||
|
while (varScope1->type == Scope::ScopeType::eStruct)
|
||||||
|
varScope1 = varScope1->nestedIn;
|
||||||
if (varScope1->type == Scope::ScopeType::eUnion) {
|
if (varScope1->type == Scope::ScopeType::eUnion) {
|
||||||
for (Usage &usage2 : usageList) {
|
for (Usage &usage2 : usageList) {
|
||||||
const Variable& var2 = *usage2.var;
|
const Variable& var2 = *usage2.var;
|
||||||
if (usage2.assign || usage2.init || var2.isStatic())
|
if (usage2.assign || usage2.init || var2.isStatic())
|
||||||
continue;
|
continue;
|
||||||
const Scope* varScope2 = var2.nameToken()->scope();
|
const Scope* varScope2 = var2.nameToken()->scope();
|
||||||
if (varScope2->type == Scope::ScopeType::eStruct)
|
while (varScope2->type == Scope::ScopeType::eStruct)
|
||||||
varScope2 = varScope2->nestedIn;
|
varScope2 = varScope2->nestedIn;
|
||||||
if (varScope1 == varScope2)
|
if (varScope1 == varScope2)
|
||||||
usage2.assign = true;
|
usage2.assign = true;
|
||||||
|
|
|
@ -3842,6 +3842,12 @@ void CheckOther::checkOverlappingWrite()
|
||||||
return ChildrenToVisit::none;
|
return ChildrenToVisit::none;
|
||||||
if (lhsmember->str() == rhs->astOperand2()->str())
|
if (lhsmember->str() == rhs->astOperand2()->str())
|
||||||
return ChildrenToVisit::none;
|
return ChildrenToVisit::none;
|
||||||
|
const Variable* rhsmembervar = rhs->astOperand2()->variable();
|
||||||
|
const Scope* varscope1 = lhsmember->variable() ? lhsmember->variable()->typeStartToken()->scope() : nullptr;
|
||||||
|
const Scope* varscope2 = rhsmembervar ? rhsmembervar->typeStartToken()->scope() : nullptr;
|
||||||
|
if (varscope1 && varscope1 == varscope2 && varscope1 != lhsvar->typeScope())
|
||||||
|
// lhsmember and rhsmember are declared in same anonymous scope inside union
|
||||||
|
return ChildrenToVisit::none;
|
||||||
errorToken = rhs->astOperand2();
|
errorToken = rhs->astOperand2();
|
||||||
return ChildrenToVisit::done;
|
return ChildrenToVisit::done;
|
||||||
});
|
});
|
||||||
|
|
143
lib/tokenize.cpp
143
lib/tokenize.cpp
|
@ -8550,10 +8550,6 @@ void Tokenizer::simplifyStructDecl()
|
||||||
// A counter that is used when giving unique names for anonymous structs.
|
// A counter that is used when giving unique names for anonymous structs.
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
// Skip simplification of unions in class definition
|
|
||||||
std::stack<bool> skip; // true = in function, false = not in function
|
|
||||||
skip.push(false);
|
|
||||||
|
|
||||||
// Add names for anonymous structs
|
// Add names for anonymous structs
|
||||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||||
if (!tok->isName())
|
if (!tok->isName())
|
||||||
|
@ -8585,15 +8581,26 @@ void Tokenizer::simplifyStructDecl()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "{" token for current scope
|
||||||
|
std::stack<const Token*> scopeStart;
|
||||||
|
const Token* functionEnd = nullptr;
|
||||||
|
|
||||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||||
|
|
||||||
// check for start of scope and determine if it is in a function
|
// check for start of scope and determine if it is in a function
|
||||||
if (tok->str() == "{")
|
if (tok->str() == "{") {
|
||||||
skip.push(Token::Match(tok->previous(), "const|)"));
|
scopeStart.push(tok);
|
||||||
|
if (!functionEnd && Token::Match(tok->previous(), "const|)"))
|
||||||
|
functionEnd = tok->link();
|
||||||
|
}
|
||||||
|
|
||||||
// end of scope
|
// end of scope
|
||||||
else if (tok->str() == "}" && !skip.empty())
|
else if (tok->str() == "}") {
|
||||||
skip.pop();
|
if (!scopeStart.empty())
|
||||||
|
scopeStart.pop();
|
||||||
|
if (tok == functionEnd)
|
||||||
|
functionEnd = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// check for named struct/union
|
// check for named struct/union
|
||||||
else if (Token::Match(tok, "class|struct|union|enum %type% :|{")) {
|
else if (Token::Match(tok, "class|struct|union|enum %type% :|{")) {
|
||||||
|
@ -8607,120 +8614,82 @@ void Tokenizer::simplifyStructDecl()
|
||||||
next = next->next();
|
next = next->next();
|
||||||
if (!next)
|
if (!next)
|
||||||
continue;
|
continue;
|
||||||
skip.push(false);
|
Token* after = next->link();
|
||||||
tok = next->link();
|
if (!after)
|
||||||
if (!tok)
|
|
||||||
break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
|
break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
|
||||||
Token *restart = next;
|
|
||||||
|
|
||||||
// check for named type
|
// check for named type
|
||||||
if (Token::Match(tok->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) {
|
if (Token::Match(after->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) {
|
||||||
tok->insertToken(";");
|
after->insertToken(";");
|
||||||
tok = tok->next();
|
after = after->next();
|
||||||
while (!Token::Match(start, "struct|class|union|enum")) {
|
while (!Token::Match(start, "struct|class|union|enum")) {
|
||||||
tok->insertToken(start->str());
|
after->insertToken(start->str());
|
||||||
tok = tok->next();
|
after = after->next();
|
||||||
start->deleteThis();
|
start->deleteThis();
|
||||||
}
|
}
|
||||||
if (!tok)
|
tok = start;
|
||||||
|
if (!after)
|
||||||
break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
|
break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
|
||||||
tok->insertToken(type->str());
|
after->insertToken(type->str());
|
||||||
if (start->str() != "class") {
|
if (start->str() != "class") {
|
||||||
tok->insertToken(start->str());
|
after->insertToken(start->str());
|
||||||
tok = tok->next();
|
after = after->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
tok = tok->tokAt(2);
|
after = after->tokAt(2);
|
||||||
|
|
||||||
if (Token::Match(tok, "( %type% )")) {
|
if (Token::Match(after, "( %type% )")) {
|
||||||
tok->link()->deleteThis();
|
after->link()->deleteThis();
|
||||||
tok->deleteThis();
|
after->deleteThis();
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for initialization
|
// check for initialization
|
||||||
if (tok && (tok->next()->str() == "(" || tok->next()->str() == "{")) {
|
if (Token::Match(after, "%any% (|{")) {
|
||||||
tok->insertToken("=");
|
after->insertToken("=");
|
||||||
tok = tok->next();
|
after = after->next();
|
||||||
const bool isEnum = start->str() == "enum";
|
const bool isEnum = start->str() == "enum";
|
||||||
if (!isEnum && cpp) {
|
if (!isEnum && cpp) {
|
||||||
tok->insertToken(type->str());
|
after->insertToken(type->str());
|
||||||
tok = tok->next();
|
after = after->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEnum) {
|
if (isEnum) {
|
||||||
if (tok->next()->str() == "{" && tok->next()->link() != tok->tokAt(2)) {
|
if (Token::Match(after->next(), "{ !!}")) {
|
||||||
tok->next()->str("(");
|
after->next()->str("(");
|
||||||
tok->linkAt(1)->str(")");
|
after->linkAt(1)->str(")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tok = restart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for anonymous struct/union
|
// check for anonymous struct/union
|
||||||
else if (Token::Match(tok, "struct|union {")) {
|
else {
|
||||||
const bool inFunction = skip.top();
|
|
||||||
skip.push(false);
|
|
||||||
Token *tok1 = tok;
|
|
||||||
|
|
||||||
Token *restart = tok->next();
|
|
||||||
tok = tok->next()->link();
|
|
||||||
|
|
||||||
// unnamed anonymous struct/union so possibly remove it
|
// unnamed anonymous struct/union so possibly remove it
|
||||||
if (tok && tok->next() && tok->next()->str() == ";") {
|
bool done = false;
|
||||||
if (inFunction && tok1->str() == "union") {
|
while (!done && Token::Match(tok, "struct|union {") && Token::simpleMatch(tok->linkAt(1), "} ;")) {
|
||||||
// Try to create references in the union..
|
done = true;
|
||||||
Token *tok2 = tok1->tokAt(2);
|
|
||||||
while (tok2) {
|
// is this a class/struct/union scope?
|
||||||
if (Token::Match(tok2, "%type% %name% ;"))
|
bool isClassStructUnionScope = false;
|
||||||
tok2 = tok2->tokAt(3);
|
if (!scopeStart.empty()) {
|
||||||
else
|
for (const Token* tok2 = scopeStart.top()->previous(); tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->previous()) {
|
||||||
|
if (Token::Match(tok2, "class|struct|union")) {
|
||||||
|
isClassStructUnionScope = true;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (!Token::simpleMatch(tok2, "} ;"))
|
|
||||||
continue;
|
|
||||||
Token *vartok = nullptr;
|
|
||||||
tok2 = tok1->tokAt(2);
|
|
||||||
while (Token::Match(tok2, "%type% %name% ;")) {
|
|
||||||
if (!vartok) {
|
|
||||||
vartok = tok2->next();
|
|
||||||
tok2 = tok2->tokAt(3);
|
|
||||||
} else {
|
|
||||||
tok2->insertToken("&");
|
|
||||||
tok2 = tok2->tokAt(2);
|
|
||||||
tok2->insertToken(vartok->str());
|
|
||||||
tok2->next()->varId(vartok->varId());
|
|
||||||
tok2->insertToken("=");
|
|
||||||
tok2 = tok2->tokAt(4);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't remove unnamed anonymous unions from a class, struct or union
|
// remove unnamed anonymous struct/union
|
||||||
if (!(!inFunction && tok1->str() == "union") && !Token::Match(tok1->tokAt(-3), "using %name% =")) {
|
// * not in class/struct/union scopes
|
||||||
skip.pop();
|
if (Token::simpleMatch(tok->linkAt(1), "} ;") && !isClassStructUnionScope && tok->str() != "union") {
|
||||||
tok1->deleteThis();
|
tok->linkAt(1)->previous()->deleteNext(2);
|
||||||
if (tok1->next() == tok) {
|
tok->deleteNext();
|
||||||
tok1->deleteThis();
|
|
||||||
tok = tok1;
|
|
||||||
} else
|
|
||||||
tok1->deleteThis();
|
|
||||||
restart = tok1->previous();
|
|
||||||
tok->deleteThis();
|
tok->deleteThis();
|
||||||
if (tok->next())
|
done = false;
|
||||||
tok->deleteThis();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!restart) {
|
|
||||||
simplifyStructDecl();
|
|
||||||
return;
|
|
||||||
} else if (!restart->next())
|
|
||||||
return;
|
|
||||||
|
|
||||||
tok = restart;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1473,6 +1473,22 @@ private:
|
||||||
"};");
|
"};");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("struct S {\n"
|
||||||
|
" union {\n"
|
||||||
|
" unsigned short all;\n"
|
||||||
|
" struct {\n"
|
||||||
|
" unsigned char flag1;\n"
|
||||||
|
" unsigned char flag2;\n"
|
||||||
|
" };\n"
|
||||||
|
" };\n"
|
||||||
|
"};\n"
|
||||||
|
"\n"
|
||||||
|
"class C : public S {\n"
|
||||||
|
"public:\n"
|
||||||
|
" C() { flag1 = flag2 = 0; tick = 0; }\n"
|
||||||
|
"};");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
check("struct S {\n"
|
check("struct S {\n"
|
||||||
" union {\n"
|
" union {\n"
|
||||||
" unsigned short all;\n"
|
" unsigned short all;\n"
|
||||||
|
|
|
@ -11059,6 +11059,12 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (error) Overlapping read/write of union is undefined behavior\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (error) Overlapping read/write of union is undefined behavior\n", errout.str());
|
||||||
|
|
||||||
|
check("void foo() {\n" // #11013
|
||||||
|
" union { struct { uint8_t a; uint8_t b; }; uint16_t c; } u;\n"
|
||||||
|
" u.a = u.b = 0;\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
// memcpy
|
// memcpy
|
||||||
check("void foo() {\n"
|
check("void foo() {\n"
|
||||||
" char a[10];\n"
|
" char a[10];\n"
|
||||||
|
|
|
@ -1200,12 +1200,6 @@ private:
|
||||||
const char expected[] = "class { } ;";
|
const char expected[] = "class { } ;";
|
||||||
ASSERT_EQUALS(expected, tok(code));
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
const char code[] = "class { struct { struct { } ; } ; };";
|
|
||||||
const char expected[] = "class { } ;";
|
|
||||||
ASSERT_EQUALS(expected, tok(code));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void simplifyStructDecl4() {
|
void simplifyStructDecl4() {
|
||||||
|
@ -1224,8 +1218,7 @@ private:
|
||||||
"} abc;\n";
|
"} abc;\n";
|
||||||
const char expected[] = "class ABC { "
|
const char expected[] = "class ABC { "
|
||||||
"void foo ( ) { "
|
"void foo ( ) { "
|
||||||
"int i ; "
|
"union { int i ; float f ; } ; "
|
||||||
"float & f = i ; "
|
|
||||||
"struct Fee { } ; struct Fee fee ; "
|
"struct Fee { } ; struct Fee fee ; "
|
||||||
"} "
|
"} "
|
||||||
"union { "
|
"union { "
|
||||||
|
|
|
@ -1973,6 +1973,11 @@ private:
|
||||||
const char code3[] = "struct a { int b; } static e[1];";
|
const char code3[] = "struct a { int b; } static e[1];";
|
||||||
const char expected3[] = "struct a { int b ; } ; struct a static e [ 1 ] ;";
|
const char expected3[] = "struct a { int b ; } ; struct a static e [ 1 ] ;";
|
||||||
ASSERT_EQUALS(expected3, tokenizeAndStringify(code3));
|
ASSERT_EQUALS(expected3, tokenizeAndStringify(code3));
|
||||||
|
|
||||||
|
// #11013 - Do not remove unnamed struct in union
|
||||||
|
const char code4[] = "union U { struct { int a; int b; }; int ab[2]; };";
|
||||||
|
const char expected4[] = "union U { struct { int a ; int b ; } ; int ab [ 2 ] ; } ;";
|
||||||
|
ASSERT_EQUALS(expected4, tokenizeAndStringify(code4));
|
||||||
}
|
}
|
||||||
|
|
||||||
void vardecl1() {
|
void vardecl1() {
|
||||||
|
@ -2090,7 +2095,7 @@ private:
|
||||||
" long y;\n"
|
" long y;\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS("void f ( ) {\n\nint x ;\nlong & y = x ;\n\n}", tokenizeAndStringify(code2));
|
ASSERT_EQUALS("void f ( ) {\nunion {\nint x ;\nlong y ;\n} ;\n}", tokenizeAndStringify(code2));
|
||||||
|
|
||||||
// ticket #3927
|
// ticket #3927
|
||||||
const char code3[] = "union xy *p = NULL;";
|
const char code3[] = "union xy *p = NULL;";
|
||||||
|
@ -4539,7 +4544,7 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitfields13() { // ticket #3502 (segmentation fault)
|
void bitfields13() { // ticket #3502 (segmentation fault)
|
||||||
ASSERT_EQUALS("x y ;", tokenizeAndStringify("struct{x y:};\n"));
|
ASSERT_NO_THROW(tokenizeAndStringify("struct{x y:};\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void bitfields15() { // #7747 - enum Foo {A,B}:4;
|
void bitfields15() { // #7747 - enum Foo {A,B}:4;
|
||||||
|
|
Loading…
Reference in New Issue