/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2021 Cppcheck team.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "config.h"
#include "platform.h"
#include "settings.h"
#include "testsuite.h"
#include "token.h"
#include "tokenize.h"
struct InternalError;
class TestSimplifyUsing : public TestFixture {
public:
TestSimplifyUsing() : TestFixture("TestSimplifyUsing") {
}
private:
Settings settings0;
Settings settings1;
Settings settings2;
void run() OVERRIDE {
settings0.severity.enable(Severity::style);
settings2.severity.enable(Severity::style);
// If there are unused templates, keep those
settings0.checkUnusedTemplates = true;
settings1.checkUnusedTemplates = true;
settings2.checkUnusedTemplates = true;
TEST_CASE(simplifyUsing1);
TEST_CASE(simplifyUsing2);
TEST_CASE(simplifyUsing3);
TEST_CASE(simplifyUsing4);
TEST_CASE(simplifyUsing5);
TEST_CASE(simplifyUsing6);
TEST_CASE(simplifyUsing7);
TEST_CASE(simplifyUsing8);
TEST_CASE(simplifyUsing9);
TEST_CASE(simplifyUsing10);
TEST_CASE(simplifyUsing11);
TEST_CASE(simplifyUsing12);
TEST_CASE(simplifyUsing13);
TEST_CASE(simplifyUsing14);
TEST_CASE(simplifyUsing15);
TEST_CASE(simplifyUsing16);
TEST_CASE(simplifyUsing17);
TEST_CASE(simplifyUsing18);
TEST_CASE(simplifyUsing19);
TEST_CASE(simplifyUsing20);
TEST_CASE(simplifyUsing21);
TEST_CASE(simplifyUsing22);
TEST_CASE(simplifyUsing23);
TEST_CASE(simplifyUsing8970);
TEST_CASE(simplifyUsing8971);
TEST_CASE(simplifyUsing8976);
TEST_CASE(simplifyUsing9040);
TEST_CASE(simplifyUsing9042);
TEST_CASE(simplifyUsing9191);
TEST_CASE(simplifyUsing9381);
TEST_CASE(simplifyUsing9385);
TEST_CASE(simplifyUsing9388);
TEST_CASE(simplifyUsing9518);
TEST_CASE(simplifyUsing9757);
TEST_CASE(simplifyUsing10008);
TEST_CASE(simplifyUsing10054);
TEST_CASE(simplifyUsing10136);
TEST_CASE(simplifyUsing10171);
TEST_CASE(simplifyUsing10172);
TEST_CASE(simplifyUsing10173);
}
std::string tok(const char code[], bool simplify = true, Settings::PlatformType type = Settings::Native, bool debugwarnings = true) {
errout.str("");
settings0.certainty.enable(Certainty::inconclusive);
settings0.debugwarnings = debugwarnings;
settings0.platform(type);
Tokenizer tokenizer(&settings0, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
return tokenizer.tokens()->stringifyList(nullptr, !simplify);
}
void simplifyUsing1() {
const char code[] = "class A\n"
"{\n"
"public:\n"
" using duplicate = wchar_t;\n"
" void foo() {}\n"
"};\n"
"using duplicate = A;\n"
"int main()\n"
"{\n"
" duplicate a;\n"
" a.foo();\n"
" A::duplicate c = 0;\n"
"}";
const char expected[] =
"class A "
"{ "
"public: "
""
"void foo ( ) { } "
"} ; "
"int main ( ) "
"{ "
"A a ; "
"a . foo ( ) ; "
"wchar_t c ; c = 0 ; "
"}";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing2() {
const char code[] = "class A;\n"
"using duplicate = A;\n"
"class A\n"
"{\n"
"public:\n"
"using duplicate = wchar_t;\n"
"duplicate foo() { wchar_t b; return b; }\n"
"};";
const char expected[] =
"class A ; "
"class A "
"{ "
"public: "
""
"wchar_t foo ( ) { wchar_t b ; return b ; } "
"} ;";
ASSERT_EQUALS(expected, tok(code));
}
void simplifyUsing3() {
const char code[] = "class A {};\n"
"using duplicate = A;\n"
"wchar_t foo()\n"
"{\n"
"using duplicate = wchar_t;\n"
"duplicate b;\n"
"return b;\n"
"}\n"
"int main()\n"
"{\n"
"duplicate b;\n"
"}";
const char expected[] =
"class A { } ; "
"wchar_t foo ( ) "
"{ "
""
"wchar_t b ; "
"return b ; "
"} "
"int main ( ) "
"{ "
"A b ; "
"}";
ASSERT_EQUALS(expected, tok(code));
}
void simplifyUsing4() {
const char code[] = "using s32 = int;\n"
"using u32 = unsigned int;\n"
"void f()\n"
"{\n"
" s32 ivar = -2;\n"
" u32 uvar = 2;\n"
" return uvar / ivar;\n"
"}";
const char expected[] =
"void f ( ) "
"{ "
"int ivar ; ivar = -2 ; "
"unsigned int uvar ; uvar = 2 ; "
"return uvar / ivar ; "
"}";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing5() {
const char code[] =
"using YY_BUFFER_STATE = struct yy_buffer_state *;\n"
"void f()\n"
"{\n"
" YY_BUFFER_STATE state;\n"
"}";
const char expected[] =
"void f ( ) "
"{ "
"struct yy_buffer_state * state ; "
"}";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing6() {
const char code[] =
"namespace VL {\n"
" using float_t = float;\n"
" inline VL::float_t fast_atan2(VL::float_t y, VL::float_t x){}\n"
"}";
const char expected[] =
"namespace VL { "
""
"float fast_atan2 ( float y , float x ) { } "
"}";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing7() {
const char code[] = "using abc = int; "
"Fred :: abc f ;";
const char expected[] = "Fred :: abc f ;";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing8() {
const char code[] = "using INT = int;\n"
"using UINT = unsigned int;\n"
"using PINT = int *;\n"
"using PUINT = unsigned int *;\n"
"using RINT = int &;\n"
"using RUINT = unsigned int &;\n"
"using RCINT = const int &;\n"
"using RCUINT = const unsigned int &;\n"
"INT ti;\n"
"UINT tui;\n"
"PINT tpi;\n"
"PUINT tpui;\n"
"RINT tri;\n"
"RUINT trui;\n"
"RCINT trci;\n"
"RCUINT trcui;";
const char expected[] =
"int ti ; "
"unsigned int tui ; "
"int * tpi ; "
"unsigned int * tpui ; "
"int & tri ; "
"unsigned int & trui ; "
"const int & trci ; "
"const unsigned int & trcui ;";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing9() {
const char code[] = "using S = struct s;\n"
"using PS = S *;\n"
"using T = struct t { int a; };\n"
"using TP = T *;\n"
"using U = struct { int a; };\n"
"using V = U *;\n"
"using W = struct { int a; } *;\n"
"S s;\n"
"PS ps;\n"
"T t;\n"
"TP tp;\n"
"U u;\n"
"V v;\n"
"W w;";
const char expected[] =
"struct t { int a ; } ; "
"struct U { int a ; } ; "
"struct Unnamed0 { int a ; } ; "
"struct s s ; "
"struct s * ps ; "
"struct t t ; "
"struct t * tp ; "
"struct U u ; "
"struct U * v ; "
"struct Unnamed0 * w ;";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing10() {
const char code[] = "using S = union s;\n"
"using PS = S *;\n"
"using T = union t { int a; float b ; };\n"
"using TP = T *;\n"
"using U = union { int a; float b; };\n"
"using V = U *;\n"
"using W = union { int a; float b; } *;\n"
"S s;\n"
"PS ps;\n"
"T t;\n"
"TP tp;\n"
"U u;\n"
"V v;\n"
"W w;";
const char expected[] =
"union t { int a ; float b ; } ; "
"union U { int a ; float b ; } ; "
"union Unnamed0 { int a ; float b ; } ; "
"union s s ; "
"union s * ps ; "
"union t t ; "
"union t * tp ; "
"union U u ; "
"union U * v ; "
"union Unnamed0 * w ;";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing11() {
const char code[] = "using abc = enum { a = 0 , b = 1 , c = 2 };\n"
"using XYZ = enum xyz { x = 0 , y = 1 , z = 2 };\n"
"abc e1;\n"
"XYZ e2;";
const char expected[] = "enum abc { a = 0 , b = 1 , c = 2 } ; "
"enum xyz { x = 0 , y = 1 , z = 2 } ; "
"enum abc e1 ; "
"enum xyz e2 ;";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing12() {
const char code[] = "using V1 = vector;\n"
"using V2 = std::vector;\n"
"using V3 = std::vector >;\n"
"using IntListIterator = std::list::iterator;\n"
"V1 v1;\n"
"V2 v2;\n"
"V3 v3;\n"
"IntListIterator iter;";
const char expected[] = "vector < int > v1 ; "
"std :: vector < int > v2 ; "
"std :: vector < std :: vector < int > > v3 ; "
"std :: list < int > :: iterator iter ;";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing13() {
const char code[] = "using Func = std::pair;\n"
"using CallQueue = std::vector;\n"
"int main() {\n"
" CallQueue q;\n"
"}";
const char expected[] = "int main ( ) { "
"std :: vector < std :: pair < int ( * ) ( void * ) , void * > > q ; "
"}";
ASSERT_EQUALS(expected, tok(code, false));
ASSERT_EQUALS("", errout.str());
}
void simplifyUsing14() {
const char code[] = "template struct E"
"{"
" using v = E0)?(N-1):0>;"
" using val = typename add::val;"
" FP_M(val);"
"};"
"template struct E "
"{"
" using nal = typename D<1>::val;"
" FP_M(val);"
"};";
TODO_ASSERT_THROW(tok(code, true, Settings::Native, false), InternalError); // TODO: Do not throw AST validation exception
//ASSERT_EQUALS("", errout.str());
}
void simplifyUsing15() {
{
const char code[] = "using frame = char [10];\n"
"frame f;";
const char expected[] = "char f [ 10 ] ;";
ASSERT_EQUALS(expected, tok(code, false));
}
{
const char code[] = "using frame = unsigned char [10];\n"
"frame f;";
const char expected[] = "unsigned char f [ 10 ] ;";
ASSERT_EQUALS(expected, tok(code, false));
}
}
void simplifyUsing16() {
const char code[] = "using MOT8 = char;\n"
"using CHFOO = MOT8 [4096];\n"
"using STRFOO = struct {\n"
" CHFOO freem;\n"
"};\n"
"STRFOO s;";
const char expected[] = "struct STRFOO { "
"char freem [ 4096 ] ; "
"} ; "
"struct STRFOO s ;";
ASSERT_EQUALS(expected, tok(code, false));
ASSERT_EQUALS("", errout.str());
}
void simplifyUsing17() {
const char code[] = "class C1 {};\n"
"using S1 = class S1 {};\n"
"using S2 = class S2 : public C1 {};\n"
"using S3 = class {};\n"
"using S4 = class : public C1 {};\n"
"S1 s1;\n"
"S2 s2;\n"
"S3 s3;\n"
"S4 s4;";
const char expected[] = "class C1 { } ; "
"class S1 { } ; "
"class S2 : public C1 { } ; "
"class S3 { } ; "
"class S4 : public C1 { } ; "
"class S1 s1 ; "
"class S2 s2 ; "
"class S3 s3 ; "
"class S4 s4 ;";
ASSERT_EQUALS(expected, tok(code, false));
}
void simplifyUsing18() {
const char code[] = "{ { { using a = a; using a; } } }";
tok(code, false); // don't crash
}
void simplifyUsing19() {
const char code[] = "namespace a {\n"
"using b = int;\n"
"void foo::c() { }\n"
"void foo::d() { }\n"
"void foo::e() {\n"
" using b = float;\n"
"}\n"
"}";
tok(code, false); // don't hang
}
void simplifyUsing20() {
const char code[] = "namespace a {\n"
"namespace b {\n"
"namespace c {\n"
"namespace d {\n"
"namespace e {\n"
"namespace f {\n"
"namespace g {\n"
"using Changeset = ::IAdaptionCallback::Changeset;\n"
"using EProperty = searches::EProperty;\n"
"using ChangesetValueType = Changeset::value_type;\n"
"namespace {\n"
" template \n"
" auto modify(std::shared_ptr& p) -> boost::optionalmodify())> {\n"
" return nullptr;\n"
" }\n"
" template \n"
" std::list getValidElements() {\n"
" return nullptr;\n"
" }\n"
"}\n"
"std::shared_ptr\n"
"foo::getConfiguration() {\n"
" return nullptr;\n"
"}\n"
"void\n"
"foo::doRegister(const Input & Input) {\n"
" UNUSED( Input );\n"
"}\n"
"foo::MicroServiceReturnValue\n"
"foo::post(SearchesPtr element, const Changeset& changeset)\n"
"{\n"
" using EProperty = ab::ep;\n"
" static std::map> updateHandlers =\n"
" {\n"
" {EProperty::Needle, {&RSISearchesResource::updateNeedle, &RSISearchesResource::isSearcherReady}},\n"
" {EProperty::SortBy, {&RSISearchesResource::updateResultsSorting, &RSISearchesResource::isSearcherReady}}\n"
" };\n"
" return nullptr;\n"
"}\n"
"}}}}}}}";
tok(code, false); // don't hang
}
void simplifyUsing21() {
const char code[] = "using a = b;\n"
"enum {}";
tok(code, false); // don't crash
}
void simplifyUsing22() {
const char code[] = "namespace aa { namespace bb { namespace cc { namespace dd { namespace ee {\n"
"class fff {\n"
"public:\n"
" using icmsp = std::shared_ptr;\n"
"private:\n"
" using Connection = boost::signals2::connection;\n"
" using ESdk = sdk::common::api::Sdk::ESdk;\n"
" using co = aa::bb::ee::com::api::com2;\n"
"};\n"
"fff::fff() : m_icm(icm) {\n"
" using ESdk = aa::bb::sdk::common::api::Sdk::ESdk;\n"
"}\n"
"}}}}}";
const char expected[] = "namespace aa { namespace bb { namespace cc { namespace dd { namespace ee { "
"class fff { "
"public: "
"private: "
"} ; "
"fff :: fff ( ) : m_icm ( icm ) { "
"} "
"} } } } }";
ASSERT_EQUALS(expected, tok(code, false)); // don't hang
}
void simplifyUsing23() {
const char code[] = "class cmcch {\n"
"public:\n"
" cmcch(icmsp const& icm, Rtnf&& rtnf = {});\n"
"private:\n"
" using escs = aa::bb::cc::dd::ee;\n"
"private:\n"
" icmsp m_icm;\n"
" mutable std::atomic