/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2019 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 "platform.h" #include "settings.h" #include "symboldatabase.h" #include "testsuite.h" #include "testutils.h" #include "token.h" #include "tokenize.h" #include "tokenlist.h" #include "utils.h" #include #include #include #include #include #include #include #include #include struct InternalError; #define GET_SYMBOL_DB(code) \ Tokenizer tokenizer(&settings1, this); \ const SymbolDatabase *db = getSymbolDB_inner(tokenizer, code, "test.cpp"); \ ASSERT(db); #define GET_SYMBOL_DB_C(code) \ Tokenizer tokenizer(&settings1, this); \ const SymbolDatabase *db = getSymbolDB_inner(tokenizer, code, "test.c"); class TestSymbolDatabase: public TestFixture { public: TestSymbolDatabase() :TestFixture("TestSymbolDatabase") ,nullScope(nullptr, nullptr, nullptr) ,vartok(nullptr) ,typetok(nullptr) { } private: const Scope nullScope; 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); tokenizer.tokenize(istr, filename); return tokenizer.getSymbolDatabase(); } 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); TEST_CASE(array); TEST_CASE(stlarray); 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_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(VariableValueType1); TEST_CASE(VariableValueType2); TEST_CASE(VariableValueType3); 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(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(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(functionImplicitlyVirtual); TEST_CASE(functionStatic); 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(createSymbolDatabaseFindAllScopes1); TEST_CASE(enum1); TEST_CASE(enum2); TEST_CASE(enum3); TEST_CASE(enum4); TEST_CASE(enum5); TEST_CASE(enum6); TEST_CASE(enum7); 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(findFunctionContainer); TEST_CASE(findFunctionExternC); TEST_CASE(findFunctionGlobalScope); // ::foo 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(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(unionWithConstructor); TEST_CASE(incomplete_type); // #9255 (infinite recursion) } void array() { GET_SYMBOL_DB_C("int a[10+2];"); ASSERT(db != nullptr); if (!db) return; ASSERT(db->variableList().size() == 2); // the first one is not used const Variable * v = db->getVariableFromVarId(1); ASSERT(v != nullptr); if (!v) return; ASSERT(v->isArray()); ASSERT_EQUALS(1U, v->dimensions().size()); ASSERT_EQUALS(12U, v->dimension(0)); } void stlarray() { GET_SYMBOL_DB("std::array arr;"); ASSERT(db != nullptr); if (!db) return; ASSERT(db->variableList().size() == 2); // the first one is not used const Variable * v = db->getVariableFromVarId(1); ASSERT(v != nullptr); if (!v) return; ASSERT(v->isArray()); ASSERT_EQUALS(1U, v->dimensions().size()); ASSERT_EQUALS(20U, v->dimension(0)); } void test_isVariableDeclarationCanHandleNull() { reset(); const bool result = nullScope.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(); givenACodeSampleToTokenize simpleDeclaration("int x;"); const bool result = nullScope.isVariableDeclaration(simpleDeclaration.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(); givenACodeSampleToTokenize simpleDeclaration("int x (1);"); const bool result = nullScope.isVariableDeclaration(simpleDeclaration.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(); givenACodeSampleToTokenize simpleDeclaration("int x {1};"); const bool result = nullScope.isVariableDeclaration(simpleDeclaration.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(); givenACodeSampleToTokenize ScopedDeclaration("::int x;"); const bool result = nullScope.isVariableDeclaration(ScopedDeclaration.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(); givenACodeSampleToTokenize StdDeclaration("std::string x;"); const bool result = nullScope.isVariableDeclaration(StdDeclaration.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(); givenACodeSampleToTokenize StdDeclaration("::std::string x;"); const bool result = nullScope.isVariableDeclaration(StdDeclaration.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(); givenACodeSampleToTokenize manyScopes("AA::BB::CC::DD::EE x;"); const bool result = nullScope.isVariableDeclaration(manyScopes.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(); givenACodeSampleToTokenize pointer("int* p;"); const bool result1 = nullScope.isVariableDeclaration(pointer.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(); givenACodeSampleToTokenize pointerconst("int* const p;"); const bool result2 = nullScope.isVariableDeclaration(pointerconst.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_isVariableDeclarationDoesNotIdentifyConstness() { reset(); givenACodeSampleToTokenize constness("const int* cp;"); const bool result = nullScope.isVariableDeclaration(constness.tokens(), vartok, typetok); ASSERT_EQUALS(false, result); ASSERT(nullptr == vartok); ASSERT(nullptr == typetok); } void test_isVariableDeclarationIdentifiesFirstOfManyVariables() { reset(); givenACodeSampleToTokenize multipleDeclaration("int first, second;"); const bool result = nullScope.isVariableDeclaration(multipleDeclaration.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(); givenACodeSampleToTokenize manyScopes("AA::BB::CC::DD::EE* p;"); const bool result = nullScope.isVariableDeclaration(manyScopes.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(); givenACodeSampleToTokenize pointerToPointer("int** pp;"); const bool result = nullScope.isVariableDeclaration(pointerToPointer.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(); givenACodeSampleToTokenize pointerToPointer("int***** p;"); const bool result = nullScope.isVariableDeclaration(pointerToPointer.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(); givenACodeSampleToTokenize arr("::std::string v[3];"); const bool result = nullScope.isVariableDeclaration(arr.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(); givenACodeSampleToTokenize arr("A *a[5];"); const bool result = nullScope.isVariableDeclaration(arr.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(); givenACodeSampleToTokenize arr("A (*a)[5];"); const bool result = nullScope.isVariableDeclaration(arr.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(); givenACodeSampleToTokenize var("std::set* chars;"); const bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var("std::deque*** ints;"); const bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var("std::deque ints[3];"); const bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var("std::vector ints;"); const bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var("std::list::const_iterator floats;"); const bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var("std::deque > intsets;"); const bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var1("int& foo;"); const bool result1 = nullScope.isVariableDeclaration(var1.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(); givenACodeSampleToTokenize var2("foo*& bar;"); const bool result2 = nullScope.isVariableDeclaration(var2.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(); givenACodeSampleToTokenize var3("std::vector& foo;"); const bool result3 = nullScope.isVariableDeclaration(var3.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(); givenACodeSampleToTokenize var("template class SomeClass{};"); const bool result = nullScope.isVariableDeclaration(var.tokens(), vartok, typetok); ASSERT_EQUALS(false, result); } void isVariableDeclarationDoesNotIdentifyCppCast() { reset(); givenACodeSampleToTokenize var("reinterpret_cast (code)[0] = 0;"); const bool result = nullScope.isVariableDeclaration(var.tokens(), vartok, typetok); ASSERT_EQUALS(false, result); } void isVariableDeclarationPointerConst() { reset(); givenACodeSampleToTokenize var("std::string const* s;"); const bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var("int&& i;"); const bool result = nullScope.isVariableDeclaration(var.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(var.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;\n"); 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;\n"); 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);\n"); 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);\n"); 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);\n"); 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);\n"); 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 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); if (!db) return; 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); if (!db) return; 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); if (!db) return; ASSERT(db->scopeList.back().type == Scope::eFor); ASSERT_EQUALS(2, db->variableList().size()); if (db->variableList().size() < 2) return; const Variable* e = db->getVariableFromVarId(1); ASSERT(e && e->isReference() && e->isLocal()); } void isVariableStlType() { { reset(); std::istringstream code("std::string s;"); TokenList list(nullptr); list.createTokens(code, "test.cpp"); const bool result = nullScope.isVariableDeclaration(list.front(), vartok, typetok); ASSERT_EQUALS(true, result); Variable v(vartok, list.front(), 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(); std::istringstream code("std::vector v;"); TokenList list(nullptr); list.createTokens(code, "test.cpp"); list.front()->tokAt(3)->link(list.front()->tokAt(5)); const bool result = nullScope.isVariableDeclaration(list.front(), vartok, typetok); ASSERT_EQUALS(true, result); Variable v(vartok, list.front(), 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(); std::istringstream code("SomeClass s;"); TokenList list(nullptr); list.createTokens(code, "test.cpp"); const bool result = nullScope.isVariableDeclaration(list.front(), vartok, typetok); ASSERT_EQUALS(true, result); Variable v(vartok, list.front(), 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(); givenACodeSampleToTokenize var("char* const * s;"); bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var("char* volatile * s;"); bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var("char* const volatile * s;"); bool result = nullScope.isVariableDeclaration(var.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(); givenACodeSampleToTokenize var("const char* const volatile * const volatile * const volatile * const volatile s;"); bool result = nullScope.isVariableDeclaration(var.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 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;\n"); 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() { }\n") // 2 scopes: Global and Function ASSERT(db && db->scopeList.size() == 2); if (db) { const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->next()); ASSERT(scope && scope->className == "func"); if (!scope) return; 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); if (db) { const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->next()); ASSERT(scope && scope->className == "func"); if (!scope) return; 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() { } };\n") // 3 scopes: Global, Class, and Function ASSERT(db && db->scopeList.size() == 3); if (db) { const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func"); const Scope *scope = findFunctionScopeByToken(db, functionToken); ASSERT(scope && scope->className == "func"); if (!scope) return; 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); if (db) { const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func"); const Scope *scope = findFunctionScopeByToken(db, functionToken); ASSERT(scope && scope->className == "func"); if (!scope) return; 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(); };\n") // 2 scopes: Global and Class (no Function scope because there is no function implementation) ASSERT(db && db->scopeList.size() == 2); if (db) { 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); if (db) { const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "operator="); const Scope *scope = findFunctionScopeByToken(db, functionToken); ASSERT(scope && scope->className == "operator="); if (!scope) return; 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() { }\n") // 3 scopes: Global, Class, and Function ASSERT(db && db->scopeList.size() == 3); if (db) { const Token * const functionToken = Token::findsimplematch(tokenizer.tokens()->linkAt(2), "func"); const Scope *scope = findFunctionScopeByToken(db, functionToken); ASSERT(scope && scope->className == "func"); if (!scope) return; 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 { }\n"); // 3 scopes: Global, Class, and Function ASSERT(db && db->scopeList.size() == 3); if (db) { const Token * const functionToken = Token::findsimplematch(tokenizer.tokens()->linkAt(2), "func"); const Scope *scope = findFunctionScopeByToken(db, functionToken); ASSERT(scope && scope->className == "func"); if (!scope) return; 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 hasRegularFunctionReturningFunctionPointer() { GET_SYMBOL_DB("void (*func(int f))(char) { }\n") // 2 scopes: Global and Function ASSERT(db && db->scopeList.size() == 2); if (db) { 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) { } };\n") // 3 scopes: Global, Class, and Function ASSERT(db && db->scopeList.size() == 3); if (db) { 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); };\n") // 2 scopes: Global and Class (no Function scope because there is no function implementation) ASSERT(db && db->scopeList.size() == 2); if (db) { 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) { }\n") // 3 scopes: Global, Class, and Function ASSERT(db && db->scopeList.size() == 3); if (db) { 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() {} };\n") // 3 scopes: Global, Class, and Function ASSERT(db && db->scopeList.size() == 3); if (db) { 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); if (db) { 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); if (db) { ASSERT_EQUALS(1, db->variableList().size() - 1); ASSERT_EQUALS(true, db->getVariableFromVarId(1) != nullptr); if (db->getVariableFromVarId(1)) 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); if (db) { 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())); if (db) { 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())); if (db) { 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 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); if (db && !db->scopeList.empty()) { // 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()); if (db) { 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()); if (db) { 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()); if (db) { 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()); if (db) { 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); if (db) { 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); if (foo && bar1 && bar2) { 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; }\n") 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;\n") ASSERT(db && db->scopeList.size() == 1); if (db && db->scopeList.size() == 1) { std::list::const_iterator it = db->scopeList.begin(); ASSERT(it->varlist.size() == 1); if (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];\n") ASSERT(db && db->scopeList.size() == 1); if (db && db->scopeList.size() == 1) { std::list::const_iterator it = db->scopeList.begin(); ASSERT(it->varlist.size() == 1); if (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 } };\n") ASSERT(db && db->scopeList.size() == 1); if (db && db->scopeList.size() == 1) { std::list::const_iterator it = db->scopeList.begin(); ASSERT(it->varlist.size() == 1); if (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)); if (db && 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); if (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()); } } void check(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); tokenizer.tokenize(istr, filename); // 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); if (f && 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); if (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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( enum"); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); if (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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( ABC"); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); if (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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); if (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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); if (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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); if (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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab"); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type()); if (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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( b"); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->tokenDef->linenr() == 4 && func->argumentList.size() == 1 && func->argumentList.front().type()); if (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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ("); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); if (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); if (db) { ASSERT_EQUALS(3, db->scopeList.size()); if (db->scopeList.size() == 3) { 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); if (scope->functionList.begin()->functionScope) { 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); if (db) { ASSERT_EQUALS(3, db->scopeList.size()); if (db->scopeList.size() == 3) { 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); if (scope->functionList.begin()->functionScope) { 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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ("); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); if (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); if (db) { const Token *f = Token::findsimplematch(tokenizer.tokens(), "B ( A :: E"); ASSERT_EQUALS(true, f && f->function()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); if (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()); if (f && f->function()) { const Function *func = f->function(); ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type()); if (func->argumentList.size() == 1 && func->argumentList.front().type()) { const Type * type = func->argumentList.front().type(); ASSERT_EQUALS(true, type->isStructType() && type->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 functionImplicitlyVirtual() { GET_SYMBOL_DB("class base { virtual void f(); };\n" "class derived : base { void f(); };\n" "void derived::f() {}"); ASSERT(db != nullptr); if (!db) return; ASSERT_EQUALS(4, db->scopeList.size()); const Function *function = db->scopeList.back().function; ASSERT_EQUALS(true, function && function->isImplicitlyVirtual(false)); } void functionStatic() { GET_SYMBOL_DB("static void fs() { }"); (void)db; const Function *func = db->scopeList.back().function; ASSERT(func); ASSERT(func->isStatic()); } 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__));\n"); 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 check("int CL_INLINE_DECL(integer_decode_float) (int x) {\n" " return (sign ? cl_I() : 0);\n" "}"); ASSERT_EQUALS("", errout.str()); } 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:valueFlowTerminatingCondition 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;\n"); 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); if (fredScope == nullptr) return; // 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;\n"); ASSERT(db && db->typeList.size() == 5); if (!db || db->typeList.size() < 5) return; 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("", 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" "};\n"); ASSERT(db && db->typeList.size() == 3); if (!db || db->typeList.size() != 3) return; 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); if (db->variableList().size() != 5) return; 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" "}\n"); ASSERT_EQUALS("", errout.str()); } void symboldatabase41() { // ticket #5197 (unknown macro) GET_SYMBOL_DB("struct X1 { MACRO1 f(int spd) MACRO2; };\n"); 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(); }\n"); 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" "}\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() { }\n"); 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; }\n"); 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);\n"); ASSERT(db != nullptr); if (db) { 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); if (db) { 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); if (db) { 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); if (db) { 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); if (db) { 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); if (db) { 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); if (db) { 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() { }\n"); ASSERT(db != nullptr); if (db) { 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); if (db) { ASSERT(db->scopeList.size() == 4U); if (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); if (db) { ASSERT(db->typeList.size() == 3U); if (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"); if (classA->name() == "A" && classB->name() == "B" && classC->name() == "C") { ASSERT(classA->derivedFrom.size() == 1U); if (classA->derivedFrom.size() == 1) { ASSERT(classA->derivedFrom[0].type != nullptr); if (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); if (db && db->scopeList.size() == 5) { const Scope *scope = db->findScopeByName("A"); ASSERT(scope != nullptr); if (scope) { const Function *function = findFunctionByName("Foo", scope); ASSERT(function != nullptr); if (function) { 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); if (db && db->scopeList.size() == 5) { const Scope *scope = db->findScopeByName("A"); ASSERT(scope != nullptr); if (scope) { const Function *function = findFunctionByName("Foo", scope); ASSERT(function != nullptr); if (function) { 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); if (db && db->scopeList.size() == 5) { const Scope *scope = db->findScopeByName("A"); ASSERT(scope != nullptr); if (scope) { const Function *function = findFunctionByName("Foo", scope); ASSERT(function != nullptr); if (function) { 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); if (db && db->scopeList.size() == 5) { const Scope *scope = db->findScopeByName("A"); ASSERT(scope != nullptr); if (scope) { const Function *function = findFunctionByName("Foo", scope); ASSERT(function != nullptr); if (function) { 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" "};\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 { }\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() == 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 { }\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() == 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 { }\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() == 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 { }\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); } } 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