diff --git a/test/testsymboldatabase_u.cpp b/test/testsymboldatabase_u.cpp new file mode 100644 index 000000000..793900668 --- /dev/null +++ b/test/testsymboldatabase_u.cpp @@ -0,0 +1,8484 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2022 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 "library.h" +#include "platform.h" +#include "settings.h" +#include "symboldatabase.h" +#include "testsuite.h" +#include "testutils.h" +#include "token.h" +#include "tokenize.h" +#include "tokenlist.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct InternalError; +class TestSymbolDatabase; + +#define GET_SYMBOL_DB_STD(code) \ + Tokenizer tokenizer(&settings1, this); \ + LOAD_LIB_2(settings1.library, "std.cfg"); \ + const SymbolDatabase *db = getSymbolDB_inner(tokenizer, code, "test.cpp"); \ + ASSERT(db); \ + do {} while (false) + +#define GET_SYMBOL_DB(code) \ + Tokenizer tokenizer(&settings1, this); \ + const SymbolDatabase *db = getSymbolDB_inner(tokenizer, code, "test.cpp"); \ + ASSERT(db); \ + do {} while (false) + +#define GET_SYMBOL_DB_C(code) \ + Tokenizer tokenizer(&settings1, this); \ + const SymbolDatabase *db = getSymbolDB_inner(tokenizer, code, "test.c"); \ + do {} while (false) + +class TestSymbolDatabase : public TestFixture { +public: + TestSymbolDatabase() + : TestFixture("TestSymbolDatabase") + ,vartok(nullptr) + ,typetok(nullptr) {} + +private: + const Token* vartok; + const Token* typetok; + Settings settings1; + Settings settings2; + + void reset() { + vartok = nullptr; + typetok = nullptr; + } + + const static SymbolDatabase* getSymbolDB_inner(Tokenizer& tokenizer, const char* code, const char* filename) { + errout.str(""); + std::istringstream istr(code); + return tokenizer.tokenize(istr, filename) ? tokenizer.getSymbolDatabase() : nullptr; + } + + static const Scope *findFunctionScopeByToken(const SymbolDatabase * db, const Token *tok) { + std::list::const_iterator scope; + + for (scope = db->scopeList.begin(); scope != db->scopeList.end(); ++scope) { + if (scope->type == Scope::eFunction) { + if (scope->classDef == tok) + return &(*scope); + } + } + return nullptr; + } + + static const Function *findFunctionByName(const char str[], const Scope* startScope) { + const Scope* currScope = startScope; + while (currScope && currScope->isExecutable()) { + if (currScope->functionOf) + currScope = currScope->functionOf; + else + currScope = currScope->nestedIn; + } + while (currScope) { + for (const Function & i : currScope->functionList) { + if (i.tokenDef->str() == str) + return &i; + } + currScope = currScope->nestedIn; + } + return nullptr; + } + + void run() override { + LOAD_LIB_2(settings1.library, "std.cfg"); + settings2.platform(Settings::Unspecified); + + // If there are unused templates, keep those + settings1.checkUnusedTemplates = true; + settings2.checkUnusedTemplates = true; + + TEST_CASE(array); + TEST_CASE(stlarray1); + TEST_CASE(stlarray2); + + TEST_CASE(test_isVariableDeclarationCanHandleNull); + TEST_CASE(test_isVariableDeclarationIdentifiesSimpleDeclaration); + TEST_CASE(test_isVariableDeclarationIdentifiesInitialization); + TEST_CASE(test_isVariableDeclarationIdentifiesCpp11Initialization); + TEST_CASE(test_isVariableDeclarationIdentifiesScopedDeclaration); + TEST_CASE(test_isVariableDeclarationIdentifiesStdDeclaration); + TEST_CASE(test_isVariableDeclarationIdentifiesScopedStdDeclaration); + TEST_CASE(test_isVariableDeclarationIdentifiesManyScopes); + TEST_CASE(test_isVariableDeclarationIdentifiesPointers); + TEST_CASE(test_isVariableDeclarationIdentifiesPointers2); + TEST_CASE(test_isVariableDeclarationDoesNotIdentifyConstness); + TEST_CASE(test_isVariableDeclarationIdentifiesFirstOfManyVariables); + TEST_CASE(test_isVariableDeclarationIdentifiesScopedPointerDeclaration); + TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithIndirection); + TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection); + TEST_CASE(test_isVariableDeclarationIdentifiesArray); + TEST_CASE(test_isVariableDeclarationIdentifiesPointerArray); + TEST_CASE(test_isVariableDeclarationIdentifiesOfArrayPointers); + TEST_CASE(isVariableDeclarationIdentifiesTemplatedPointerVariable); + TEST_CASE(isVariableDeclarationIdentifiesTemplatedPointerToPointerVariable); + TEST_CASE(isVariableDeclarationIdentifiesTemplatedArrayVariable); + TEST_CASE(isVariableDeclarationIdentifiesTemplatedVariable); + TEST_CASE(isVariableDeclarationIdentifiesTemplatedVariableIterator); + TEST_CASE(isVariableDeclarationIdentifiesNestedTemplateVariable); + TEST_CASE(isVariableDeclarationIdentifiesReference); + TEST_CASE(isVariableDeclarationDoesNotIdentifyTemplateClass); + TEST_CASE(isVariableDeclarationDoesNotIdentifyCppCast); + TEST_CASE(isVariableDeclarationPointerConst); + TEST_CASE(isVariableDeclarationRValueRef); + TEST_CASE(isVariableDeclarationDoesNotIdentifyCase); + TEST_CASE(isVariableDeclarationIf); + TEST_CASE(isVariableStlType); + TEST_CASE(isVariablePointerToConstPointer); + TEST_CASE(isVariablePointerToVolatilePointer); + TEST_CASE(isVariablePointerToConstVolatilePointer); + TEST_CASE(isVariableMultiplePointersAndQualifiers); + TEST_CASE(variableVolatile); + TEST_CASE(variableConstexpr); + TEST_CASE(isVariableDecltype); + + TEST_CASE(VariableValueType1); + TEST_CASE(VariableValueType2); + TEST_CASE(VariableValueType3); + TEST_CASE(VariableValueType4); // smart pointer type + TEST_CASE(VariableValueType5); // smart pointer type + TEST_CASE(VariableValueTypeReferences); + + TEST_CASE(findVariableType1); + TEST_CASE(findVariableType2); + TEST_CASE(findVariableType3); + TEST_CASE(findVariableTypeExternC); + + TEST_CASE(rangeBasedFor); + + TEST_CASE(arrayMemberVar1); + TEST_CASE(arrayMemberVar2); + TEST_CASE(arrayMemberVar3); + TEST_CASE(staticMemberVar); + TEST_CASE(getVariableFromVarIdBoundsCheck); + + TEST_CASE(hasRegularFunction); + TEST_CASE(hasRegularFunction_trailingReturnType); + TEST_CASE(hasInlineClassFunction); + TEST_CASE(hasInlineClassFunction_trailingReturnType); + TEST_CASE(hasMissingInlineClassFunction); + TEST_CASE(hasClassFunction); + TEST_CASE(hasClassFunction_trailingReturnType); + TEST_CASE(hasClassFunction_decltype_auto); + + TEST_CASE(hasRegularFunctionReturningFunctionPointer); + TEST_CASE(hasInlineClassFunctionReturningFunctionPointer); + TEST_CASE(hasMissingInlineClassFunctionReturningFunctionPointer); + TEST_CASE(hasInlineClassOperatorTemplate); + TEST_CASE(hasClassFunctionReturningFunctionPointer); + TEST_CASE(methodWithRedundantScope); + TEST_CASE(complexFunctionArrayPtr); + TEST_CASE(pointerToMemberFunction); + TEST_CASE(hasSubClassConstructor); + TEST_CASE(testConstructors); + TEST_CASE(functionDeclarationTemplate); + TEST_CASE(functionDeclarations); + TEST_CASE(functionDeclarations2); + TEST_CASE(constexprFunction); + TEST_CASE(constructorInitialization); + TEST_CASE(memberFunctionOfUnknownClassMacro1); + TEST_CASE(memberFunctionOfUnknownClassMacro2); + TEST_CASE(memberFunctionOfUnknownClassMacro3); + TEST_CASE(functionLinkage); + + TEST_CASE(classWithFriend); + + TEST_CASE(parseFunctionCorrect); + TEST_CASE(parseFunctionDeclarationCorrect); + TEST_CASE(Cpp11InitInInitList); + + TEST_CASE(hasGlobalVariables1); + TEST_CASE(hasGlobalVariables2); + TEST_CASE(hasGlobalVariables3); + + TEST_CASE(checkTypeStartEndToken1); + TEST_CASE(checkTypeStartEndToken2); // handling for unknown macro: 'void f() MACRO {..' + TEST_CASE(checkTypeStartEndToken3); // no variable name: void f(const char){} + + TEST_CASE(functionArgs1); + TEST_CASE(functionArgs2); + TEST_CASE(functionArgs4); + TEST_CASE(functionArgs5); // #7650 + TEST_CASE(functionArgs6); // #7651 + TEST_CASE(functionArgs7); // #7652 + TEST_CASE(functionArgs8); // #7653 + TEST_CASE(functionArgs9); // #7657 + TEST_CASE(functionArgs10); + TEST_CASE(functionArgs11); + TEST_CASE(functionArgs12); // #7661 + TEST_CASE(functionArgs13); // #7697 + TEST_CASE(functionArgs14); // #9055 + TEST_CASE(functionArgs15); // #7159 + TEST_CASE(functionArgs16); // #9591 + TEST_CASE(functionArgs17); + TEST_CASE(functionArgs18); // #10376 + + TEST_CASE(functionImplicitlyVirtual); + + TEST_CASE(functionIsInlineKeyword); + + TEST_CASE(functionStatic); + + TEST_CASE(functionReturnsReference); // Function::returnsReference + + TEST_CASE(namespaces1); + TEST_CASE(namespaces2); + TEST_CASE(namespaces3); // #3854 - unknown macro + TEST_CASE(namespaces4); + + TEST_CASE(tryCatch1); + + TEST_CASE(symboldatabase1); + TEST_CASE(symboldatabase2); + TEST_CASE(symboldatabase3); // ticket #2000 + TEST_CASE(symboldatabase4); + TEST_CASE(symboldatabase5); // ticket #2178 + TEST_CASE(symboldatabase6); // ticket #2221 + TEST_CASE(symboldatabase7); // ticket #2230 + TEST_CASE(symboldatabase8); // ticket #2252 + TEST_CASE(symboldatabase9); // ticket #2525 + TEST_CASE(symboldatabase10); // ticket #2537 + TEST_CASE(symboldatabase11); // ticket #2539 + TEST_CASE(symboldatabase12); // ticket #2547 + TEST_CASE(symboldatabase13); // ticket #2577 + TEST_CASE(symboldatabase14); // ticket #2589 + TEST_CASE(symboldatabase17); // ticket #2657 + TEST_CASE(symboldatabase19); // ticket #2991 (segmentation fault) + TEST_CASE(symboldatabase20); // ticket #3013 (segmentation fault) + TEST_CASE(symboldatabase21); + TEST_CASE(symboldatabase22); // ticket #3437 (segmentation fault) + TEST_CASE(symboldatabase23); // ticket #3435 + TEST_CASE(symboldatabase24); // ticket #3508 (constructor, destructor) + TEST_CASE(symboldatabase25); // ticket #3561 (throw C++) + TEST_CASE(symboldatabase26); // ticket #3561 (throw C) + TEST_CASE(symboldatabase27); // ticket #3543 (segmentation fault) + TEST_CASE(symboldatabase28); + TEST_CASE(symboldatabase29); // ticket #4442 (segmentation fault) + TEST_CASE(symboldatabase30); + TEST_CASE(symboldatabase31); + TEST_CASE(symboldatabase32); + TEST_CASE(symboldatabase33); // ticket #4682 (false negatives) + TEST_CASE(symboldatabase34); // ticket #4694 (segmentation fault) + TEST_CASE(symboldatabase35); // ticket #4806 (segmentation fault) + TEST_CASE(symboldatabase36); // ticket #4892 (segmentation fault) + TEST_CASE(symboldatabase37); + TEST_CASE(symboldatabase38); // ticket #5125 (infinite recursion) + TEST_CASE(symboldatabase40); // ticket #5153 + TEST_CASE(symboldatabase41); // ticket #5197 (unknown macro) + TEST_CASE(symboldatabase42); // only put variables in variable list + TEST_CASE(symboldatabase43); // #4738 + TEST_CASE(symboldatabase44); + TEST_CASE(symboldatabase45); // #6125 + TEST_CASE(symboldatabase46); // #6171 (anonymous namespace) + TEST_CASE(symboldatabase47); // #6308 + TEST_CASE(symboldatabase48); // #6417 + TEST_CASE(symboldatabase49); // #6424 + TEST_CASE(symboldatabase50); // #6432 + TEST_CASE(symboldatabase51); // #6538 + TEST_CASE(symboldatabase52); // #6581 + TEST_CASE(symboldatabase53); // #7124 (library podtype) + TEST_CASE(symboldatabase54); // #7257 + TEST_CASE(symboldatabase55); // #7767 (return unknown macro) + TEST_CASE(symboldatabase56); // #7909 + TEST_CASE(symboldatabase57); + TEST_CASE(symboldatabase58); // #6985 (using namespace type lookup) + TEST_CASE(symboldatabase59); + TEST_CASE(symboldatabase60); + TEST_CASE(symboldatabase61); + TEST_CASE(symboldatabase62); + TEST_CASE(symboldatabase63); + TEST_CASE(symboldatabase64); + TEST_CASE(symboldatabase65); + TEST_CASE(symboldatabase66); // #8540 + TEST_CASE(symboldatabase67); // #8538 + TEST_CASE(symboldatabase68); // #8560 + TEST_CASE(symboldatabase69); + TEST_CASE(symboldatabase70); + TEST_CASE(symboldatabase71); + TEST_CASE(symboldatabase72); // #8600 + TEST_CASE(symboldatabase74); // #8838 - final + TEST_CASE(symboldatabase75); + TEST_CASE(symboldatabase76); // #9056 + TEST_CASE(symboldatabase77); // #8663 + TEST_CASE(symboldatabase78); // #9147 + TEST_CASE(symboldatabase79); // #9392 + TEST_CASE(symboldatabase80); // #9389 + TEST_CASE(symboldatabase81); // #9411 + TEST_CASE(symboldatabase82); + TEST_CASE(symboldatabase83); // #9431 + TEST_CASE(symboldatabase84); + TEST_CASE(symboldatabase85); + TEST_CASE(symboldatabase86); + TEST_CASE(symboldatabase87); // #9922 'extern const char ( * x [ 256 ] ) ;' + TEST_CASE(symboldatabase88); // #10040 (using namespace) + TEST_CASE(symboldatabase89); // valuetype name + TEST_CASE(symboldatabase90); + TEST_CASE(symboldatabase91); + TEST_CASE(symboldatabase92); // daca crash + TEST_CASE(symboldatabase93); // alignas attribute + TEST_CASE(symboldatabase94); // structured bindings + TEST_CASE(symboldatabase95); // #10295 + TEST_CASE(symboldatabase96); // #10126 + TEST_CASE(symboldatabase97); // #10598 - final class + TEST_CASE(symboldatabase98); // #10451 + + TEST_CASE(createSymbolDatabaseFindAllScopes1); + TEST_CASE(createSymbolDatabaseFindAllScopes2); + TEST_CASE(createSymbolDatabaseFindAllScopes3); + TEST_CASE(createSymbolDatabaseFindAllScopes4); + + TEST_CASE(enum1); + TEST_CASE(enum2); + TEST_CASE(enum3); + TEST_CASE(enum4); + TEST_CASE(enum5); + TEST_CASE(enum6); + TEST_CASE(enum7); + TEST_CASE(enum8); + TEST_CASE(enum9); + + TEST_CASE(sizeOfType); + + TEST_CASE(isImplicitlyVirtual); + TEST_CASE(isPure); + + TEST_CASE(isFunction1); // UNKNOWN_MACRO(a,b) { .. } + TEST_CASE(isFunction2); + + TEST_CASE(findFunction1); + TEST_CASE(findFunction2); // mismatch: parameter passed by address => reference argument + TEST_CASE(findFunction3); + TEST_CASE(findFunction4); + TEST_CASE(findFunction5); // #6230 + TEST_CASE(findFunction6); + TEST_CASE(findFunction7); // #6700 + TEST_CASE(findFunction8); + TEST_CASE(findFunction9); + TEST_CASE(findFunction10); // #7673 + TEST_CASE(findFunction11); + TEST_CASE(findFunction12); + TEST_CASE(findFunction13); + TEST_CASE(findFunction14); + TEST_CASE(findFunction15); + TEST_CASE(findFunction16); + TEST_CASE(findFunction17); + TEST_CASE(findFunction18); + TEST_CASE(findFunction19); + TEST_CASE(findFunction20); // #8280 + TEST_CASE(findFunction21); + TEST_CASE(findFunction22); + TEST_CASE(findFunction23); + TEST_CASE(findFunction24); // smart pointer + TEST_CASE(findFunction25); // std::vector> + TEST_CASE(findFunction26); // #8668 - pointer parameter in function call, const pointer function argument + TEST_CASE(findFunction27); + TEST_CASE(findFunction28); + TEST_CASE(findFunction29); + TEST_CASE(findFunction30); + TEST_CASE(findFunction31); + TEST_CASE(findFunction32); // C: relax type matching + TEST_CASE(findFunction33); // #9885 variadic function + TEST_CASE(findFunction34); // #10061 + TEST_CASE(findFunction35); + TEST_CASE(findFunction36); // #10122 + TEST_CASE(findFunction37); // #10124 + TEST_CASE(findFunction38); // #10125 + TEST_CASE(findFunction39); // #10127 + TEST_CASE(findFunction40); // #10135 + TEST_CASE(findFunction41); // #10202 + TEST_CASE(findFunction42); + TEST_CASE(findFunction43); // #10087 + TEST_CASE(findFunctionContainer); + TEST_CASE(findFunctionExternC); + TEST_CASE(findFunctionGlobalScope); // ::foo + + TEST_CASE(overloadedFunction1); + + TEST_CASE(valueTypeMatchParameter); // ValueType::matchParameter + + TEST_CASE(noexceptFunction1); + TEST_CASE(noexceptFunction2); + TEST_CASE(noexceptFunction3); + TEST_CASE(noexceptFunction4); + + TEST_CASE(throwFunction1); + TEST_CASE(throwFunction2); + + TEST_CASE(nothrowAttributeFunction); + TEST_CASE(nothrowDeclspecFunction); + + TEST_CASE(noreturnAttributeFunction); + TEST_CASE(nodiscardAttributeFunction); + + TEST_CASE(varTypesIntegral); // known integral + TEST_CASE(varTypesFloating); // known floating + TEST_CASE(varTypesOther); // (un)known + + TEST_CASE(functionPrototype); // #5867 + + TEST_CASE(lambda); // #5867 + TEST_CASE(lambda2); // #7473 + TEST_CASE(lambda3); + + TEST_CASE(circularDependencies); // #6298 + + TEST_CASE(executableScopeWithUnknownFunction); + + TEST_CASE(valuetype); + + TEST_CASE(variadic1); // #7453 + TEST_CASE(variadic2); // #7649 + TEST_CASE(variadic3); // #7387 + + TEST_CASE(noReturnType); + + TEST_CASE(auto1); + TEST_CASE(auto2); + TEST_CASE(auto3); + TEST_CASE(auto4); + TEST_CASE(auto5); + TEST_CASE(auto6); // #7963 (segmentation fault) + TEST_CASE(auto7); + TEST_CASE(auto8); + TEST_CASE(auto9); // #8044 (segmentation fault) + TEST_CASE(auto10); // #8020 + TEST_CASE(auto11); // #8964 - const auto startX = x; + TEST_CASE(auto12); // #8993 - const std::string &x; auto y = x; if (y.empty()) .. + TEST_CASE(auto13); + TEST_CASE(auto14); + TEST_CASE(auto15); // C++17 auto deduction from braced-init-list + TEST_CASE(auto16); + + TEST_CASE(unionWithConstructor); + + TEST_CASE(incomplete_type); // #9255 (infinite recursion) + } + + void array() { + GET_SYMBOL_DB_C("int a[10+2];"); + ASSERT(db != nullptr); + + ASSERT(db->variableList().size() == 2); // the first one is not used + const Variable * v = db->getVariableFromVarId(1); + ASSERT(v != nullptr); + + ASSERT(v->isArray()); + ASSERT_EQUALS(1U, v->dimensions().size()); + ASSERT_EQUALS(12U, v->dimension(0)); + } + + void stlarray1() { + GET_SYMBOL_DB("std::array arr;"); + ASSERT(db != nullptr); + + ASSERT_EQUALS(2, db->variableList().size()); // the first one is not used + const Variable * v = db->getVariableFromVarId(1); + ASSERT(v != nullptr); + + ASSERT(v->isArray()); + ASSERT_EQUALS(1U, v->dimensions().size()); + ASSERT_EQUALS(20U, v->dimension(0)); + } + + void stlarray2() { + GET_SYMBOL_DB("constexpr int sz = 16; std::array arr;"); + ASSERT(db != nullptr); + + ASSERT_EQUALS(3, db->variableList().size()); // the first one is not used + const Variable * v = db->getVariableFromVarId(2); + ASSERT(v != nullptr); + + ASSERT(v->isArray()); + ASSERT_EQUALS(1U, v->dimensions().size()); + ASSERT_EQUALS(20U, v->dimension(0)); + } + + void test_isVariableDeclarationCanHandleNull() { + reset(); + GET_SYMBOL_DB("void main(){}"); + const bool result = db->scopeList.front().isVariableDeclaration(nullptr, vartok, typetok); + ASSERT_EQUALS(false, result); + ASSERT(nullptr == vartok); + ASSERT(nullptr == typetok); + Variable v(nullptr, nullptr, nullptr, 0, AccessControl::Public, nullptr, nullptr, &settings1); + } + + void test_isVariableDeclarationIdentifiesSimpleDeclaration() { + reset(); + GET_SYMBOL_DB("int x;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("x", vartok->str()); + ASSERT_EQUALS("int", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesInitialization() { + reset(); + GET_SYMBOL_DB("int x (1);"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("x", vartok->str()); + ASSERT_EQUALS("int", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesCpp11Initialization() { + reset(); + GET_SYMBOL_DB("int x {1};"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("x", vartok->str()); + ASSERT_EQUALS("int", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesScopedDeclaration() { + reset(); + GET_SYMBOL_DB("::int x;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("x", vartok->str()); + ASSERT_EQUALS("int", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesStdDeclaration() { + reset(); + GET_SYMBOL_DB("std::string x;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("x", vartok->str()); + ASSERT_EQUALS("string", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesScopedStdDeclaration() { + reset(); + GET_SYMBOL_DB("::std::string x;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("x", vartok->str()); + ASSERT_EQUALS("string", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesManyScopes() { + reset(); + GET_SYMBOL_DB("AA::BB::CC::DD::EE x;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("x", vartok->str()); + ASSERT_EQUALS("EE", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesPointers() { + { + reset(); + GET_SYMBOL_DB("int* p;"); + const bool result1 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result1); + ASSERT_EQUALS("p", vartok->str()); + ASSERT_EQUALS("int", typetok->str()); + Variable v1(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v1.isArray()); + ASSERT(true == v1.isPointer()); + ASSERT(false == v1.isReference()); + } + { + reset(); + givenACodeSampleToTokenize constpointer("const int* p;"); + Variable v2(constpointer.tokens()->tokAt(3), constpointer.tokens()->next(), constpointer.tokens()->tokAt(2), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v2.isArray()); + ASSERT(true == v2.isPointer()); + ASSERT(false == v2.isConst()); + ASSERT(false == v2.isReference()); + } + { + reset(); + GET_SYMBOL_DB("int* const p;"); + const bool result2 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result2); + ASSERT_EQUALS("p", vartok->str()); + ASSERT_EQUALS("int", typetok->str()); + Variable v3(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v3.isArray()); + ASSERT(true == v3.isPointer()); + ASSERT(true == v3.isConst()); + ASSERT(false == v3.isReference()); + } + } + + void test_isVariableDeclarationIdentifiesPointers2() { + + GET_SYMBOL_DB("void slurpInManifest() {\n" + " std::string tmpiostring(*tI);\n" + " if(tmpiostring==\"infoonly\"){}\n" + "}"); + + const Token *tok = Token::findsimplematch(tokenizer.tokens(), "tmpiostring =="); + ASSERT(tok->variable()); + ASSERT(!tok->variable()->isPointer()); + } + + void test_isVariableDeclarationDoesNotIdentifyConstness() { + reset(); + GET_SYMBOL_DB("const int* cp;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(false, result); + ASSERT(nullptr == vartok); + ASSERT(nullptr == typetok); + } + + void test_isVariableDeclarationIdentifiesFirstOfManyVariables() { + reset(); + GET_SYMBOL_DB("int first, second;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("first", vartok->str()); + ASSERT_EQUALS("int", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesScopedPointerDeclaration() { + reset(); + GET_SYMBOL_DB("AA::BB::CC::DD::EE* p;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("p", vartok->str()); + ASSERT_EQUALS("EE", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesDeclarationWithIndirection() { + reset(); + GET_SYMBOL_DB("int** pp;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("pp", vartok->str()); + ASSERT_EQUALS("int", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection() { + reset(); + GET_SYMBOL_DB("int***** p;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("p", vartok->str()); + ASSERT_EQUALS("int", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesArray() { + reset(); + GET_SYMBOL_DB("::std::string v[3];"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("v", vartok->str()); + ASSERT_EQUALS("string", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(true == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isPointerArray()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesPointerArray() { + reset(); + GET_SYMBOL_DB("A *a[5];"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("a", vartok->str()); + ASSERT_EQUALS("A", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isPointer()); + ASSERT(true == v.isArray()); + ASSERT(false == v.isPointerToArray()); + ASSERT(true == v.isPointerArray()); + ASSERT(false == v.isReference()); + } + + void test_isVariableDeclarationIdentifiesOfArrayPointers() { + reset(); + GET_SYMBOL_DB("A (*a)[5];"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("a", vartok->str()); + ASSERT_EQUALS("A", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointerToArray()); + ASSERT(false == v.isPointerArray()); + ASSERT(false == v.isReference()); + } + + void isVariableDeclarationIdentifiesTemplatedPointerVariable() { + reset(); + GET_SYMBOL_DB("std::set* chars;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("chars", vartok->str()); + ASSERT_EQUALS("set", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariableDeclarationIdentifiesTemplatedPointerToPointerVariable() { + reset(); + GET_SYMBOL_DB("std::deque*** ints;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("ints", vartok->str()); + ASSERT_EQUALS("deque", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariableDeclarationIdentifiesTemplatedArrayVariable() { + reset(); + GET_SYMBOL_DB("std::deque ints[3];"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("ints", vartok->str()); + ASSERT_EQUALS("deque", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(true == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariableDeclarationIdentifiesTemplatedVariable() { + reset(); + GET_SYMBOL_DB("std::vector ints;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("ints", vartok->str()); + ASSERT_EQUALS("vector", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariableDeclarationIdentifiesTemplatedVariableIterator() { + reset(); + GET_SYMBOL_DB("std::list::const_iterator floats;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("floats", vartok->str()); + ASSERT_EQUALS("const_iterator", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariableDeclarationIdentifiesNestedTemplateVariable() { + reset(); + GET_SYMBOL_DB("std::deque > intsets;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + ASSERT_EQUALS("intsets", vartok->str()); + ASSERT_EQUALS("deque", typetok->str()); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariableDeclarationIdentifiesReference() { + { + reset(); + GET_SYMBOL_DB("int& foo;"); + const bool result1 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result1); + Variable v1(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v1.isArray()); + ASSERT(false == v1.isPointer()); + ASSERT(true == v1.isReference()); + } + { + reset(); + GET_SYMBOL_DB("foo*& bar;"); + const bool result2 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result2); + Variable v2(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v2.isArray()); + ASSERT(true == v2.isPointer()); + ASSERT(true == v2.isReference()); + } + { + reset(); + GET_SYMBOL_DB("std::vector& foo;"); + const bool result3 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result3); + Variable v3(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v3.isArray()); + ASSERT(false == v3.isPointer()); + ASSERT(true == v3.isReference()); + } + } + + void isVariableDeclarationDoesNotIdentifyTemplateClass() { + reset(); + GET_SYMBOL_DB("template class SomeClass{};"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(false, result); + } + + void isVariableDeclarationDoesNotIdentifyCppCast() { + reset(); + GET_SYMBOL_DB("reinterpret_cast (code)[0] = 0;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(false, result); + } + + void isVariableDeclarationPointerConst() { + reset(); + GET_SYMBOL_DB("std::string const* s;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens()->next(), vartok, typetok); + ASSERT_EQUALS(true, result); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariableDeclarationRValueRef() { + reset(); + GET_SYMBOL_DB("int&& i;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(false == v.isPointer()); + ASSERT(true == v.isReference()); + ASSERT(true == v.isRValueReference()); + ASSERT(tokenizer.tokens()->tokAt(2)->scope() != nullptr); + } + + void isVariableDeclarationDoesNotIdentifyCase() { + GET_SYMBOL_DB_C("a b;\n" + "void f() {\n" + " switch (c) {\n" + " case b:;\n" + " }" + "}"); + const Variable* b = db->getVariableFromVarId(1); + ASSERT_EQUALS("b", b->name()); + ASSERT_EQUALS("a", b->typeStartToken()->str()); + } + + void isVariableDeclarationIf() { + GET_SYMBOL_DB("void foo() {\n" + " for (auto& elem : items) {\n" + " if (auto x = bar()) { int y = 3; }\n" + " }\n" + "}"); + const Token *x = Token::findsimplematch(tokenizer.tokens(), "x"); + ASSERT(x); + ASSERT(x->varId()); + ASSERT(x->variable()); + + const Token *y = Token::findsimplematch(tokenizer.tokens(), "y"); + ASSERT(y); + ASSERT(y->varId()); + ASSERT(y->variable()); + } + + void VariableValueType1() { + GET_SYMBOL_DB("typedef uint8_t u8;\n" + "static u8 x;"); + const Variable* x = db->getVariableFromVarId(1); + ASSERT_EQUALS("x", x->name()); + ASSERT(x->valueType()->isIntegral()); + } + + void VariableValueType2() { + GET_SYMBOL_DB("using u8 = uint8_t;\n" + "static u8 x;"); + const Variable* x = db->getVariableFromVarId(1); + ASSERT_EQUALS("x", x->name()); + ASSERT(x->valueType()->isIntegral()); + } + + void VariableValueType3() { + // std::string::size_type + { + GET_SYMBOL_DB("void f(std::string::size_type x);"); + const Variable* const x = db->getVariableFromVarId(1); + ASSERT_EQUALS("x", x->name()); + // TODO: Configure std::string::size_type somehow. + TODO_ASSERT_EQUALS(ValueType::Type::LONGLONG, ValueType::Type::UNKNOWN_INT, x->valueType()->type); + ASSERT_EQUALS(ValueType::Sign::UNSIGNED, x->valueType()->sign); + } + // std::wstring::size_type + { + GET_SYMBOL_DB("void f(std::wstring::size_type x);"); + const Variable* const x = db->getVariableFromVarId(1); + ASSERT_EQUALS("x", x->name()); + // TODO: Configure std::wstring::size_type somehow. + TODO_ASSERT_EQUALS(ValueType::Type::LONGLONG, ValueType::Type::UNKNOWN_INT, x->valueType()->type); + ASSERT_EQUALS(ValueType::Sign::UNSIGNED, x->valueType()->sign); + } + // std::u16string::size_type + { + GET_SYMBOL_DB("void f(std::u16string::size_type x);"); + const Variable* const x = db->getVariableFromVarId(1); + ASSERT_EQUALS("x", x->name()); + // TODO: Configure std::u16string::size_type somehow. + TODO_ASSERT_EQUALS(ValueType::Type::LONGLONG, ValueType::Type::UNKNOWN_INT, x->valueType()->type); + ASSERT_EQUALS(ValueType::Sign::UNSIGNED, x->valueType()->sign); + } + // std::u32string::size_type + { + GET_SYMBOL_DB("void f(std::u32string::size_type x);"); + const Variable* const x = db->getVariableFromVarId(1); + ASSERT_EQUALS("x", x->name()); + // TODO: Configure std::u32string::size_type somehow. + TODO_ASSERT_EQUALS(ValueType::Type::LONGLONG, ValueType::Type::UNKNOWN_INT, x->valueType()->type); + ASSERT_EQUALS(ValueType::Sign::UNSIGNED, x->valueType()->sign); + } + } + + void VariableValueType4() { + GET_SYMBOL_DB("class C {\n" + "public:\n" + " std::shared_ptr x;\n" + "};"); + + const Variable* const x = db->getVariableFromVarId(1); + ASSERT(x->valueType()); + ASSERT(x->valueType()->smartPointerType); + } + + void VariableValueType5() { + GET_SYMBOL_DB("class C {};\n" + "void foo(std::shared_ptr* p) {}"); + + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->smartPointerTypeToken); + ASSERT(p->valueType()->pointer == 1); + } + + void VariableValueTypeReferences() { + { + GET_SYMBOL_DB("void foo(int x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB("void foo(int* x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->reference == Reference::None); + } + { + GET_SYMBOL_DB("void foo(int& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->reference == Reference::LValue); + } + { + GET_SYMBOL_DB("void foo(int&& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->reference == Reference::RValue); + } + { + GET_SYMBOL_DB("void foo(int*& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->reference == Reference::LValue); + } + { + GET_SYMBOL_DB("void foo(int*&& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->reference == Reference::RValue); + } + { + GET_SYMBOL_DB("void foo(int**& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 2); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->reference == Reference::LValue); + } + { + GET_SYMBOL_DB("void foo(int**&& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 2); + ASSERT(p->valueType()->constness == 0); + ASSERT(p->valueType()->reference == Reference::RValue); + } + { + GET_SYMBOL_DB("void foo(const int& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 1); + ASSERT(p->valueType()->reference == Reference::LValue); + } + { + GET_SYMBOL_DB("void foo(const int&& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 0); + ASSERT(p->valueType()->constness == 1); + ASSERT(p->valueType()->reference == Reference::RValue); + } + { + GET_SYMBOL_DB("void foo(const int*& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->constness == 1); + ASSERT(p->valueType()->reference == Reference::LValue); + } + { + GET_SYMBOL_DB("void foo(const int*&& x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->constness == 1); + ASSERT(p->valueType()->reference == Reference::RValue); + } + { + GET_SYMBOL_DB("void foo(int* const & x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->constness == 2); + ASSERT(p->valueType()->reference == Reference::LValue); + } + { + GET_SYMBOL_DB("void foo(int* const && x) {}\n"); + const Variable* const p = db->getVariableFromVarId(1); + ASSERT(p->valueType()); + ASSERT(p->valueType()->pointer == 1); + ASSERT(p->valueType()->constness == 2); + ASSERT(p->valueType()->reference == Reference::RValue); + } + } + + void findVariableType1() { + GET_SYMBOL_DB("class A {\n" + "public:\n" + " struct B {};\n" + " void f();\n" + "};\n" + "\n" + "void f()\n" + "{\n" + " struct A::B b;\n" + " b.x = 1;\n" + "}"); + ASSERT(db != nullptr); + + const Variable* bvar = db->getVariableFromVarId(1); + ASSERT_EQUALS("b", bvar->name()); + ASSERT(bvar->type() != nullptr); + } + + void findVariableType2() { + GET_SYMBOL_DB("class A {\n" + "public:\n" + " class B {\n" + " public:\n" + " struct C {\n" + " int x;\n" + " int y;\n" + " };\n" + " };\n" + "\n" + " void f();\n" + "};\n" + "\n" + "void A::f()\n" + "{\n" + " struct B::C c;\n" + " c.x = 1;\n" + "}"); + ASSERT(db != nullptr); + + const Variable* cvar = db->getVariableFromVarId(3); + ASSERT_EQUALS("c", cvar->name()); + ASSERT(cvar->type() != nullptr); + } + + void findVariableType3() { + GET_SYMBOL_DB("namespace {\n" + " struct A {\n" + " int x;\n" + " int y;\n" + " };\n" + "}\n" + "\n" + "void f()\n" + "{\n" + " struct A a;\n" + " a.x = 1;\n" + "}"); + (void)db; + const Variable* avar = Token::findsimplematch(tokenizer.tokens(), "a")->variable(); + ASSERT(avar); + ASSERT(avar && avar->type() != nullptr); + } + + void findVariableTypeExternC() { + GET_SYMBOL_DB("extern \"C\" { typedef int INT; }\n" + "void bar() {\n" + " INT x = 3;\n" + "}"); + (void)db; + const Variable* avar = Token::findsimplematch(tokenizer.tokens(), "x")->variable(); + ASSERT(avar); + ASSERT(avar->valueType() != nullptr); + ASSERT(avar->valueType()->str() == "signed int"); + } + + void rangeBasedFor() { + GET_SYMBOL_DB("void reset() {\n" + " for(auto& e : array)\n" + " foo(e);\n" + "}"); + + ASSERT(db != nullptr); + + ASSERT(db->scopeList.back().type == Scope::eFor); + ASSERT_EQUALS(2, db->variableList().size()); + + const Variable* e = db->getVariableFromVarId(1); + ASSERT(e && e->isReference() && e->isLocal()); + } + void isVariableStlType() { + { + reset(); + GET_SYMBOL_DB("std::string s;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + Variable v(vartok, tokenizer.tokens(), tokenizer.list.back(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + static const std::set types = { "string", "wstring" }; + static const std::set no_types = { "set" }; + ASSERT_EQUALS(true, v.isStlType()); + ASSERT_EQUALS(true, v.isStlType(types)); + ASSERT_EQUALS(false, v.isStlType(no_types)); + ASSERT_EQUALS(true, v.isStlStringType()); + } + { + reset(); + GET_SYMBOL_DB("std::vector v;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + Variable v(vartok, tokenizer.tokens(), tokenizer.list.back(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + static const std::set types = { "bitset", "set", "vector", "wstring" }; + static const std::set no_types = { "bitset", "map", "set" }; + ASSERT_EQUALS(true, v.isStlType()); + ASSERT_EQUALS(true, v.isStlType(types)); + ASSERT_EQUALS(false, v.isStlType(no_types)); + ASSERT_EQUALS(false, v.isStlStringType()); + } + { + reset(); + GET_SYMBOL_DB("SomeClass s;"); + const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + Variable v(vartok, tokenizer.tokens(), tokenizer.list.back(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + static const std::set types = { "bitset", "set", "vector" }; + ASSERT_EQUALS(false, v.isStlType()); + ASSERT_EQUALS(false, v.isStlType(types)); + ASSERT_EQUALS(false, v.isStlStringType()); + } + } + + void isVariablePointerToConstPointer() { + reset(); + GET_SYMBOL_DB("char* const * s;"); + bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariablePointerToVolatilePointer() { + reset(); + GET_SYMBOL_DB("char* volatile * s;"); + bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariablePointerToConstVolatilePointer() { + reset(); + GET_SYMBOL_DB("char* const volatile * s;"); + bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok); + ASSERT_EQUALS(true, result); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void isVariableMultiplePointersAndQualifiers() { + reset(); + GET_SYMBOL_DB("const char* const volatile * const volatile * const volatile * const volatile s;"); + bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens()->next(), vartok, typetok); + ASSERT_EQUALS(true, result); + Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1); + ASSERT(false == v.isArray()); + ASSERT(true == v.isPointer()); + ASSERT(false == v.isReference()); + } + + void variableVolatile() { + GET_SYMBOL_DB("std::atomic x;\n" + "volatile int y;"); + + const Token *x = Token::findsimplematch(tokenizer.tokens(), "x"); + ASSERT(x); + ASSERT(x->variable()); + ASSERT(x->variable()->isVolatile()); + + const Token *y = Token::findsimplematch(tokenizer.tokens(), "y"); + ASSERT(y); + ASSERT(y->variable()); + ASSERT(y->variable()->isVolatile()); + } + + void variableConstexpr() { + GET_SYMBOL_DB("constexpr int x = 16;"); + + const Token *x = Token::findsimplematch(tokenizer.tokens(), "x"); + ASSERT(x); + ASSERT(x->variable()); + ASSERT(x->variable()->isConst()); + ASSERT(x->variable()->isStatic()); + ASSERT(x->valueType()); + ASSERT(x->valueType()->pointer == 0); + ASSERT(x->valueType()->constness == 1); + ASSERT(x->valueType()->reference == Reference::None); + } + + void isVariableDecltype() { + GET_SYMBOL_DB("int x;\n" + "decltype(x) a;\n" + "const decltype(x) b;\n" + "decltype(x) *c;\n"); + ASSERT(db); + ASSERT_EQUALS(4, db->scopeList.front().varlist.size()); + + const Variable *a = Token::findsimplematch(tokenizer.tokens(), "a")->variable(); + ASSERT(a); + ASSERT_EQUALS("a", a->name()); + ASSERT(a->valueType()); + ASSERT_EQUALS("signed int", a->valueType()->str()); + + const Variable *b = Token::findsimplematch(tokenizer.tokens(), "b")->variable(); + ASSERT(b); + ASSERT_EQUALS("b", b->name()); + ASSERT(b->valueType()); + ASSERT_EQUALS("const signed int", b->valueType()->str()); + + const Variable *c = Token::findsimplematch(tokenizer.tokens(), "c")->variable(); + ASSERT(c); + ASSERT_EQUALS("c", c->name()); + ASSERT(c->valueType()); + ASSERT_EQUALS("signed int *", c->valueType()->str()); + } + + void arrayMemberVar1() { + GET_SYMBOL_DB("struct Foo {\n" + " int x;\n" + "};\n" + "void f() {\n" + " struct Foo foo[10];\n" + " foo[1].x = 123;\n" // <- x should get a variable() pointer + "}"); + + const Token *tok = Token::findsimplematch(tokenizer.tokens(), ". x"); + tok = tok ? tok->next() : nullptr; + ASSERT(db != nullptr); + ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;")); + ASSERT(tok && tok->varId() == 3U); // It's possible to set a varId + } + + void arrayMemberVar2() { + GET_SYMBOL_DB("struct Foo {\n" + " int x;\n" + "};\n" + "void f() {\n" + " struct Foo foo[10][10];\n" + " foo[1][2].x = 123;\n" // <- x should get a variable() pointer + "}"); + + const Token *tok = Token::findsimplematch(tokenizer.tokens(), ". x"); + tok = tok ? tok->next() : nullptr; + ASSERT(db != nullptr); + ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;")); + ASSERT(tok && tok->varId() == 3U); // It's possible to set a varId + } + + void arrayMemberVar3() { + GET_SYMBOL_DB("struct Foo {\n" + " int x;\n" + "};\n" + "void f() {\n" + " struct Foo foo[10];\n" + " (foo[1]).x = 123;\n" // <- x should get a variable() pointer + "}"); + + const Token *tok = Token::findsimplematch(tokenizer.tokens(), ". x"); + tok = tok ? tok->next() : nullptr; + ASSERT(db != nullptr); + ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;")); + ASSERT(tok && tok->varId() == 3U); // It's possible to set a varId + } + + void staticMemberVar() { + GET_SYMBOL_DB("class Foo {\n" + " static const double d;\n" + "};\n" + "const double Foo::d = 5.0;"); + + const Variable* v = db->getVariableFromVarId(1); + ASSERT(v && db->variableList().size() == 2); + ASSERT(v && v->isStatic() && v->isConst() && v->isPrivate()); + } + + void getVariableFromVarIdBoundsCheck() { + GET_SYMBOL_DB("int x;\n" + "int y;"); + + const Variable* v = db->getVariableFromVarId(2); + // three elements: varId 0 also counts via a fake-entry + ASSERT(v && db->variableList().size() == 3); + + ASSERT_THROW(db->getVariableFromVarId(3), std::out_of_range); + } + + void hasRegularFunction() { + GET_SYMBOL_DB("void func() { }"); + + // 2 scopes: Global and Function + ASSERT(db && db->scopeList.size() == 2); + + const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->next()); + + ASSERT(scope && scope->className == "func"); + + ASSERT(scope->functionOf == nullptr); + + const Function *function = findFunctionByName("func", &db->scopeList.front()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->next()); + ASSERT(function && function->hasBody()); + ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn != scope); + ASSERT(function && function->retDef == tokenizer.tokens()); + } + + void hasRegularFunction_trailingReturnType() { + GET_SYMBOL_DB("auto func() -> int { }"); + + // 2 scopes: Global and Function + ASSERT(db && db->scopeList.size() == 2); + + const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->next()); + + ASSERT(scope && scope->className == "func"); + + ASSERT(scope->functionOf == nullptr); + + const Function *function = findFunctionByName("func", &db->scopeList.front()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == tokenizer.tokens()->next()); + ASSERT(function && function->hasBody()); + ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn != scope); + ASSERT(function && function->retDef == tokenizer.tokens()->tokAt(5)); + } + + void hasInlineClassFunction() { + GET_SYMBOL_DB("class Fred { void func() { } };"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "func"); + + ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred")); + + const Function *function = findFunctionByName("func", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody() && function->isInline()); + ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred")); + ASSERT(function && function->retDef == functionToken->previous()); + + ASSERT(db && db->findScopeByName("Fred") && db->findScopeByName("Fred")->definedType->getFunction("func") == function); + } + + + void hasInlineClassFunction_trailingReturnType() { + GET_SYMBOL_DB("class Fred { auto func() -> int { } };"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "func"); + + ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred")); + + const Function *function = findFunctionByName("func", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody() && function->isInline()); + ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred")); + ASSERT(function && function->retDef == functionToken->tokAt(4)); + + ASSERT(db && db->findScopeByName("Fred") && db->findScopeByName("Fred")->definedType->getFunction("func") == function); + } + + void hasMissingInlineClassFunction() { + GET_SYMBOL_DB("class Fred { void func(); };"); + + // 2 scopes: Global and Class (no Function scope because there is no function implementation) + ASSERT(db && db->scopeList.size() == 2); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope == nullptr); + + const Function *function = findFunctionByName("func", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && !function->hasBody()); + } + + void hasInlineClassOperatorTemplate() { + GET_SYMBOL_DB("struct Fred { template Foo & operator=(const Foo &) { return *this; } };"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "operator="); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "operator="); + + ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred")); + + const Function *function = findFunctionByName("operator=", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "operator="); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody() && function->isInline()); + ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred")); + ASSERT(function && function->retDef == functionToken->tokAt(-2)); + + ASSERT(db && db->findScopeByName("Fred") && db->findScopeByName("Fred")->definedType->getFunction("operator=") == function); + } + + void hasClassFunction() { + GET_SYMBOL_DB("class Fred { void func(); }; void Fred::func() { }"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens()->linkAt(2), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "func"); + + ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred")); + + const Function *function = findFunctionByName("func", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody() && !function->isInline()); + ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred")); + } + + void hasClassFunction_trailingReturnType() { + GET_SYMBOL_DB("class Fred { auto func() -> int; }; auto Fred::func() -> int { }"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens()->linkAt(2), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "func"); + + ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred")); + + const Function *function = findFunctionByName("func", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody() && !function->isInline()); + ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred")); + } + + void hasClassFunction_decltype_auto() + { + GET_SYMBOL_DB("struct d { decltype(auto) f() {} };"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token* const functionToken = Token::findsimplematch(tokenizer.tokens(), "f"); + + const Scope* scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "f"); + + ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("d")); + + const Function* function = findFunctionByName("f", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "f"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody()); + } + + void hasRegularFunctionReturningFunctionPointer() { + GET_SYMBOL_DB("void (*func(int f))(char) { }"); + + // 2 scopes: Global and Function + ASSERT(db && db->scopeList.size() == 2); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "func"); + + const Function *function = findFunctionByName("func", &db->scopeList.front()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody()); + } + + void hasInlineClassFunctionReturningFunctionPointer() { + GET_SYMBOL_DB("class Fred { void (*func(int f))(char) { } };"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "func"); + + const Function *function = findFunctionByName("func", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody() && function->isInline()); + } + + void hasMissingInlineClassFunctionReturningFunctionPointer() { + GET_SYMBOL_DB("class Fred { void (*func(int f))(char); };"); + + // 2 scopes: Global and Class (no Function scope because there is no function implementation) + ASSERT(db && db->scopeList.size() == 2); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope == nullptr); + + const Function *function = findFunctionByName("func", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && !function->hasBody()); + } + + void hasClassFunctionReturningFunctionPointer() { + GET_SYMBOL_DB("class Fred { void (*func(int f))(char); }; void (*Fred::func(int f))(char) { }"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens()->linkAt(2), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "func"); + + const Function *function = findFunctionByName("func", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody() && !function->isInline()); + } + + void methodWithRedundantScope() { + GET_SYMBOL_DB("class Fred { void Fred::func() {} };"); + + // 3 scopes: Global, Class, and Function + ASSERT(db && db->scopeList.size() == 3); + + const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func"); + + const Scope *scope = findFunctionScopeByToken(db, functionToken); + + ASSERT(scope && scope->className == "func"); + + const Function *function = findFunctionByName("func", &db->scopeList.back()); + + ASSERT(function && function->token->str() == "func"); + ASSERT(function && function->token == functionToken); + ASSERT(function && function->hasBody() && function->isInline()); + } + + void complexFunctionArrayPtr() { + GET_SYMBOL_DB("int(*p1)[10]; \n" // pointer to array 10 of int + "void(*p2)(char); \n" // pointer to function (char) returning void + "int(*(*p3)(char))[10];\n" // pointer to function (char) returning pointer to array 10 of int + "float(*(*p4)(char))(long); \n" // pointer to function (char) returning pointer to function (long) returning float + "short(*(*(*p5) (char))(long))(double);\n" // pointer to function (char) returning pointer to function (long) returning pointer to function (double) returning short + "int(*a1[10])(void); \n" // array 10 of pointer to function (void) returning int + "float(*(*a2[10])(char))(long);\n" // array 10 of pointer to func (char) returning pointer to func (long) returning float + "short(*(*(*a3[10])(char))(long))(double);\n" // array 10 of pointer to function (char) returning pointer to function (long) returning pointer to function (double) returning short + "::boost::rational(&r_)[9];\n" // reference to array of ::boost::rational + "::boost::rational(&r_)[9];"); // reference to array of ::boost::rational (template!) + + ASSERT(db != nullptr); + + ASSERT_EQUALS(10, db->variableList().size() - 1); + ASSERT_EQUALS(true, db->getVariableFromVarId(1) && db->getVariableFromVarId(1)->dimensions().size() == 1); + ASSERT_EQUALS(true, db->getVariableFromVarId(2) != nullptr); + ASSERT_EQUALS(true, db->getVariableFromVarId(3) && db->getVariableFromVarId(3)->dimensions().size() == 0); + ASSERT_EQUALS(true, db->getVariableFromVarId(4) != nullptr); + ASSERT_EQUALS(true, db->getVariableFromVarId(5) != nullptr); + ASSERT_EQUALS(true, db->getVariableFromVarId(6) && db->getVariableFromVarId(6)->dimensions().size() == 1); + ASSERT_EQUALS(true, db->getVariableFromVarId(7) && db->getVariableFromVarId(7)->dimensions().size() == 1); + ASSERT_EQUALS(true, db->getVariableFromVarId(8) && db->getVariableFromVarId(8)->dimensions().size() == 1); + ASSERT_EQUALS(true, db->getVariableFromVarId(9) && db->getVariableFromVarId(9)->dimensions().size() == 1); + ASSERT_EQUALS(true, db->getVariableFromVarId(10) && db->getVariableFromVarId(10)->dimensions().size() == 1); + ASSERT_EQUALS("", errout.str()); + } + + void pointerToMemberFunction() { + GET_SYMBOL_DB("bool (A::*pFun)();"); // Pointer to member function of A, returning bool and taking no parameters + + ASSERT(db != nullptr); + + ASSERT_EQUALS(1, db->variableList().size() - 1); + ASSERT_EQUALS(true, db->getVariableFromVarId(1) != nullptr); + + ASSERT_EQUALS("pFun", db->getVariableFromVarId(1)->name()); + ASSERT_EQUALS("", errout.str()); + } + + void hasSubClassConstructor() { + GET_SYMBOL_DB("class Foo { class Sub; }; class Foo::Sub { Sub() {} };"); + ASSERT(db != nullptr); + + bool seen_something = false; + for (const Scope & scope : db->scopeList) { + for (std::list::const_iterator func = scope.functionList.begin(); func != scope.functionList.end(); ++func) { + ASSERT_EQUALS("Sub", func->token->str()); + ASSERT_EQUALS(true, func->hasBody()); + ASSERT_EQUALS(Function::eConstructor, func->type); + seen_something = true; + } + } + ASSERT_EQUALS(true, seen_something); + } + + void testConstructors() { + { + GET_SYMBOL_DB("class Foo { Foo(); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor && !ctor->isExplicit()); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("class Foo { explicit Foo(Foo f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(4)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor && ctor->isExplicit()); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("class Foo { Foo(Bar& f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo& f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eCopyConstructor); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("class Foo { Foo(const Foo &f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eCopyConstructor); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("template class Foo { Foo(Foo& f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(7)->function(); + ASSERT(db && ctor && ctor->type == Function::eCopyConstructor); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo& f, int default = 0); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eCopyConstructor); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo& f, char noDefault); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eConstructor); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo&& f); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eMoveConstructor); + ASSERT(ctor && ctor->retDef == nullptr); + } + { + GET_SYMBOL_DB("class Foo { Foo(Foo&& f, int default = 1, bool defaultToo = true); };"); + const Function* ctor = tokenizer.tokens()->tokAt(3)->function(); + ASSERT(db && ctor && ctor->type == Function::eMoveConstructor); + ASSERT(ctor && ctor->retDef == nullptr); + } + } + + void functionDeclarationTemplate() { + GET_SYMBOL_DB("std::map foo() {}"); + + // 2 scopes: Global and Function + ASSERT(db && db->scopeList.size() == 2 && findFunctionByName("foo", &db->scopeList.back())); + + const Scope *scope = &db->scopeList.front(); + + ASSERT(scope && scope->functionList.size() == 1); + + const Function *foo = &scope->functionList.front(); + + ASSERT(foo && foo->token->str() == "foo"); + ASSERT(foo && foo->hasBody()); + } + + void functionDeclarations() { + GET_SYMBOL_DB("void foo();\nvoid foo();\nint foo(int i);\nvoid foo() {}"); + + // 2 scopes: Global and Function + ASSERT(db && db->scopeList.size() == 2 && findFunctionByName("foo", &db->scopeList.back())); + + const Scope *scope = &db->scopeList.front(); + + ASSERT(scope && scope->functionList.size() == 2); + + const Function *foo = &scope->functionList.front(); + const Function *foo_int = &scope->functionList.back(); + + ASSERT(foo && foo->token->str() == "foo"); + ASSERT(foo && foo->hasBody()); + ASSERT(foo && foo->token->strAt(2) == ")"); + + ASSERT(foo_int && !foo_int->token); + ASSERT(foo_int && foo_int->tokenDef->str() == "foo"); + ASSERT(foo_int && !foo_int->hasBody()); + ASSERT(foo_int && foo_int->tokenDef->strAt(2) == "int"); + + ASSERT(&foo_int->argumentList.front() == db->getVariableFromVarId(1)); + } + + void functionDeclarations2() { + GET_SYMBOL_DB_STD("std::array foo(int x);"); + + // 1 scopes: Global + ASSERT(db && db->scopeList.size() == 1); + + const Scope *scope = &db->scopeList.front(); + + ASSERT(scope && scope->functionList.size() == 1); + + const Function *foo = &scope->functionList.front(); + + ASSERT(foo); + ASSERT(foo->tokenDef->str() == "foo"); + ASSERT(!foo->hasBody()); + + const Token*parenthesis = foo->tokenDef->next(); + ASSERT(parenthesis->str() == "(" && parenthesis->previous()->str() == "foo"); + ASSERT(parenthesis->valueType()->type == ValueType::Type::CONTAINER); + } + + void constexprFunction() { + GET_SYMBOL_DB_STD("constexpr int foo();"); + + // 1 scopes: Global + ASSERT(db && db->scopeList.size() == 1); + + const Scope *scope = &db->scopeList.front(); + + ASSERT(scope && scope->functionList.size() == 1); + + const Function *foo = &scope->functionList.front(); + + ASSERT(foo); + ASSERT(foo->tokenDef->str() == "foo"); + ASSERT(!foo->hasBody()); + ASSERT(foo->isConstexpr()); + } + + void constructorInitialization() { + GET_SYMBOL_DB("std::string logfile;\n" + "std::ofstream log(logfile.c_str(), std::ios::out);"); + + // 1 scope: Global + ASSERT(db && db->scopeList.size() == 1); + + // No functions + ASSERT(db->scopeList.front().functionList.empty()); + } + + void memberFunctionOfUnknownClassMacro1() { + GET_SYMBOL_DB("class ScVbaFormatCondition { OUString getServiceImplName() SAL_OVERRIDE; };\n" + "void ScVbaValidation::getFormula1() {\n" + " sal_uInt16 nFlags = 0;\n" + " if (pDocSh && !getCellRangesForAddress(nFlags)) ;\n" + "}"); + + ASSERT(db && errout.str().empty()); + + const Scope *scope = db->findScopeByName("getFormula1"); + ASSERT(scope != nullptr); + ASSERT(scope && scope->nestedIn == &db->scopeList.front()); + } + + void memberFunctionOfUnknownClassMacro2() { + GET_SYMBOL_DB("class ScVbaFormatCondition { OUString getServiceImplName() SAL_OVERRIDE {} };\n" + "void getFormula1() {\n" + " sal_uInt16 nFlags = 0;\n" + " if (pDocSh && !getCellRangesForAddress(nFlags)) ;\n" + "}"); + + ASSERT(db && errout.str().empty()); + + const Scope *scope = db->findScopeByName("getFormula1"); + ASSERT(scope != nullptr); + ASSERT(scope && scope->nestedIn == &db->scopeList.front()); + + scope = db->findScopeByName("getServiceImplName"); + ASSERT(scope != nullptr); + ASSERT(scope && scope->nestedIn && scope->nestedIn->className == "ScVbaFormatCondition"); + } + + void memberFunctionOfUnknownClassMacro3() { + GET_SYMBOL_DB("class ScVbaFormatCondition { OUString getServiceImplName() THROW(whatever); };\n" + "void ScVbaValidation::getFormula1() {\n" + " sal_uInt16 nFlags = 0;\n" + " if (pDocSh && !getCellRangesForAddress(nFlags)) ;\n" + "}"); + + ASSERT(db && errout.str().empty()); + + const Scope *scope = db->findScopeByName("getFormula1"); + ASSERT(scope != nullptr); + ASSERT(scope && scope->nestedIn == &db->scopeList.front()); + } + + void functionLinkage() { + GET_SYMBOL_DB("static void f1() { }\n" + "void f2();\n" + "extern void f3();\n" + "void f4();\n" + "extern void f5() { };\n" + "void f6() { }"); + + ASSERT(db && errout.str().empty()); + + const Token *f = Token::findsimplematch(tokenizer.tokens(), "f1"); + ASSERT(f && f->function() && f->function()->isStaticLocal() && f->function()->retDef->str() == "void"); + + f = Token::findsimplematch(tokenizer.tokens(), "f2"); + ASSERT(f && f->function() && !f->function()->isStaticLocal() && f->function()->retDef->str() == "void"); + + f = Token::findsimplematch(tokenizer.tokens(), "f3"); + ASSERT(f && f->function() && f->function()->isExtern() && f->function()->retDef->str() == "void"); + + f = Token::findsimplematch(tokenizer.tokens(), "f4"); + ASSERT(f && f->function() && !f->function()->isExtern() && f->function()->retDef->str() == "void"); + + f = Token::findsimplematch(tokenizer.tokens(), "f5"); + ASSERT(f && f->function() && f->function()->isExtern() && f->function()->retDef->str() == "void"); + + f = Token::findsimplematch(tokenizer.tokens(), "f6"); + ASSERT(f && f->function() && !f->function()->isExtern() && f->function()->retDef->str() == "void"); + } + + void classWithFriend() { + GET_SYMBOL_DB("class Foo {}; class Bar1 { friend class Foo; }; class Bar2 { friend Foo; };"); + // 3 scopes: Global, 3 classes + ASSERT(db && db->scopeList.size() == 4); + + const Scope* foo = db->findScopeByName("Foo"); + ASSERT(foo != nullptr); + const Scope* bar1 = db->findScopeByName("Bar1"); + ASSERT(bar1 != nullptr); + const Scope* bar2 = db->findScopeByName("Bar2"); + ASSERT(bar2 != nullptr); + + ASSERT(bar1->definedType->friendList.size() == 1 && bar1->definedType->friendList.front().nameEnd->str() == "Foo" && bar1->definedType->friendList.front().type == foo->definedType); + ASSERT(bar2->definedType->friendList.size() == 1 && bar2->definedType->friendList.front().nameEnd->str() == "Foo" && bar2->definedType->friendList.front().type == foo->definedType); + } + + void parseFunctionCorrect() { + // ticket 3188 - "if" statement parsed as function + GET_SYMBOL_DB("void func(i) int i; { if (i == 1) return; }"); + ASSERT(db != nullptr); + + // 3 scopes: Global, function, if + ASSERT_EQUALS(3, db->scopeList.size()); + + ASSERT(findFunctionByName("func", &db->scopeList.back()) != nullptr); + ASSERT(findFunctionByName("if", &db->scopeList.back()) == nullptr); + } + + void parseFunctionDeclarationCorrect() { + GET_SYMBOL_DB("void func();\n" + "int bar() {}\n" + "void func() {}"); + ASSERT_EQUALS(3, db->findScopeByName("func")->bodyStart->linenr()); + } + + void Cpp11InitInInitList() { + GET_SYMBOL_DB("class Foo {\n" + " std::vector bar;\n" + " Foo() : bar({\"a\", \"b\"})\n" + " {}\n" + "};"); + ASSERT_EQUALS(4, db->scopeList.front().nestedList.front()->nestedList.front()->bodyStart->linenr()); + } + + void hasGlobalVariables1() { + GET_SYMBOL_DB("int i;"); + + ASSERT(db && db->scopeList.size() == 1); + + std::list::const_iterator it = db->scopeList.begin(); + ASSERT(it->varlist.size() == 1); + std::list::const_iterator var = it->varlist.begin(); + ASSERT(var->name() == "i"); + ASSERT(var->typeStartToken()->str() == "int"); + } + + void hasGlobalVariables2() { + GET_SYMBOL_DB("int array[2][2];"); + + ASSERT(db && db->scopeList.size() == 1); + + std::list::const_iterator it = db->scopeList.begin(); + ASSERT(it->varlist.size() == 1); + + std::list::const_iterator var = it->varlist.begin(); + ASSERT(var->name() == "array"); + ASSERT(var->typeStartToken()->str() == "int"); + } + + void hasGlobalVariables3() { + GET_SYMBOL_DB("int array[2][2] = { { 0, 0 }, { 0, 0 } };"); + + ASSERT(db && db->scopeList.size() == 1); + + std::list::const_iterator it = db->scopeList.begin(); + ASSERT(it->varlist.size() == 1); + + std::list::const_iterator var = it->varlist.begin(); + ASSERT(var->name() == "array"); + ASSERT(var->typeStartToken()->str() == "int"); + } + + void checkTypeStartEndToken1() { + GET_SYMBOL_DB("static std::string i;\n" + "static const std::string j;\n" + "const std::string* k;\n" + "const char m[];\n" + "void f(const char* const l;) {}"); + + ASSERT(db && db->variableList().size() == 6 && db->getVariableFromVarId(1) && db->getVariableFromVarId(2) && db->getVariableFromVarId(3) && db->getVariableFromVarId(4) && db->getVariableFromVarId(5)); + + ASSERT_EQUALS("std", db->getVariableFromVarId(1)->typeStartToken()->str()); + ASSERT_EQUALS("std", db->getVariableFromVarId(2)->typeStartToken()->str()); + ASSERT_EQUALS("std", db->getVariableFromVarId(3)->typeStartToken()->str()); + ASSERT_EQUALS("char", db->getVariableFromVarId(4)->typeStartToken()->str()); + ASSERT_EQUALS("char", db->getVariableFromVarId(5)->typeStartToken()->str()); + + ASSERT_EQUALS("string", db->getVariableFromVarId(1)->typeEndToken()->str()); + ASSERT_EQUALS("string", db->getVariableFromVarId(2)->typeEndToken()->str()); + ASSERT_EQUALS("*", db->getVariableFromVarId(3)->typeEndToken()->str()); + ASSERT_EQUALS("char", db->getVariableFromVarId(4)->typeEndToken()->str()); + ASSERT_EQUALS("*", db->getVariableFromVarId(5)->typeEndToken()->str()); + } + + void checkTypeStartEndToken2() { + GET_SYMBOL_DB("class CodeGenerator {\n" + " DiagnosticsEngine Diags;\n" + "public:\n" + " void Initialize() {\n" + " Builder.reset(Diags);\n" + " }\n" + "\n" + " void HandleTagDeclRequiredDefinition() LLVM_OVERRIDE {\n" + " if (Diags.hasErrorOccurred())\n" + " return;\n" + " }\n" + "};"); + ASSERT_EQUALS("DiagnosticsEngine", db->getVariableFromVarId(1)->typeStartToken()->str()); + } + + void checkTypeStartEndToken3() { + GET_SYMBOL_DB("void f(const char) {}"); + + ASSERT(db && db->functionScopes.size()==1U); + + const Function * const f = db->functionScopes.front()->function; + ASSERT_EQUALS(1U, f->argCount()); + ASSERT_EQUALS(0U, f->initializedArgCount()); + ASSERT_EQUALS(1U, f->minArgCount()); + const Variable * const arg1 = f->getArgumentVar(0); + ASSERT_EQUALS("char", arg1->typeStartToken()->str()); + ASSERT_EQUALS("char", arg1->typeEndToken()->str()); + } + +#define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) + void check_(const char* file, int line, const char code[], bool debug = true, const char filename[] = "test.cpp") { + // Clear the error log + errout.str(""); + + // Check.. + settings1.debugwarnings = debug; + + // Tokenize.. + Tokenizer tokenizer(&settings1, this); + std::istringstream istr(code); + ASSERT_LOC(tokenizer.tokenize(istr, filename), file, line); + + // force symbol database creation + tokenizer.createSymbolDatabase(); + + settings1.debugwarnings = false; + } + + void functionArgs1() { + { + GET_SYMBOL_DB("void f(std::vector, const std::vector & v) { }"); + ASSERT_EQUALS(1+1, db->variableList().size()); + const Variable* v = db->getVariableFromVarId(1); + ASSERT(v && v->isReference() && v->isConst() && v->isArgument()); + const Scope* f = db->findScopeByName("f"); + ASSERT(f && f->type == Scope::eFunction && f->function); + + ASSERT(f->function->argumentList.size() == 2 && f->function->argumentList.front().index() == 0 && f->function->argumentList.front().name() == "" && f->function->argumentList.back().index() == 1); + ASSERT_EQUALS("", errout.str()); + } + { + GET_SYMBOL_DB("void g(std::map > m) { }"); + ASSERT_EQUALS(1+1, db->variableList().size()); + const Variable* m = db->getVariableFromVarId(1); + ASSERT(m && !m->isReference() && !m->isConst() && m->isArgument() && m->isClass()); + const Scope* g = db->findScopeByName("g"); + ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().index() == 0); + ASSERT_EQUALS("", errout.str()); + } + { + GET_SYMBOL_DB("void g(std::map m = std::map()) { }"); + const Scope* g = db->findScopeByName("g"); + ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().index() == 0 && g->function->initializedArgCount() == 1); + ASSERT_EQUALS("", errout.str()); + } + { + GET_SYMBOL_DB("void g(int = 0) { }"); + const Scope* g = db->findScopeByName("g"); + ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().hasDefault()); + ASSERT_EQUALS("", errout.str()); + } + { + GET_SYMBOL_DB("void g(int*) { }"); // unnamed pointer argument (#8052) + const Scope* g = db->findScopeByName("g"); + ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().nameToken() == nullptr && g->function->argumentList.front().isPointer()); + ASSERT_EQUALS("", errout.str()); + } + { + GET_SYMBOL_DB("void g(int* const) { }"); // 'const' is not the name of the variable - #5882 + const Scope* g = db->findScopeByName("g"); + ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().nameToken() == nullptr); + ASSERT_EQUALS("", errout.str()); + } + } + + void functionArgs2() { + GET_SYMBOL_DB("void f(int a[][4]) { }"); + const Variable *a = db->getVariableFromVarId(1); + ASSERT_EQUALS("a", a->nameToken()->str()); + ASSERT_EQUALS(2UL, a->dimensions().size()); + ASSERT_EQUALS(0UL, a->dimension(0)); + ASSERT_EQUALS(false, a->dimensions()[0].known); + ASSERT_EQUALS(4UL, a->dimension(1)); + ASSERT_EQUALS(true, a->dimensions()[1].known); + } + + void functionArgs4() { + GET_SYMBOL_DB("void f1(char [10], struct foo [10]);"); + ASSERT_EQUALS(true, db->scopeList.front().functionList.size() == 1UL); + const Function *func = &db->scopeList.front().functionList.front(); + ASSERT_EQUALS(true, func && func->argumentList.size() == 2UL); + + const Variable *first = &func->argumentList.front(); + ASSERT_EQUALS(0UL, first->name().size()); + ASSERT_EQUALS(1UL, first->dimensions().size()); + ASSERT_EQUALS(10UL, first->dimension(0)); + const Variable *second = &func->argumentList.back(); + ASSERT_EQUALS(0UL, second->name().size()); + ASSERT_EQUALS(1UL, second->dimensions().size()); + ASSERT_EQUALS(10UL, second->dimension(0)); + } + + void functionArgs5() { // #7650 + GET_SYMBOL_DB("class ABC {};\n" + "class Y {\n" + " enum ABC {A,B,C};\n" + " void f(enum ABC abc) {}\n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( enum"); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->isEnumType()); + } + + void functionArgs6() { // #7651 + GET_SYMBOL_DB("class ABC {};\n" + "class Y {\n" + " enum ABC {A,B,C};\n" + " void f(ABC abc) {}\n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( ABC"); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->isEnumType()); + } + + void functionArgs7() { // #7652 + { + GET_SYMBOL_DB("struct AB { int a; int b; };\n" + "int foo(struct AB *ab);\n" + "void bar() {\n" + " struct AB ab;\n" + " foo(&ab);\n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->classDef->linenr() == 1); + } + { + GET_SYMBOL_DB("struct AB { int a; int b; };\n" + "int foo(AB *ab);\n" + "void bar() {\n" + " struct AB ab;\n" + " foo(&ab);\n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->classDef->linenr() == 1); + } + { + GET_SYMBOL_DB("struct AB { int a; int b; };\n" + "int foo(struct AB *ab);\n" + "void bar() {\n" + " AB ab;\n" + " foo(&ab);\n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->classDef->linenr() == 1); + } + { + GET_SYMBOL_DB("struct AB { int a; int b; };\n" + "int foo(AB *ab);\n" + "void bar() {\n" + " AB ab;\n" + " foo(&ab);\n" + "};"); + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->classDef->linenr() == 1); + } + } + + void functionArgs8() { // #7653 + GET_SYMBOL_DB("struct A { int i; };\n" + "struct B { double d; };\n" + "int foo(struct A a);\n" + "double foo(struct B b);\n" + "void bar() {\n" + " struct B b;\n" + " foo(b);\n" + "}"); + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( b"); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->tokenDef->linenr() == 4 && func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->isStructType()); + } + + void functionArgs9() { // #7657 + GET_SYMBOL_DB("struct A {\n" + " struct B {\n" + " enum C { };\n" + " };\n" + "};\n" + "void foo(A::B::C c) { }"); + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ("); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->isEnumType()); + } + + void functionArgs10() { + GET_SYMBOL_DB("class Fred {\n" + "public:\n" + " Fred(Whitespace = PRESERVE_WHITESPACE);\n" + "};\n" + "Fred::Fred(Whitespace whitespace) { }"); + ASSERT_EQUALS(true, db != nullptr); + ASSERT_EQUALS(3, db->scopeList.size()); + std::list::const_iterator scope = db->scopeList.begin(); + ++scope; + ASSERT_EQUALS((unsigned int)Scope::eClass, (unsigned int)scope->type); + ASSERT_EQUALS(1, scope->functionList.size()); + ASSERT(scope->functionList.begin()->functionScope != nullptr); + const Scope * functionScope = scope->functionList.begin()->functionScope; + ++scope; + ASSERT(functionScope == &*scope); + } + + void functionArgs11() { + GET_SYMBOL_DB("class Fred {\n" + "public:\n" + " void foo(char a[16]);\n" + "};\n" + "void Fred::foo(char b[16]) { }"); + ASSERT_EQUALS(true, db != nullptr); + ASSERT_EQUALS(3, db->scopeList.size()); + std::list::const_iterator scope = db->scopeList.begin(); + ++scope; + ASSERT_EQUALS((unsigned int)Scope::eClass, (unsigned int)scope->type); + ASSERT_EQUALS(1, scope->functionList.size()); + ASSERT(scope->functionList.begin()->functionScope != nullptr); + const Scope * functionScope = scope->functionList.begin()->functionScope; + ++scope; + ASSERT(functionScope == &*scope); + } + + void functionArgs12() { // #7661 + GET_SYMBOL_DB("struct A {\n" + " enum E { };\n" + " int a[10];\n" + "};\n" + "struct B : public A {\n" + " void foo(B::E e) { }\n" + "};"); + + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ("); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->isEnumType()); + } + + void functionArgs13() { // #7697 + GET_SYMBOL_DB("struct A {\n" + " enum E { };\n" + " struct S { };\n" + "};\n" + "struct B : public A {\n" + " B(E e);\n" + " B(S s);\n" + "};\n" + "B::B(A::E e) { }\n" + "B::B(A::S s) { }"); + + ASSERT_EQUALS(true, db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "B ( A :: E"); + ASSERT_EQUALS(true, f && f->function()); + const Function *func = f->function(); + ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); + const Type * type = func->argumentList.front().type(); + ASSERT_EQUALS(true, type->isEnumType() && type->name() == "E"); + + f = Token::findsimplematch(tokenizer.tokens(), "B ( A :: S"); + ASSERT_EQUALS(true, f && f->function()); + const Function *func2 = f->function(); + ASSERT_EQUALS(true, func2->argumentList.size() == 1 && func2->argumentList.front().type()); + const Type * type2 = func2->argumentList.front().type(); + ASSERT_EQUALS(true, type2->isStructType() && type2->name() == "S"); + } + + void functionArgs14() { // #7697 + GET_SYMBOL_DB("void f(int (&a)[10], int (&b)[10]);"); + (void)db; + const Function *func = tokenizer.tokens()->next()->function(); + ASSERT_EQUALS(true, func != nullptr); + ASSERT_EQUALS(2, func ? func->argCount() : 0); + ASSERT_EQUALS(0, func ? func->initializedArgCount() : 1); + ASSERT_EQUALS(2, func ? func->minArgCount() : 0); + } + + void functionArgs15() { // #7159 + const char code[] = + "class Class {\n" + " void Method(\n" + " char c = []()->char {\n" + " int d = rand();\n"// the '=' on this line used to reproduce the defect + " return d;\n" + " }()\n" + " );\n" + "};\n"; + GET_SYMBOL_DB(code); + ASSERT(db); + ASSERT_EQUALS(2, db->scopeList.size()); + const Scope& classScope = db->scopeList.back(); + ASSERT_EQUALS(Scope::eClass, classScope.type); + ASSERT_EQUALS("Class", classScope.className); + ASSERT_EQUALS(1, classScope.functionList.size()); + const Function& method = classScope.functionList.front(); + ASSERT_EQUALS("Method", method.name()); + ASSERT_EQUALS(1, method.argCount()); + ASSERT_EQUALS(1, method.initializedArgCount()); + ASSERT_EQUALS(0, method.minArgCount()); + } + + void functionArgs16() { // #9591 + const char code[] = + "struct A { int var; };\n" + "void foo(int x, decltype(A::var) *&p) {}"; + GET_SYMBOL_DB(code); + ASSERT(db); + const Scope *scope = db->functionScopes.front(); + const Function *func = scope->function; + ASSERT_EQUALS(2, func->argCount()); + const Variable *arg2 = func->getArgumentVar(1); + ASSERT_EQUALS("p", arg2->name()); + ASSERT(arg2->isPointer()); + ASSERT(arg2->isReference()); + } + + void functionArgs17() { + const char code[] = "void f(int (*fp)(), int x, int y) {}"; + GET_SYMBOL_DB(code); + ASSERT(db != nullptr); + const Scope *scope = db->functionScopes.front(); + const Function *func = scope->function; + ASSERT_EQUALS(3, func->argCount()); + } + + void functionArgs18() { + const char code[] = "void f(int (*param1)[2], int param2) {}"; + GET_SYMBOL_DB(code); + ASSERT(db != nullptr); + const Scope *scope = db->functionScopes.front(); + const Function *func = scope->function; + ASSERT_EQUALS(2, func->argCount()); + } + + void functionImplicitlyVirtual() { + GET_SYMBOL_DB("class base { virtual void f(); };\n" + "class derived : base { void f(); };\n" + "void derived::f() {}"); + ASSERT(db != nullptr); + ASSERT_EQUALS(4, db->scopeList.size()); + const Function *function = db->scopeList.back().function; + ASSERT_EQUALS(true, function && function->isImplicitlyVirtual(false)); + } + + void functionIsInlineKeyword() { + GET_SYMBOL_DB("inline void fs() {}"); + (void)db; + const Function *func = db->scopeList.back().function; + ASSERT(func); + ASSERT(func->isInlineKeyword()); + } + + void functionStatic() { + GET_SYMBOL_DB("static void fs() { }"); + (void)db; + const Function *func = db->scopeList.back().function; + ASSERT(func); + ASSERT(func->isStatic()); + } + + void functionReturnsReference() { + GET_SYMBOL_DB("Fred::Reference foo();"); + ASSERT_EQUALS(1, db->scopeList.back().functionList.size()); + const Function &func = *db->scopeList.back().functionList.begin(); + ASSERT(!Function::returnsReference(&func, false)); + ASSERT(Function::returnsReference(&func, true)); + } + + void namespaces1() { + GET_SYMBOL_DB("namespace fred {\n" + " namespace barney {\n" + " class X { X(int); };\n" + " }\n" + "}\n" + "namespace barney { X::X(int) { } }"); + + // Locate the scope for the class.. + const Scope *scope = nullptr; + for (const Scope & it : db->scopeList) { + if (it.isClassOrStruct()) { + scope = ⁢ + break; + } + } + + ASSERT(scope != nullptr); + if (!scope) + return; + + ASSERT_EQUALS("X", scope->className); + + // The class has a constructor but the implementation _is not_ seen + ASSERT_EQUALS(1U, scope->functionList.size()); + const Function *function = &(scope->functionList.front()); + ASSERT_EQUALS(false, function->hasBody()); + } + + // based on namespaces1 but here the namespaces match + void namespaces2() { + GET_SYMBOL_DB("namespace fred {\n" + " namespace barney {\n" + " class X { X(int); };\n" + " }\n" + "}\n" + "namespace fred {\n" + " namespace barney {\n" + " X::X(int) { }\n" + " }\n" + "}"); + + // Locate the scope for the class.. + const Scope *scope = nullptr; + for (const Scope & it : db->scopeList) { + if (it.isClassOrStruct()) { + scope = ⁢ + break; + } + } + + ASSERT(scope != nullptr); + if (!scope) + return; + + ASSERT_EQUALS("X", scope->className); + + // The class has a constructor and the implementation _is_ seen + ASSERT_EQUALS(1U, scope->functionList.size()); + const Function *function = &(scope->functionList.front()); + ASSERT_EQUALS("X", function->tokenDef->str()); + ASSERT_EQUALS(true, function->hasBody()); + } + + void namespaces3() { // #3854 - namespace with unknown macro + GET_SYMBOL_DB("namespace fred UNKNOWN_MACRO(default) {\n" + "}"); + ASSERT_EQUALS(2U, db->scopeList.size()); + ASSERT_EQUALS(Scope::eGlobal, db->scopeList.front().type); + ASSERT_EQUALS(Scope::eNamespace, db->scopeList.back().type); + } + + void namespaces4() { // #4698 - type lookup + GET_SYMBOL_DB("struct A { int a; };\n" + "namespace fred { struct A {}; }\n" + "fred::A fredA;"); + const Variable *fredA = db->getVariableFromVarId(2U); + ASSERT_EQUALS("fredA", fredA->name()); + const Type *fredAType = fredA->type(); + ASSERT_EQUALS(2U, fredAType->classDef->linenr()); + } + + void tryCatch1() { + const char str[] = "void foo() {\n" + " try { }\n" + " catch (const Error1 & x) { }\n" + " catch (const X::Error2 & x) { }\n" + " catch (Error3 x) { }\n" + " catch (X::Error4 x) { }\n" + "}"; + GET_SYMBOL_DB(str); + ASSERT_EQUALS("", errout.str()); + ASSERT(db && db->variableList().size() == 5); // index 0 + 4 variables + ASSERT(db && db->scopeList.size() == 7); // global + function + try + 4 catch + } + + + void symboldatabase1() { + check("namespace foo {\n" + " class bar;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + check("class foo : public bar < int, int> {\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase2() { + check("class foo {\n" + "public slots :\n" + "foo() { }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + + check("class foo {\n" + "class bar;\n" + "foo() { }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase3() { + check("typedef void (func_type)();\n" + "struct A {\n" + " friend func_type f : 2;\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase4() { + check("static void function_declaration_before(void) __attribute__((__used__));\n" + "static void function_declaration_before(void) {}\n" + "static void function_declaration_after(void) {}\n" + "static void function_declaration_after(void) __attribute__((__used__));"); + ASSERT_EQUALS("", errout.str()); + + check("main(int argc, char *argv[]) { }", true, "test.c"); + ASSERT_EQUALS("[test.c:1]: (debug) SymbolDatabase::isFunction found C function 'main' without a return type.\n", errout.str()); + + check("namespace boost {\n" + " std::locale generate_locale()\n" + " {\n" + " return std::locale();\n" + " }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("namespace X {\n" + " static void function_declaration_before(void) __attribute__((__used__));\n" + " static void function_declaration_before(void) {}\n" + " static void function_declaration_after(void) {}\n" + " static void function_declaration_after(void) __attribute__((__used__));\n" + "}"); + ASSERT_EQUALS("", errout.str()); + + check("testing::testing()\n" + "{\n" + "}"); + ASSERT_EQUALS("[test.cpp:1]: (debug) Executable scope 'testing' with unknown function.\n", errout.str()); + } + + void symboldatabase5() { + // ticket #2178 - segmentation fault + ASSERT_THROW(check("int CL_INLINE_DECL(integer_decode_float) (int x) {\n" + " return (sign ? cl_I() : 0);\n" + "}"), InternalError); + } + + void symboldatabase6() { + // ticket #2221 - segmentation fault + check("template class X { };\n" + "X< 1>2 > x1;\n" + "X<(1>2)> x2;\n" + "template class Y { };\n" + "Y> x3;\n" + "Y>1>> x4;\n" + "Y>1)>> x5;\n", false); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase7() { + // ticket #2230 - segmentation fault + check("template class E,class D> class C : E\n" + "{\n" + "public:\n" + " int f();\n" + "};\n" + "class E : C\n" + "{\n" + "public:\n" + " int f() { return C< ::D,int>::f(); }\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase8() { + // ticket #2252 - segmentation fault + check("struct PaletteColorSpaceHolder: public rtl::StaticWithInit,\n" + " PaletteColorSpaceHolder>\n" + "{\n" + " uno::Reference operator()()\n" + " {\n" + " return vcl::unotools::createStandardColorSpace();\n" + " }\n" + "};"); + + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase9() { + // ticket #2425 - segmentation fault + check("class CHyperlink : public CString\n" + "{\n" + "public:\n" + " const CHyperlink& operator=(LPCTSTR lpsz) {\n" + " CString::operator=(lpsz);\n" + " return *this;\n" + " }\n" + "};\n", false); + + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase10() { + // ticket #2537 - segmentation fault + check("class A {\n" + "private:\n" + " void f();\n" + "};\n" + "class B {\n" + " friend void A::f();\n" + "};"); + + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase11() { + // ticket #2539 - segmentation fault + check("int g ();\n" + "struct S {\n" + " int i : (false ? g () : 1);\n" + "};"); + + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase12() { + // ticket #2547 - segmentation fault + check("class foo {\n" + " void bar2 () = __null;\n" + "};"); + + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase13() { + // ticket #2577 - segmentation fault + check("class foo {\n" + " void bar2 () = A::f;\n" + "};"); + + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase14() { + // ticket #2589 - segmentation fault + ASSERT_THROW(check("struct B : A\n"), InternalError); + } + + void symboldatabase17() { + // ticket #2657 - segmentation fault + check("{return f(){}}"); + + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase19() { + // ticket #2991 - segmentation fault + check("::y(){x}"); + + ASSERT_EQUALS_WITHOUT_LINENUMBERS("[test.cpp:1]: (debug) Executable scope 'y' with unknown function.\n" + "[test.cpp:1]: (debug) valueflow.cpp:1321:valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n", errout.str()); + } + + void symboldatabase20() { + // ticket #3013 - segmentation fault + ASSERT_THROW(check("struct x : virtual y\n"), InternalError); + } + + void symboldatabase21() { + check("class Fred {\n" + " class Foo { };\n" + " void func() const;\n" + "};\n" + "Fred::func() const {\n" + " Foo foo;\n" + "}"); + + ASSERT_EQUALS("", errout.str()); + } + + // ticket 3437 (segmentation fault) + void symboldatabase22() { + check("template struct A {};\n" + "A a;"); + ASSERT_EQUALS("", errout.str()); + } + + // ticket 3435 (std::vector) + void symboldatabase23() { + GET_SYMBOL_DB("class A { std::vector ints; };"); + ASSERT_EQUALS(2U, db->scopeList.size()); + const Scope &scope = db->scopeList.back(); + ASSERT_EQUALS(1U, scope.varlist.size()); + const Variable &var = scope.varlist.front(); + ASSERT_EQUALS(std::string("ints"), var.name()); + ASSERT_EQUALS(true, var.isClass()); + } + + // ticket 3508 (constructor, destructor) + void symboldatabase24() { + GET_SYMBOL_DB("struct Fred {\n" + " ~Fred();\n" + " Fred();\n" + "};\n" + "Fred::Fred() { }\n" + "Fred::~Fred() { }"); + // Global scope, Fred, Fred::Fred, Fred::~Fred + ASSERT_EQUALS(4U, db->scopeList.size()); + + // Find the scope for the Fred struct.. + const Scope *fredScope = nullptr; + for (const Scope & scope : db->scopeList) { + if (scope.isClassOrStruct() && scope.className == "Fred") + fredScope = &scope; + } + ASSERT(fredScope != nullptr); + + // The struct Fred has two functions, a constructor and a destructor + ASSERT_EQUALS(2U, fredScope->functionList.size()); + + // Get linenumbers where the bodies for the constructor and destructor are.. + unsigned int constructor = 0; + unsigned int destructor = 0; + for (const Function & it : fredScope->functionList) { + if (it.type == Function::eConstructor) + constructor = it.token->linenr(); // line number for constructor body + if (it.type == Function::eDestructor) + destructor = it.token->linenr(); // line number for destructor body + } + + // The body for the constructor is located at line 5.. + ASSERT_EQUALS(5U, constructor); + + // The body for the destructor is located at line 6.. + ASSERT_EQUALS(6U, destructor); + + } + + // ticket #3561 (throw C++) + void symboldatabase25() { + const char str[] = "int main() {\n" + " foo bar;\n" + " throw bar;\n" + "}"; + GET_SYMBOL_DB(str); + ASSERT_EQUALS("", errout.str()); + ASSERT(db && db->variableList().size() == 2); // index 0 + 1 variable + } + + // ticket #3561 (throw C) + void symboldatabase26() { + const char str[] = "int main() {\n" + " throw bar;\n" + "}"; + GET_SYMBOL_DB_C(str); + ASSERT_EQUALS("", errout.str()); + ASSERT(db && db->variableList().size() == 2); // index 0 + 1 variable + } + + // ticket #3543 (segmentation fault) + void symboldatabase27() { + check("class C : public B1\n" + "{\n" + " B1()\n" + " {} C(int) : B1() class\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase28() { + GET_SYMBOL_DB("struct S {};\n" + "void foo(struct S s) {}"); + ASSERT(db && db->getVariableFromVarId(1) && db->getVariableFromVarId(1)->typeScope() && db->getVariableFromVarId(1)->typeScope()->className == "S"); + } + + // ticket #4442 (segmentation fault) + void symboldatabase29() { + check("struct B : A {\n" + " B() : A {}\n" + "};"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase30() { + GET_SYMBOL_DB("struct A { void foo(const int a); };\n" + "void A::foo(int a) { }"); + ASSERT(db && db->functionScopes.size() == 1 && db->functionScopes[0]->functionOf); + } + + void symboldatabase31() { + GET_SYMBOL_DB("class Foo;\n" + "class Bar;\n" + "class Sub;\n" + "class Foo { class Sub; };\n" + "class Bar { class Sub; };\n" + "class Bar::Sub {\n" + " int b;\n" + "public:\n" + " Sub() { }\n" + " Sub(int);\n" + "};\n" + "Bar::Sub::Sub(int) { };\n" + "class ::Foo::Sub {\n" + " int f;\n" + "public:\n" + " ~Sub();\n" + " Sub();\n" + "};\n" + "::Foo::Sub::~Sub() { }\n" + "::Foo::Sub::Sub() { }\n" + "class Foo;\n" + "class Bar;\n" + "class Sub;"); + ASSERT(db && db->typeList.size() == 5); + + std::list::const_iterator i = db->typeList.begin(); + const Type* Foo = &(*i++); + const Type* Bar = &(*i++); + const Type* Sub = &(*i++); + const Type* Foo_Sub = &(*i++); + const Type* Bar_Sub = &(*i); + ASSERT(Foo && Foo->classDef && Foo->classScope && Foo->enclosingScope && Foo->name() == "Foo"); + ASSERT(Bar && Bar->classDef && Bar->classScope && Bar->enclosingScope && Bar->name() == "Bar"); + ASSERT(Sub && Sub->classDef && !Sub->classScope && Sub->enclosingScope && Sub->name() == "Sub"); + ASSERT(Foo_Sub && Foo_Sub->classDef && Foo_Sub->classScope && Foo_Sub->enclosingScope == Foo->classScope && Foo_Sub->name() == "Sub"); + ASSERT(Bar_Sub && Bar_Sub->classDef && Bar_Sub->classScope && Bar_Sub->enclosingScope == Bar->classScope && Bar_Sub->name() == "Sub"); + ASSERT(Foo_Sub && Foo_Sub->classScope && Foo_Sub->classScope->numConstructors == 1 && Foo_Sub->classScope->className == "Sub"); + ASSERT(Bar_Sub && Bar_Sub->classScope && Bar_Sub->classScope->numConstructors == 2 && Bar_Sub->classScope->className == "Sub"); + } + + void symboldatabase32() { + GET_SYMBOL_DB("struct Base {\n" + " void foo() {}\n" + "};\n" + "class Deri : Base {\n" + "};"); + ASSERT(db && db->findScopeByName("Deri") && db->findScopeByName("Deri")->definedType->getFunction("foo")); + } + + void symboldatabase33() { // ticket #4682 + GET_SYMBOL_DB("static struct A::B s;\n" + "static struct A::B t = { 0 };\n" + "static struct A::B u(0);\n" + "static struct A::B v{0};\n" + "static struct A::B w({0});\n" + "void foo() { }"); + ASSERT(db && db->functionScopes.size() == 1); + } + + void symboldatabase34() { // ticket #4694 + check("typedef _Atomic(int(A::*)) atomic_mem_ptr_to_int;\n" + "typedef _Atomic(int)&atomic_int_ref;\n" + "struct S {\n" + " _Atomic union { int n; };\n" + "};"); + ASSERT_EQUALS("[test.cpp:2]: (debug) Failed to parse 'typedef _Atomic ( int ) & atomic_int_ref ;'. The checking continues anyway.\n", errout.str()); + } + + void symboldatabase35() { // ticket #4806 and #4841 + check("class FragmentQueue : public CL_NS(util)::PriorityQueue >\n" + "{};"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase36() { // ticket #4892 + check("void struct ( ) { if ( 1 ) } int main ( ) { }"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase37() { + GET_SYMBOL_DB("class Fred {\n" + "public:\n" + " struct Wilma { };\n" + " struct Barney {\n" + " bool operator == (const struct Barney & b) const { return true; }\n" + " bool operator == (const struct Wilma & w) const { return true; }\n" + " };\n" + " Fred(const struct Barney & b) { barney = b; }\n" + "private:\n" + " struct Barney barney;\n" + "};"); + ASSERT(db && db->typeList.size() == 3); + + std::list::const_iterator i = db->typeList.begin(); + const Type* Fred = &(*i++); + const Type* Wilma = &(*i++); + const Type* Barney = &(*i++); + ASSERT(Fred && Fred->classDef && Fred->classScope && Fred->enclosingScope && Fred->name() == "Fred"); + ASSERT(Wilma && Wilma->classDef && Wilma->classScope && Wilma->enclosingScope && Wilma->name() == "Wilma"); + ASSERT(Barney && Barney->classDef && Barney->classScope && Barney->enclosingScope && Barney->name() == "Barney"); + ASSERT(db->variableList().size() == 5); + + ASSERT(db->getVariableFromVarId(1) && db->getVariableFromVarId(1)->type() && db->getVariableFromVarId(1)->type()->name() == "Barney"); + ASSERT(db->getVariableFromVarId(2) && db->getVariableFromVarId(2)->type() && db->getVariableFromVarId(2)->type()->name() == "Wilma"); + ASSERT(db->getVariableFromVarId(3) && db->getVariableFromVarId(3)->type() && db->getVariableFromVarId(3)->type()->name() == "Barney"); + } + + void symboldatabase38() { // ticket #5125 + check("template struct scoped_service;\n" + "struct service {};\n" + "template <> struct scoped_service {};\n" + "template \n" + "struct scoped_service : scoped_service\n" + "{\n" + " scoped_service( T* ptr ) : scoped_service(ptr), m_ptr(ptr) {}\n" + " T* const m_ptr;\n" + "};"); + } + + void symboldatabase40() { // ticket #5153 + check("void f() {\n" + " try { }\n" + " catch (std::bad_alloc) { }\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase41() { // ticket #5197 (unknown macro) + GET_SYMBOL_DB("struct X1 { MACRO1 f(int spd) MACRO2; };"); + ASSERT(db && db->findScopeByName("X1") && db->findScopeByName("X1")->functionList.size() == 1 && !db->findScopeByName("X1")->functionList.front().hasBody()); + } + + void symboldatabase42() { // only put variables in variable list + GET_SYMBOL_DB("void f() { extern int x(); }"); + ASSERT(db != nullptr); + const Scope * const fscope = db ? db->findScopeByName("f") : nullptr; + ASSERT(fscope != nullptr); + ASSERT_EQUALS(0U, fscope ? fscope->varlist.size() : ~0U); // "x" is not a variable + } + + void symboldatabase43() { // ticket #4738 + check("void f() {\n" + " new int;\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } + + void symboldatabase44() { + GET_SYMBOL_DB("int i { 1 };\n" + "int j ( i );\n" + "void foo() {\n" + " int k { 1 };\n" + " int l ( 1 );\n" + "}"); + ASSERT(db != nullptr); + ASSERT_EQUALS(4U, db->variableList().size() - 1); + ASSERT_EQUALS(2U, db->scopeList.size()); + for (std::size_t i = 1U; i < db->variableList().size(); i++) + ASSERT(db->getVariableFromVarId(i) != nullptr); + } + + void symboldatabase45() { + GET_SYMBOL_DB("typedef struct {\n" + " unsigned long bits;\n" + "} S;\n" + "struct T {\n" + " S span;\n" + " int flags;\n" + "};\n" + "struct T f(int x) {\n" + " return (struct T) {\n" + " .span = (S) { 0UL },\n" + " .flags = (x ? 256 : 0),\n" + " };\n" + "}"); + + ASSERT(db != nullptr); + ASSERT_EQUALS(4U, db->variableList().size() - 1); + for (std::size_t i = 1U; i < db->variableList().size(); i++) + ASSERT(db->getVariableFromVarId(i) != nullptr); + + ASSERT_EQUALS(4U, db->scopeList.size()); + std::list::const_iterator scope = db->scopeList.begin(); + ASSERT_EQUALS(Scope::eGlobal, scope->type); + ++scope; + ASSERT_EQUALS(Scope::eStruct, scope->type); + ++scope; + ASSERT_EQUALS(Scope::eStruct, scope->type); + ++scope; + ASSERT_EQUALS(Scope::eFunction, scope->type); + } + + void symboldatabase46() { // #6171 (anonymous namespace) + GET_SYMBOL_DB("struct S { };\n" + "namespace {\n" + " struct S { };\n" + "}"); + + ASSERT(db != nullptr); + ASSERT_EQUALS(4U, db->scopeList.size()); + std::list::const_iterator scope = db->scopeList.begin(); + ASSERT_EQUALS(Scope::eGlobal, scope->type); + ++scope; + ASSERT_EQUALS(Scope::eStruct, scope->type); + ASSERT_EQUALS(scope->className, "S"); + ++scope; + ASSERT_EQUALS(Scope::eNamespace, scope->type); + ASSERT_EQUALS(scope->className, ""); + ++scope; + ASSERT_EQUALS(Scope::eStruct, scope->type); + ASSERT_EQUALS(scope->className, "S"); + } + + void symboldatabase47() { // #6308 - associate Function and Scope for destructors + GET_SYMBOL_DB("namespace NS {\n" + " class MyClass {\n" + " ~MyClass();\n" + " };\n" + "}\n" + "using namespace NS;\n" + "MyClass::~MyClass() {\n" + " delete Example;\n" + "}"); + ASSERT(db && !db->functionScopes.empty() && db->functionScopes.front()->function && db->functionScopes.front()->function->functionScope == db->functionScopes.front()); + } + + void symboldatabase48() { // #6417 + GET_SYMBOL_DB("namespace NS {\n" + " class MyClass {\n" + " MyClass();\n" + " ~MyClass();\n" + " };\n" + "}\n" + "using namespace NS;\n" + "MyClass::~MyClass() { }\n" + "MyClass::MyClass() { }"); + ASSERT(db && !db->functionScopes.empty() && db->functionScopes.front()->function && db->functionScopes.front()->function->functionScope == db->functionScopes.front()); + + const Token *f = Token::findsimplematch(tokenizer.tokens(), "MyClass ( ) ;"); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3 && f->function()->token->linenr() == 9); + + f = Token::findsimplematch(tokenizer.tokens(), "~ MyClass ( ) ;"); + f = f->next(); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4 && f->function()->token->linenr() == 8); + } + + void symboldatabase49() { // #6424 + GET_SYMBOL_DB("namespace Ns { class C; }\n" + "void f1() { char *p; *p = 0; }\n" + "class Ns::C* p;\n" + "void f2() { char *p; *p = 0; }"); + ASSERT(db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "p ; void f2"); + ASSERT_EQUALS(true, db && f && f->variable()); + f = Token::findsimplematch(tokenizer.tokens(), "f2"); + ASSERT_EQUALS(true, db && f && f->function()); + } + + void symboldatabase50() { // #6432 + GET_SYMBOL_DB("template \n" + "class _ConstTessMemberResultCallback_0_0\n" + " {\n" + " public:\n" + " typedef void (T::*MemberSignature)() const;\n" + "\n" + " private:\n" + " const T* object_;\n" + " MemberSignature member_;\n" + "\n" + " public:\n" + " inline _ConstTessMemberResultCallback_0_0(\n" + " const T* object, MemberSignature member)\n" + " : object_(object),\n" + " member_(member) {\n" + " }\n" + "};"); + ASSERT(db != nullptr); + const Token *f = Token::findsimplematch(tokenizer.tokens(), "_ConstTessMemberResultCallback_0_0 ("); + ASSERT_EQUALS(true, db && f && f->function() && f->function()->isConstructor()); + } + + void symboldatabase51() { // #6538 + GET_SYMBOL_DB("static const float f1 = 2 * foo1(a, b);\n" + "static const float f2 = 2 * ::foo2(a, b);\n" + "static const float f3 = 2 * std::foo3(a, b);\n" + "static const float f4 = c * foo4(a, b);\n" + "static const int i1 = 2 & foo5(a, b);\n" + "static const bool b1 = 2 > foo6(a, b);"); + ASSERT(db != nullptr); + ASSERT(findFunctionByName("foo1", &db->scopeList.front()) == nullptr); + ASSERT(findFunctionByName("foo2", &db->scopeList.front()) == nullptr); + ASSERT(findFunctionByName("foo3", &db->scopeList.front()) == nullptr); + ASSERT(findFunctionByName("foo4", &db->scopeList.front()) == nullptr); + ASSERT(findFunctionByName("foo5", &db->scopeList.front()) == nullptr); + ASSERT(findFunctionByName("foo6", &db->scopeList.front()) == nullptr); + } + + void symboldatabase52() { // #6581 + GET_SYMBOL_DB("void foo() {\n" + " int i = 0;\n" + " S s{ { i }, 0 };\n" + "}"); + + ASSERT(db != nullptr); + ASSERT_EQUALS(2, db->scopeList.size()); + ASSERT_EQUALS(2, db->variableList().size()-1); + ASSERT(db->getVariableFromVarId(1) != nullptr); + ASSERT(db->getVariableFromVarId(2) != nullptr); + } + + void symboldatabase53() { // #7124 + GET_SYMBOL_DB("int32_t x;" + "std::int32_t y;"); + + ASSERT(db != nullptr); + ASSERT(db->getVariableFromVarId(1) != nullptr); + ASSERT(db->getVariableFromVarId(2) != nullptr); + ASSERT_EQUALS(false, db->getVariableFromVarId(1)->isClass()); + ASSERT_EQUALS(false, db->getVariableFromVarId(2)->isClass()); + } + + void symboldatabase54() { // #7343 + GET_SYMBOL_DB("class A {\n" + " void getReg() const override {\n" + " assert(Kind == k_ShiftExtend);\n" + " }\n" + "};"); + + ASSERT(db != nullptr); + ASSERT_EQUALS(1U, db->functionScopes.size()); + ASSERT_EQUALS("getReg", db->functionScopes.front()->className); + ASSERT_EQUALS(true, db->functionScopes.front()->function->hasOverrideSpecifier()); + } + + void symboldatabase55() { // #7767 + GET_SYMBOL_DB("PRIVATE S32 testfunc(void) {\n" + " return 0;\n" + "}"); + + ASSERT(db != nullptr); + ASSERT_EQUALS(1U, db->functionScopes.size()); + ASSERT_EQUALS("testfunc", db->functionScopes.front()->className); + } + + void symboldatabase56() { // #7909 + { + GET_SYMBOL_DB("class Class {\n" + " class NestedClass {\n" + " public:\n" + " virtual void f();\n" + " };\n" + " friend void NestedClass::f();\n" + "}"); + + ASSERT(db != nullptr); + ASSERT_EQUALS(0U, db->functionScopes.size()); + ASSERT(db->scopeList.back().type == Scope::eClass && db->scopeList.back().className == "NestedClass"); + ASSERT(db->scopeList.back().functionList.size() == 1U && !db->scopeList.back().functionList.front().hasBody()); + } + { + GET_SYMBOL_DB("class Class {\n" + " friend void f1();\n" + " friend void f2() { }\n" + "}"); + + ASSERT(db != nullptr); + ASSERT_EQUALS(1U, db->functionScopes.size()); + ASSERT(db->scopeList.back().type == Scope::eFunction && db->scopeList.back().className == "f2"); + ASSERT(db->scopeList.back().function && db->scopeList.back().function->hasBody()); + } + { + GET_SYMBOL_DB_C("friend f1();\n" + "friend f2() { }"); + + ASSERT(db != nullptr); + ASSERT_EQUALS(2U, db->scopeList.size()); + ASSERT_EQUALS(2U, db->scopeList.begin()->functionList.size()); + } + } + + void symboldatabase57() { + GET_SYMBOL_DB("int bar(bool b)\n" + "{\n" + " if(b)\n" + " return 1;\n" + " else\n" + " return 1;\n" + "}"); + ASSERT(db != nullptr); + ASSERT(db->scopeList.size() == 4U); + std::list::const_iterator it = db->scopeList.begin(); + ASSERT(it->type == Scope::eGlobal); + ASSERT((++it)->type == Scope::eFunction); + ASSERT((++it)->type == Scope::eIf); + ASSERT((++it)->type == Scope::eElse); + } + + void symboldatabase58() { // #6985 (using namespace type lookup) + GET_SYMBOL_DB("namespace N2\n" + "{\n" + "class B { };\n" + "}\n" + "using namespace N2;\n" + "class C {\n" + " class A : public B\n" + " {\n" + " };\n" + "};"); + ASSERT(db != nullptr); + ASSERT(db->typeList.size() == 3U); + std::list::const_iterator it = db->typeList.begin(); + const Type * classB = &(*it); + const Type * classC = &(*(++it)); + const Type * classA = &(*(++it)); + ASSERT(classA->name() == "A" && classB->name() == "B" && classC->name() == "C"); + ASSERT(classA->derivedFrom.size() == 1U); + ASSERT(classA->derivedFrom[0].type != nullptr); + ASSERT(classA->derivedFrom[0].type == classB); + } + + void symboldatabase59() { // #8465 + GET_SYMBOL_DB("struct A::B ab[10];\n" + "void f() {}"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 2); + } + + void symboldatabase60() { // #8470 + GET_SYMBOL_DB("struct A::someType A::bar() { return 0; }"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 2); + } + + void symboldatabase61() { + GET_SYMBOL_DB("struct Fred {\n" + " struct Info { };\n" + "};\n" + "void foo() {\n" + " struct Fred::Info* info;\n" + " info = new (nothrow) struct Fred::Info();\n" + " info = new struct Fred::Info();\n" + " memset(info, 0, sizeof(struct Fred::Info));\n" + "}"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 4); + } + + void symboldatabase62() { + { + GET_SYMBOL_DB("struct A {\n" + "public:\n" + " struct X { int a; };\n" + " void Foo(const std::vector &includes);\n" + "};\n" + "void A::Foo(const std::vector &includes) {\n" + " for (std::vector::const_iterator it = includes.begin(); it != includes.end(); ++it) {\n" + " const struct A::X currentIncList = *it;\n" + " }\n" + "}"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 5); + const Scope *scope = db->findScopeByName("A"); + ASSERT(scope != nullptr); + const Function *function = findFunctionByName("Foo", scope); + ASSERT(function != nullptr); + ASSERT(function->hasBody()); + } + { + GET_SYMBOL_DB("class A {\n" + "public:\n" + " class X { public: int a; };\n" + " void Foo(const std::vector &includes);\n" + "};\n" + "void A::Foo(const std::vector &includes) {\n" + " for (std::vector::const_iterator it = includes.begin(); it != includes.end(); ++it) {\n" + " const class A::X currentIncList = *it;\n" + " }\n" + "}"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 5); + const Scope *scope = db->findScopeByName("A"); + ASSERT(scope != nullptr); + const Function *function = findFunctionByName("Foo", scope); + ASSERT(function != nullptr); + ASSERT(function->hasBody()); + } + { + GET_SYMBOL_DB("struct A {\n" + "public:\n" + " union X { int a; float b; };\n" + " void Foo(const std::vector &includes);\n" + "};\n" + "void A::Foo(const std::vector &includes) {\n" + " for (std::vector::const_iterator it = includes.begin(); it != includes.end(); ++it) {\n" + " const union A::X currentIncList = *it;\n" + " }\n" + "}"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 5); + const Scope *scope = db->findScopeByName("A"); + ASSERT(scope != nullptr); + const Function *function = findFunctionByName("Foo", scope); + ASSERT(function != nullptr); + ASSERT(function->hasBody()); + } + { + GET_SYMBOL_DB("struct A {\n" + "public:\n" + " enum X { a, b };\n" + " void Foo(const std::vector &includes);\n" + "};\n" + "void A::Foo(const std::vector &includes) {\n" + " for (std::vector::const_iterator it = includes.begin(); it != includes.end(); ++it) {\n" + " const enum A::X currentIncList = *it;\n" + " }\n" + "}"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 5); + const Scope *scope = db->findScopeByName("A"); + ASSERT(scope != nullptr); + const Function *function = findFunctionByName("Foo", scope); + ASSERT(function != nullptr); + ASSERT(function->hasBody()); + } + } + + void symboldatabase63() { + { + GET_SYMBOL_DB("template class T ; void foo() { }"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 2); + } + { + GET_SYMBOL_DB("template struct T ; void foo() { }"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 2); + } + } + + void symboldatabase64() { + { + GET_SYMBOL_DB("class Fred { struct impl; };\n" + "struct Fred::impl {\n" + " impl() { }\n" + " ~impl() { }\n" + " impl(const impl &) { }\n" + " void foo(const impl &, const impl &) const { }\n" + "};"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 7); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 3 && + functionToken->function()->token->linenr() == 3); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 4 && + functionToken->next()->function()->token->linenr() == 4); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 5); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 6); + } + { + GET_SYMBOL_DB("class Fred { struct impl; };\n" + "struct Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + "};\n" + "Fred::impl::impl() { }\n" + "Fred::impl::~impl() { }\n" + "Fred::impl::impl(const Fred::impl &) { }\n" + "void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 7); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 3 && + functionToken->function()->token->linenr() == 8); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 4 && + functionToken->next()->function()->token->linenr() == 9); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 10); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred :: impl & , const Fred :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 11); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " class Fred { struct impl; };\n" + " struct Fred::impl {\n" + " impl() { }\n" + " ~impl() { }\n" + " impl(const impl &) { }\n" + " void foo(const impl &, const impl &) const { }\n" + " };\n" + "}"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 4 && + functionToken->function()->token->linenr() == 4); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 5 && + functionToken->next()->function()->token->linenr() == 5); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 6); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 7); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " class Fred { struct impl; };\n" + " struct Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + " };\n" + " Fred::impl::impl() { }\n" + " Fred::impl::~impl() { }\n" + " Fred::impl::impl(const Fred::impl &) { }\n" + " void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }\n" + "}"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 4 && + functionToken->function()->token->linenr() == 9); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 5 && + functionToken->next()->function()->token->linenr() == 10); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred :: impl & , const Fred :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 12); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " class Fred { struct impl; };\n" + " struct Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + " };\n" + "}\n" + "NS::Fred::impl::impl() { }\n" + "NS::Fred::impl::~impl() { }\n" + "NS::Fred::impl::impl(const NS::Fred::impl &) { }\n" + "void NS::Fred::impl::foo(const NS::Fred::impl &, const NS::Fred::impl &) const { }"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 4 && + functionToken->function()->token->linenr() == 10); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 5 && + functionToken->next()->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const NS :: Fred :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 12); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const NS :: Fred :: impl & , const NS :: Fred :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 13); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " class Fred { struct impl; };\n" + "}\n" + "struct NS::Fred::impl {\n" + " impl() { }\n" + " ~impl() { }\n" + " impl(const impl &) { }\n" + " void foo(const impl &, const impl &) const { }\n" + "};"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 5); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 6 && + functionToken->next()->function()->token->linenr() == 6); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 7); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 8 && + functionToken->function()->token->linenr() == 8); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " class Fred { struct impl; };\n" + "}\n" + "struct NS::Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + "};\n" + "NS::Fred::impl::impl() { }\n" + "NS::Fred::impl::~impl() { }\n" + "NS::Fred::impl::impl(const NS::Fred::impl &) { }\n" + "void NS::Fred::impl::foo(const NS::Fred::impl &, const NS::Fred::impl &) const { }"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 10); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 6 && + functionToken->next()->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const NS :: Fred :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 12); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const NS :: Fred :: impl & , const NS :: Fred :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 8 && + functionToken->function()->token->linenr() == 13); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " class Fred { struct impl; };\n" + "}\n" + "struct NS::Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + "};\n" + "namespace NS {\n" + " Fred::impl::impl() { }\n" + " Fred::impl::~impl() { }\n" + " Fred::impl::impl(const Fred::impl &) { }\n" + " void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }\n" + "}"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 6 && + functionToken->next()->function()->token->linenr() == 12); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 13); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred :: impl & , const Fred :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 8 && + functionToken->function()->token->linenr() == 14); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " class Fred { struct impl; };\n" + "}\n" + "struct NS::Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + "};\n" + "using namespace NS;\n" + "Fred::impl::impl() { }\n" + "Fred::impl::~impl() { }\n" + "Fred::impl::impl(const Fred::impl &) { }\n" + "void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 6 && + functionToken->next()->function()->token->linenr() == 12); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 13); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred :: impl & , const Fred :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 8 && + functionToken->function()->token->linenr() == 14); + } + { + GET_SYMBOL_DB("template class Fred { struct impl; };\n" + "template struct Fred::impl {\n" + " impl() { }\n" + " ~impl() { }\n" + " impl(const impl &) { }\n" + " void foo(const impl &, const impl &) const { }\n" + "};"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 7); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 3 && + functionToken->function()->token->linenr() == 3); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 4 && + functionToken->next()->function()->token->linenr() == 4); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 5); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 6); + } + { + GET_SYMBOL_DB("template class Fred { struct impl; };\n" + "template struct Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + "};\n" + "template Fred::impl::impl() { }\n" + "template Fred::impl::~impl() { }\n" + "template Fred::impl::impl(const Fred::impl &) { }\n" + "template void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 7); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 3 && + functionToken->function()->token->linenr() == 8); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 4 && + functionToken->next()->function()->token->linenr() == 9); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred < A > :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 10); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred < A > :: impl & , const Fred < A > :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 11); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " template class Fred { struct impl; };\n" + " template struct Fred::impl {\n" + " impl() { }\n" + " ~impl() { }\n" + " impl(const impl &) { }\n" + " void foo(const impl &, const impl &) const { }\n" + " };\n" + "}"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 4 && + functionToken->function()->token->linenr() == 4); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 5 && + functionToken->next()->function()->token->linenr() == 5); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 6); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 7); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " template class Fred { struct impl; };\n" + " template struct Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + " };\n" + " template Fred::impl::impl() { }\n" + " template Fred::impl::~impl() { }\n" + " template Fred::impl::impl(const Fred::impl &) { }\n" + " template void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }\n" + "}"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 4 && + functionToken->function()->token->linenr() == 9); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 5 && + functionToken->next()->function()->token->linenr() == 10); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred < A > :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred < A > :: impl & , const Fred < A > :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 12); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " template class Fred { struct impl; };\n" + " template struct Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + " };\n" + "}\n" + "template NS::Fred::impl::impl() { }\n" + "template NS::Fred::impl::~impl() { }\n" + "template NS::Fred::impl::impl(const NS::Fred::impl &) { }\n" + "template void NS::Fred::impl::foo(const NS::Fred::impl &, const NS::Fred::impl &) const { }"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 4 && + functionToken->function()->token->linenr() == 10); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 5 && + functionToken->next()->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const NS :: Fred < A > :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 6 && + functionToken->function()->token->linenr() == 12); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const NS :: Fred < A > :: impl & , const NS :: Fred < A > :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 13); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " template class Fred { struct impl; };\n" + "}\n" + "template struct NS::Fred::impl {\n" + " impl() { }\n" + " ~impl() { }\n" + " impl(const impl &) { }\n" + " void foo(const impl &, const impl &) const { }\n" + "};"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 5); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 6 && + functionToken->next()->function()->token->linenr() == 6); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 7); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 8 && + functionToken->function()->token->linenr() == 8); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " template class Fred { struct impl; };\n" + "}\n" + "template struct NS::Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + "};\n" + "template NS::Fred::impl::impl() { }\n" + "template NS::Fred::impl::~impl() { }\n" + "template NS::Fred::impl::impl(const NS::Fred::impl &) { }\n" + "template void NS::Fred::impl::foo(const NS::Fred::impl &, const NS::Fred::impl &) const { }"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 10); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 6 && + functionToken->next()->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const NS :: Fred < A > :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 12); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const NS :: Fred < A > :: impl & , const NS :: Fred < A > :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 8 && + functionToken->function()->token->linenr() == 13); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " template class Fred { struct impl; };\n" + "}\n" + "template struct NS::Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + "};\n" + "namespace NS {\n" + " template Fred::impl::impl() { }\n" + " template Fred::impl::~impl() { }\n" + " template Fred::impl::impl(const Fred::impl &) { }\n" + " template void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }\n" + "}"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 6 && + functionToken->next()->function()->token->linenr() == 12); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred < A > :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 13); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred < A > :: impl & , const Fred < A > :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 8 && + functionToken->function()->token->linenr() == 14); + } + { + GET_SYMBOL_DB("namespace NS {\n" + " template class Fred { struct impl; };\n" + "}\n" + "template struct NS::Fred::impl {\n" + " impl();\n" + " ~impl();\n" + " impl(const impl &);\n" + " void foo(const impl &, const impl &) const;\n" + "};\n" + "using namespace NS;\n" + "template Fred::impl::impl() { }\n" + "template Fred::impl::~impl() { }\n" + "template Fred::impl::impl(const Fred::impl &) { }\n" + "template void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }"); + + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 8); + ASSERT(db && db->classAndStructScopes.size() == 2); + ASSERT(db && db->typeList.size() == 2); + ASSERT(db && db->functionScopes.size() == 4); + + const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 5 && + functionToken->function()->token->linenr() == 11); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }"); + ASSERT(db && functionToken && functionToken->next()->function() && + functionToken->next()->function()->functionScope && + functionToken->next()->function()->tokenDef->linenr() == 6 && + functionToken->next()->function()->token->linenr() == 12); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred < A > :: impl & ) { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 7 && + functionToken->function()->token->linenr() == 13); + + functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred < A > :: impl & , const Fred < A > :: impl & ) const { }"); + ASSERT(db && functionToken && functionToken->function() && + functionToken->function()->functionScope && + functionToken->function()->tokenDef->linenr() == 8 && + functionToken->function()->token->linenr() == 14); + } + } + + void symboldatabase65() { + // don't crash on missing links from instantiation of template with typedef + check("int ( * X0 ) ( long ) < int ( ) ( long ) > :: f0 ( int * ) { return 0 ; }"); + ASSERT_EQUALS("[test.cpp:1]: (debug) SymbolDatabase::findFunction found '>' without link.\n", errout.str()); + } + + void symboldatabase66() { // #8540 + GET_SYMBOL_DB("enum class ENUM1;\n" + "enum class ENUM2 { MEMBER2 };\n" + "enum class ENUM3 : int { MEMBER1, };"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 3); + ASSERT(db && db->typeList.size() == 3); + } + + void symboldatabase67() { // #8538 + GET_SYMBOL_DB("std::string get_endpoint_url() const noexcept override;"); + const Function *f = db ? &db->scopeList.front().functionList.front() : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->hasOverrideSpecifier()); + ASSERT(f && f->isConst()); + ASSERT(f && f->isNoExcept()); + } + + void symboldatabase68() { // #8560 + GET_SYMBOL_DB("struct Bar {\n" + " virtual std::string get_endpoint_url() const noexcept;\n" + "};\n" + "struct Foo : Bar {\n" + " virtual std::string get_endpoint_url() const noexcept override final;\n" + "};"); + const Token *f = db ? Token::findsimplematch(tokenizer.tokens(), "get_endpoint_url ( ) const noexcept ;") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 2); + ASSERT(f && f->function() && f->function()->hasVirtualSpecifier()); + ASSERT(f && f->function() && !f->function()->hasOverrideSpecifier()); + ASSERT(f && f->function() && !f->function()->hasFinalSpecifier()); + ASSERT(f && f->function() && f->function()->isConst()); + ASSERT(f && f->function() && f->function()->isNoExcept()); + f = db ? Token::findsimplematch(tokenizer.tokens(), "get_endpoint_url ( ) const noexcept override final ;") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 5); + ASSERT(f && f->function() && f->function()->hasVirtualSpecifier()); + ASSERT(f && f->function() && f->function()->hasOverrideSpecifier()); + ASSERT(f && f->function() && f->function()->hasFinalSpecifier()); + ASSERT(f && f->function() && f->function()->isConst()); + ASSERT(f && f->function() && f->function()->isNoExcept()); + } + + void symboldatabase69() { + GET_SYMBOL_DB("struct Fred {\n" + " int x, y;\n" + " void foo() const volatile { }\n" + " void foo() volatile { }\n" + " void foo() const { }\n" + " void foo() { }\n" + "};"); + const Token *f = db ? Token::findsimplematch(tokenizer.tokens(), "foo ( ) const volatile {") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 3); + ASSERT(f && f->function() && f->function()->isConst()); + ASSERT(f && f->function() && f->function()->isVolatile()); + f = db ? Token::findsimplematch(tokenizer.tokens(), "foo ( ) volatile {") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 4); + ASSERT(f && f->function() && !f->function()->isConst()); + ASSERT(f && f->function() && f->function()->isVolatile()); + f = db ? Token::findsimplematch(tokenizer.tokens(), "foo ( ) const {") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 5); + ASSERT(f && f->function() && f->function()->isConst()); + ASSERT(f && f->function() && !f->function()->isVolatile()); + f = db ? Token::findsimplematch(tokenizer.tokens(), "foo ( ) {") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 6); + ASSERT(f && f->function() && !f->function()->isVolatile()); + ASSERT(f && f->function() && !f->function()->isConst()); + } + + void symboldatabase70() { + { + GET_SYMBOL_DB("class Map::Entry* e;"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 1); + ASSERT(db && db->variableList().size() == 2); + } + { + GET_SYMBOL_DB("template class boost::token_iterator_generator::type; void foo() { }"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 2); + } + { + GET_SYMBOL_DB("void foo() {\n" + " return class Arm_relocate_functions::thumb32_branch_offset(upper_insn, lower_insn);\n" + "}"); + ASSERT(db != nullptr); + ASSERT(db && db->scopeList.size() == 2); + } + } + + void symboldatabase71() { + GET_SYMBOL_DB("class A { };\n" + "class B final : public A { };"); + ASSERT(db && db->scopeList.size() == 3); + ASSERT(db && db->typeList.size() == 2); + } + + void symboldatabase72() { // #8600 + GET_SYMBOL_DB("struct A { struct B; };\n" + "struct A::B {\n" + " B() = default;\n" + " B(const B&) {}\n" + "};"); + + ASSERT(db && db->scopeList.size() == 4); + ASSERT(db && db->typeList.size() == 2); + const Token * f = db ? Token::findsimplematch(tokenizer.tokens(), "B ( const B & ) { }") : nullptr; + ASSERT(f != nullptr); + ASSERT(f && f->function() && f->function()->token->linenr() == 4); + ASSERT(f && f->function() && f->function()->type == Function::eCopyConstructor); + } + + void symboldatabase74() { // #8838 - final + GET_SYMBOL_DB("class Base { virtual int f() const = 0; };\n" + "class Derived : Base { virtual int f() const final { return 6; } };"); + + ASSERT_EQUALS(4, db->scopeList.size()); + ASSERT_EQUALS(1, db->functionScopes.size()); + + const Scope *f1 = db->functionScopes[0]; + ASSERT(f1->function->hasFinalSpecifier()); + } + + void symboldatabase75() { + GET_SYMBOL_DB("template \n" + "class optional {\n" + " auto value() & -> T &;\n" + " auto value() && -> T &&;\n" + " auto value() const& -> T const &;\n" + "};\n" + "template \n" + "auto optional::value() & -> T & {}\n" + "template \n" + "auto optional::value() && -> T && {}\n" + "template \n" + "auto optional::value() const & -> T const & {}\n" + "optional i;"); + + ASSERT_EQUALS(5, db->scopeList.size()); + ASSERT_EQUALS(3, db->functionScopes.size()); + + const Scope *f = db->functionScopes[0]; + ASSERT(f->function->hasBody()); + ASSERT(!f->function->isConst()); + ASSERT(f->function->hasTrailingReturnType()); + ASSERT(f->function->hasLvalRefQualifier()); + + f = db->functionScopes[1]; + ASSERT(f->function->hasBody()); + ASSERT(!f->function->isConst()); + ASSERT(f->function->hasTrailingReturnType()); + ASSERT(f->function->hasRvalRefQualifier()); + + f = db->functionScopes[2]; + ASSERT(f->function->hasBody()); + ASSERT(f->function->isConst()); + ASSERT(f->function->hasTrailingReturnType()); + ASSERT(f->function->hasLvalRefQualifier()); + } + + void symboldatabase76() { // #9056 + GET_SYMBOL_DB("namespace foo {\n" + " using namespace bar::baz;\n" + " auto func(int arg) -> bar::quux {}\n" + "}"); + ASSERT_EQUALS(2, db->mVariableList.size()); + } + + void symboldatabase77() { // #8663 + GET_SYMBOL_DB("template \n" + "void f() {\n" + " using T3 = typename T1::template T3;\n" + " T3 t;\n" + "}"); + ASSERT_EQUALS(2, db->mVariableList.size()); + } + + void symboldatabase78() { // #9147 + GET_SYMBOL_DB("template struct a;\n" + "namespace {\n" + "template struct b;\n" + "template