Skip to content

Commit ac6f436

Browse files
Fix #11430 internalAstError with using and functional-style cast (#6781)
1 parent cf7f74d commit ac6f436

7 files changed

Lines changed: 96 additions & 19 deletions

File tree

lib/tokenize.cpp

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -753,8 +753,8 @@ namespace {
753753

754754
mUsed = true;
755755

756-
// Special handling for T() when T is a pointer
757-
if (Token::Match(tok, "%name% ( )")) {
756+
// Special handling for T(...) when T is a pointer
757+
if (Token::Match(tok, "%name% [({]") && !Token::simpleMatch(tok->linkAt(1), ") (")) {
758758
bool pointerType = false;
759759
for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
760760
if (type->str() == "*" || type->str() == "&") {
@@ -769,10 +769,23 @@ namespace {
769769
}
770770
}
771771
if (pointerType) {
772-
tok->deleteThis();
773-
tok->next()->insertToken("0");
774-
Token* tok2 = insertTokens(tok, mRangeType);
775-
insertTokens(tok2, mRangeTypeQualifiers);
772+
tok->tokAt(1)->str("(");
773+
tok->linkAt(1)->str(")");
774+
if (tok->linkAt(1) == tok->tokAt(2)) { // T() or T{}
775+
tok->deleteThis();
776+
tok->next()->insertToken("0");
777+
Token* tok2 = insertTokens(tok, mRangeType);
778+
insertTokens(tok2, mRangeTypeQualifiers);
779+
}
780+
else { // functional-style cast
781+
tok->originalName(tok->str());
782+
tok->isSimplifiedTypedef(true);
783+
tok->str("(");
784+
Token* tok2 = insertTokens(tok, mRangeType);
785+
tok2 = insertTokens(tok2, mRangeTypeQualifiers);
786+
Token* tok3 = tok2->insertToken(")");
787+
Token::createMutualLinks(tok, tok3);
788+
}
776789
return;
777790
}
778791
}
@@ -3331,13 +3344,27 @@ bool Tokenizer::simplifyUsing()
33313344
}
33323345
}
33333346

3334-
// Is this a "T()" expression where T is a pointer type?
3335-
if (Token::Match(tok1, "%name% ( )") && !pointers.empty()) {
3336-
Token* tok2 = tok1->linkAt(1);
3337-
tok1->deleteThis();
3338-
TokenList::copyTokens(tok1, start, usingEnd->previous());
3339-
tok2->insertToken("0");
3340-
after = tok2->next();
3347+
// Is this a "T(...)" expression where T is a pointer type?
3348+
if (Token::Match(tok1, "%name% [({]") && !pointers.empty() && !Token::simpleMatch(tok1->linkAt(1), ") (")) {
3349+
tok1->tokAt(1)->str("(");
3350+
tok1->linkAt(1)->str(")");
3351+
if (tok1->linkAt(1) == tok1->tokAt(2)) { // T() or T{}
3352+
Token* tok2 = tok1->linkAt(1);
3353+
tok1->deleteThis();
3354+
TokenList::copyTokens(tok1, start, usingEnd->previous());
3355+
tok2->insertToken("0");
3356+
after = tok2->next();
3357+
}
3358+
else { // functional-style cast
3359+
Token* tok2 = tok1->linkAt(1);
3360+
tok1->originalName(tok1->str());
3361+
tok1->isSimplifiedTypedef(true);
3362+
tok1->str("(");
3363+
Token* tok3 = TokenList::copyTokens(tok1, start, usingEnd->previous());
3364+
tok3->insertToken(")");
3365+
Token::createMutualLinks(tok1, tok3->next());
3366+
after = tok2->next();
3367+
}
33413368
}
33423369
else { // just replace simple type aliases
33433370
TokenList::copyTokens(tok1, start, usingEnd->previous());

lib/tokenlist.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2020,6 +2020,10 @@ void TokenList::simplifyPlatformTypes()
20202020
tok->deleteThis();
20212021
}
20222022
tok->originalName(tok->str());
2023+
const bool isFunctionalPtrCast = (platformtype->mConstPtr || platformtype->mPointer || platformtype->mPtrPtr) &&
2024+
Token::Match(tok, "%name% [({]") && !Token::simpleMatch(tok->linkAt(1), ") (");
2025+
Token* start = isFunctionalPtrCast ? tok->tokAt(1) : nullptr;
2026+
Token* end = isFunctionalPtrCast ? tok->linkAt(1) : nullptr;
20232027
Token *typeToken;
20242028
if (platformtype->mConstPtr) {
20252029
tok->str("const");
@@ -2049,6 +2053,17 @@ void TokenList::simplifyPlatformTypes()
20492053
typeToken->isUnsigned(true);
20502054
if (platformtype->mLong)
20512055
typeToken->isLong(true);
2056+
2057+
if (isFunctionalPtrCast) {
2058+
start->str("(");
2059+
end->str(")");
2060+
if (end == start->tokAt(1))
2061+
end->insertTokenBefore("0");
2062+
end = start->insertTokenBefore(")");
2063+
start = tok->insertTokenBefore("(");
2064+
start->isSimplifiedTypedef(true);
2065+
Token::createMutualLinks(start, end);
2066+
}
20522067
}
20532068
}
20542069
}

test/cfg/windows.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -823,7 +823,7 @@ void invalidFunctionArg()
823823
CloseHandle(hMutex);
824824

825825
//Incorrect: 2. parameter to LoadLibraryEx() must be NULL
826-
// TODO cppcheck-suppress invalidFunctionArg
826+
// cppcheck-suppress [invalidFunctionArg, cstyleCast]
827827
HINSTANCE hInstLib = LoadLibraryEx(L"My.dll", HANDLE(1), 0);
828828
FreeLibrary(hInstLib);
829829

test/testother.cpp

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1767,11 +1767,11 @@ class TestOther : public TestFixture {
17671767
errout_str());
17681768
}
17691769

1770-
#define checkOldStylePointerCast(code) checkOldStylePointerCast_(code, __FILE__, __LINE__)
1770+
#define checkOldStylePointerCast(...) checkOldStylePointerCast_(__FILE__, __LINE__, __VA_ARGS__)
17711771
template<size_t size>
1772-
void checkOldStylePointerCast_(const char (&code)[size], const char* file, int line) {
1773-
// #5560 - set c++03
1774-
const Settings settings = settingsBuilder().severity(Severity::style).cpp(Standards::CPP03).build();
1772+
void checkOldStylePointerCast_(const char* file, int line, const char (&code)[size], Standards::cppstd_t std = Standards::CPPLatest) {
1773+
1774+
const Settings settings = settingsBuilder().severity(Severity::style).cpp(std).build();
17751775

17761776
// Tokenize..
17771777
SimpleTokenizer tokenizerCpp(settings, *this);
@@ -1892,7 +1892,7 @@ class TestOther : public TestFixture {
18921892
"{ virtual G* createGui(S*, C*) const = 0; };\n"
18931893
"\n"
18941894
"class MS : public M\n"
1895-
"{ virtual void addController(C*) override {} };");
1895+
"{ virtual void addController(C*) override {} };", Standards::CPP03);
18961896
ASSERT_EQUALS("", errout_str());
18971897

18981898
// #6164
@@ -1985,6 +1985,19 @@ class TestOther : public TestFixture {
19851985
" r = 0;\n"
19861986
"}\n");
19871987
ASSERT_EQUALS("[test.cpp:2]: (style) C-style reference casting\n", errout_str());
1988+
1989+
// #11430
1990+
checkOldStylePointerCast("struct B {\n"
1991+
" float* data() const;\n"
1992+
"};\n"
1993+
"namespace N {\n"
1994+
" bool f(float* v);\n"
1995+
"}\n"
1996+
"bool g(B& b) {\n"
1997+
" using float_ptr = float*;\n"
1998+
" return N::f(float_ptr(b.data()));\n"
1999+
"}\n");
2000+
ASSERT_EQUALS("[test.cpp:9]: (style) C-style pointer casting\n", errout_str());
19882001
}
19892002

19902003
#define checkInvalidPointerCast(...) checkInvalidPointerCast_(__FILE__, __LINE__, __VA_ARGS__)

test/testsimplifytypedef.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3382,6 +3382,11 @@ class TestSimplifyTypedef : public TestFixture {
33823382
const char code2[] = "typedef int* T;\n"
33833383
"void f(T = T()){}\n";
33843384
ASSERT_EQUALS("void f ( int * = ( int * ) 0 ) { }", tok(code2));
3385+
3386+
// #11430
3387+
const char code3[] = "typedef char* T;\n"
3388+
"T f() { return T(\"abc\"); }\n";
3389+
ASSERT_EQUALS("char * f ( ) { return ( char * ) ( \"abc\" ) ; }", tok(code3));
33853390
}
33863391

33873392
void simplifyTypedef143() { // #11506

test/testsimplifyusing.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class TestSimplifyUsing : public TestFixture {
7171
TEST_CASE(simplifyUsing29);
7272
TEST_CASE(simplifyUsing30);
7373
TEST_CASE(simplifyUsing31);
74+
TEST_CASE(simplifyUsing32);
7475

7576
TEST_CASE(simplifyUsing8970);
7677
TEST_CASE(simplifyUsing8971);
@@ -782,6 +783,16 @@ class TestSimplifyUsing : public TestFixture {
782783
ASSERT_EQUALS("", errout_str());
783784
}
784785

786+
void simplifyUsing32() { // #11430
787+
const char code[] = "using T = int*;\n"
788+
"T f() { return T{}; }\n"
789+
"T g() { return T(malloc(4)); }\n";
790+
const char expected[] = "int * f ( ) { return ( int * ) 0 ; } "
791+
"int * g ( ) { return ( int * ) ( malloc ( 4 ) ) ; }";
792+
ASSERT_EQUALS(expected, tok(code, Platform::Type::Native, /*debugwarnings*/ true));
793+
ASSERT_EQUALS("", errout_str());
794+
}
795+
785796
void simplifyUsing8970() {
786797
const char code[] = "using V = std::vector<int>;\n"
787798
"struct A {\n"

test/testtokenize.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5731,6 +5731,12 @@ class TestTokenizer : public TestFixture {
57315731
"} "
57325732
"unsigned char tbyte ;";
57335733
ASSERT_EQUALS(expected, tokenizeAndStringifyWindows(code, true, Platform::Type::Win32A));
5734+
5735+
const char code2[] = "LPCTSTR f(void* p) { return LPCTSTR(p); }\n" // #11430
5736+
"LPCTSTR g() { return LPCTSTR{}; }";
5737+
const char expected2[] = "const char * f ( void * p ) { return ( const char * ) ( p ) ; }\n"
5738+
"const char * g ( ) { return ( const char * ) ( 0 ) ; }";
5739+
ASSERT_EQUALS(expected2, tokenizeAndStringifyWindows(code2, true, Platform::Type::Win32A));
57345740
}
57355741

57365742
void platformWin32W() {

0 commit comments

Comments
 (0)