/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2024 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 "errortypes.h"
#include "fixture.h"
#include "helpers.h"
#include "platform.h"
#include "settings.h"
#include "sourcelocation.h"
#include "symboldatabase.h"
#include "token.h"
#include "tokenize.h"
#include "tokenlist.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
class TestSymbolDatabase;
#define GET_SYMBOL_DB(code) \
SimpleTokenizer tokenizer(settings1, *this); \
const SymbolDatabase *db = getSymbolDB_inner(tokenizer, code, true); \
ASSERT(db); \
do {} while (false)
#define GET_SYMBOL_DB_C(code) \
SimpleTokenizer tokenizer(settings1, *this); \
const SymbolDatabase *db = getSymbolDB_inner(tokenizer, code, false); \
do {} while (false)
#define GET_SYMBOL_DB_DBG(code) \
SimpleTokenizer tokenizer(settingsDbg, *this); \
const SymbolDatabase *db = getSymbolDB_inner(tokenizer, code, true); \
ASSERT(db); \
do {} while (false)
class TestSymbolDatabase : public TestFixture {
public:
TestSymbolDatabase() : TestFixture("TestSymbolDatabase") {}
private:
const Token* vartok{nullptr};
const Token* typetok{nullptr};
const Settings settings1 = settingsBuilder().library("std.cfg").build();
const Settings settings2 = settingsBuilder().platform(Platform::Type::Unspecified).build();
const Settings settingsDbg = settingsBuilder().library("std.cfg").debugwarnings(true).build();
void reset() {
vartok = nullptr;
typetok = nullptr;
}
static const SymbolDatabase* getSymbolDB_inner(SimpleTokenizer& tokenizer, const char* code, bool cpp) {
return tokenizer.tokenize(code, cpp) ? tokenizer.getSymbolDatabase() : nullptr;
}
static const Token* findToken(Tokenizer& tokenizer, const std::string& expr, unsigned int exprline)
{
for (const Token* tok = tokenizer.tokens(); tok; tok = tok->next()) {
if (Token::simpleMatch(tok, expr.c_str(), expr.size()) && tok->linenr() == exprline) {
return tok;
}
}
return nullptr;
}
static std::string asExprIdString(const Token* tok)
{
return tok->expressionString() + "@" + std::to_string(tok->exprId());
}
std::string testExprIdEqual(const char code[],
const std::string& expr1,
unsigned int exprline1,
const std::string& expr2,
unsigned int exprline2,
SourceLocation loc = SourceLocation::current())
{
SimpleTokenizer tokenizer(settings1, *this);
ASSERT_LOC(tokenizer.tokenize(code), loc.file_name(), loc.line());
const Token* tok1 = findToken(tokenizer, expr1, exprline1);
const Token* tok2 = findToken(tokenizer, expr2, exprline2);
if (!tok1)
return "'" + expr1 + "'" + " not found";
if (!tok2)
return "'" + expr2 + "'" + " not found";
if (tok1->exprId() == 0)
return asExprIdString(tok1) + " has not exprId";
if (tok2->exprId() == 0)
return asExprIdString(tok2) + " has not exprId";
if (tok1->exprId() != tok2->exprId())
return asExprIdString(tok1) + " != " + asExprIdString(tok2);
return "";
}
bool testExprIdNotEqual(const char code[],
const std::string& expr1,
unsigned int exprline1,
const std::string& expr2,
unsigned int exprline2,
SourceLocation loc = SourceLocation::current())
{
std::string result = testExprIdEqual(code, expr1, exprline1, expr2, exprline2, loc);
return !result.empty();
}
static const Scope *findFunctionScopeByToken(const SymbolDatabase * db, const Token *tok) {
std::list::const_iterator scope;
for (scope = db->scopeList.cbegin(); scope != db->scopeList.cend(); ++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) {
auto it = std::find_if(currScope->functionList.cbegin(), currScope->functionList.cend(), [&](const Function& f) {
return f.tokenDef->str() == str;
});
if (it != currScope->functionList.end())
return &*it;
currScope = currScope->nestedIn;
}
return nullptr;
}
void run() override {
TEST_CASE(array);
TEST_CASE(array_ptr);
TEST_CASE(stlarray1);
TEST_CASE(stlarray2);
TEST_CASE(stlarray3);
TEST_CASE(test_isVariableDeclarationCanHandleNull);
TEST_CASE(test_isVariableDeclarationIdentifiesSimpleDeclaration);
TEST_CASE(test_isVariableDeclarationIdentifiesInitialization);
TEST_CASE(test_isVariableDeclarationIdentifiesCpp11Initialization);
TEST_CASE(test_isVariableDeclarationIdentifiesScopedDeclaration);
TEST_CASE(test_isVariableDeclarationIdentifiesStdDeclaration);
TEST_CASE(test_isVariableDeclarationIdentifiesScopedStdDeclaration);
TEST_CASE(test_isVariableDeclarationIdentifiesManyScopes);
TEST_CASE(test_isVariableDeclarationIdentifiesPointers);
TEST_CASE(test_isVariableDeclarationIdentifiesPointers2);
TEST_CASE(test_isVariableDeclarationDoesNotIdentifyConstness);
TEST_CASE(test_isVariableDeclarationIdentifiesFirstOfManyVariables);
TEST_CASE(test_isVariableDeclarationIdentifiesScopedPointerDeclaration);
TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithIndirection);
TEST_CASE(test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection);
TEST_CASE(test_isVariableDeclarationIdentifiesArray);
TEST_CASE(test_isVariableDeclarationIdentifiesPointerArray);
TEST_CASE(test_isVariableDeclarationIdentifiesOfArrayPointers1);
TEST_CASE(test_isVariableDeclarationIdentifiesOfArrayPointers2);
TEST_CASE(test_isVariableDeclarationIdentifiesOfArrayPointers3);
TEST_CASE(test_isVariableDeclarationIdentifiesArrayOfFunctionPointers);
TEST_CASE(isVariableDeclarationIdentifiesTemplatedPointerVariable);
TEST_CASE(isVariableDeclarationIdentifiesTemplatedPointerToPointerVariable);
TEST_CASE(isVariableDeclarationIdentifiesTemplatedArrayVariable);
TEST_CASE(isVariableDeclarationIdentifiesTemplatedVariable);
TEST_CASE(isVariableDeclarationIdentifiesTemplatedVariableIterator);
TEST_CASE(isVariableDeclarationIdentifiesNestedTemplateVariable);
TEST_CASE(isVariableDeclarationIdentifiesReference);
TEST_CASE(isVariableDeclarationDoesNotIdentifyTemplateClass);
TEST_CASE(isVariableDeclarationDoesNotIdentifyCppCast);
TEST_CASE(isVariableDeclarationPointerConst);
TEST_CASE(isVariableDeclarationRValueRef);
TEST_CASE(isVariableDeclarationDoesNotIdentifyCase);
TEST_CASE(isVariableDeclarationIf);
TEST_CASE(isVariableStlType);
TEST_CASE(isVariablePointerToConstPointer);
TEST_CASE(isVariablePointerToVolatilePointer);
TEST_CASE(isVariablePointerToConstVolatilePointer);
TEST_CASE(isVariableMultiplePointersAndQualifiers);
TEST_CASE(variableVolatile);
TEST_CASE(variableConstexpr);
TEST_CASE(isVariableDecltype);
TEST_CASE(isVariableAlignas);
TEST_CASE(VariableValueType1);
TEST_CASE(VariableValueType2);
TEST_CASE(VariableValueType3);
TEST_CASE(VariableValueType4); // smart pointer type
TEST_CASE(VariableValueType5); // smart pointer type
TEST_CASE(VariableValueTypeReferences);
TEST_CASE(VariableValueTypeTemplate);
TEST_CASE(findVariableType1);
TEST_CASE(findVariableType2);
TEST_CASE(findVariableType3);
TEST_CASE(findVariableTypeExternC);
TEST_CASE(rangeBasedFor);
TEST_CASE(memberVar1);
TEST_CASE(arrayMemberVar1);
TEST_CASE(arrayMemberVar2);
TEST_CASE(arrayMemberVar3);
TEST_CASE(arrayMemberVar4);
TEST_CASE(staticMemberVar);
TEST_CASE(getVariableFromVarIdBoundsCheck);
TEST_CASE(hasRegularFunction);
TEST_CASE(hasRegularFunction_trailingReturnType);
TEST_CASE(hasInlineClassFunction);
TEST_CASE(hasInlineClassFunction_trailingReturnType);
TEST_CASE(hasMissingInlineClassFunction);
TEST_CASE(hasClassFunction);
TEST_CASE(hasClassFunction_trailingReturnType);
TEST_CASE(hasClassFunction_decltype_auto);
TEST_CASE(hasRegularFunctionReturningFunctionPointer);
TEST_CASE(hasInlineClassFunctionReturningFunctionPointer);
TEST_CASE(hasMissingInlineClassFunctionReturningFunctionPointer);
TEST_CASE(hasInlineClassOperatorTemplate);
TEST_CASE(hasClassFunctionReturningFunctionPointer);
TEST_CASE(methodWithRedundantScope);
TEST_CASE(complexFunctionArrayPtr);
TEST_CASE(pointerToMemberFunction);
TEST_CASE(hasSubClassConstructor);
TEST_CASE(testConstructors);
TEST_CASE(functionDeclarationTemplate);
TEST_CASE(functionDeclarations);
TEST_CASE(functionDeclarations2);
TEST_CASE(constexprFunction);
TEST_CASE(constructorInitialization);
TEST_CASE(memberFunctionOfUnknownClassMacro1);
TEST_CASE(memberFunctionOfUnknownClassMacro2);
TEST_CASE(memberFunctionOfUnknownClassMacro3);
TEST_CASE(functionLinkage);
TEST_CASE(externalFunctionsInsideAFunction); // #12420
TEST_CASE(namespacedFunctionInsideExternBlock); // #12420
TEST_CASE(classWithFriend);
TEST_CASE(parseFunctionCorrect);
TEST_CASE(parseFunctionDeclarationCorrect);
TEST_CASE(Cpp11InitInInitList);
TEST_CASE(hasGlobalVariables1);
TEST_CASE(hasGlobalVariables2);
TEST_CASE(hasGlobalVariables3);
TEST_CASE(checkTypeStartEndToken1);
TEST_CASE(checkTypeStartEndToken2); // handling for unknown macro: 'void f() MACRO {..'
TEST_CASE(checkTypeStartEndToken3); // no variable name: void f(const char){}
TEST_CASE(functionArgs1);
TEST_CASE(functionArgs2);
TEST_CASE(functionArgs4);
TEST_CASE(functionArgs5); // #7650
TEST_CASE(functionArgs6); // #7651
TEST_CASE(functionArgs7); // #7652
TEST_CASE(functionArgs8); // #7653
TEST_CASE(functionArgs9); // #7657
TEST_CASE(functionArgs10);
TEST_CASE(functionArgs11);
TEST_CASE(functionArgs12); // #7661
TEST_CASE(functionArgs13); // #7697
TEST_CASE(functionArgs14); // #9055
TEST_CASE(functionArgs15); // #7159
TEST_CASE(functionArgs16); // #9591
TEST_CASE(functionArgs17);
TEST_CASE(functionArgs18); // #10376
TEST_CASE(functionArgs19); // #10376
TEST_CASE(functionArgs20);
TEST_CASE(functionArgs21);
TEST_CASE(functionImplicitlyVirtual);
TEST_CASE(functionGetOverridden);
TEST_CASE(functionIsInlineKeyword);
TEST_CASE(functionStatic);
TEST_CASE(functionReturnsReference); // Function::returnsReference
TEST_CASE(namespaces1);
TEST_CASE(namespaces2);
TEST_CASE(namespaces3); // #3854 - unknown macro
TEST_CASE(namespaces4);
TEST_CASE(needInitialization);
TEST_CASE(tryCatch1);
TEST_CASE(symboldatabase1);
TEST_CASE(symboldatabase2);
TEST_CASE(symboldatabase3); // ticket #2000
TEST_CASE(symboldatabase4);
TEST_CASE(symboldatabase5); // ticket #2178
TEST_CASE(symboldatabase6); // ticket #2221
TEST_CASE(symboldatabase7); // ticket #2230
TEST_CASE(symboldatabase8); // ticket #2252
TEST_CASE(symboldatabase9); // ticket #2525
TEST_CASE(symboldatabase10); // ticket #2537
TEST_CASE(symboldatabase11); // ticket #2539
TEST_CASE(symboldatabase12); // ticket #2547
TEST_CASE(symboldatabase13); // ticket #2577
TEST_CASE(symboldatabase14); // ticket #2589
TEST_CASE(symboldatabase17); // ticket #2657
TEST_CASE(symboldatabase19); // ticket #2991 (segmentation fault)
TEST_CASE(symboldatabase20); // ticket #3013 (segmentation fault)
TEST_CASE(symboldatabase21);
TEST_CASE(symboldatabase22); // ticket #3437 (segmentation fault)
TEST_CASE(symboldatabase23); // ticket #3435
TEST_CASE(symboldatabase24); // ticket #3508 (constructor, destructor)
TEST_CASE(symboldatabase25); // ticket #3561 (throw C++)
TEST_CASE(symboldatabase26); // ticket #3561 (throw C)
TEST_CASE(symboldatabase27); // ticket #3543 (segmentation fault)
TEST_CASE(symboldatabase28);
TEST_CASE(symboldatabase29); // ticket #4442 (segmentation fault)
TEST_CASE(symboldatabase30);
TEST_CASE(symboldatabase31);
TEST_CASE(symboldatabase32);
TEST_CASE(symboldatabase33); // ticket #4682 (false negatives)
TEST_CASE(symboldatabase34); // ticket #4694 (segmentation fault)
TEST_CASE(symboldatabase35); // ticket #4806 (segmentation fault)
TEST_CASE(symboldatabase36); // ticket #4892 (segmentation fault)
TEST_CASE(symboldatabase37);
TEST_CASE(symboldatabase38); // ticket #5125 (infinite recursion)
TEST_CASE(symboldatabase40); // ticket #5153
TEST_CASE(symboldatabase41); // ticket #5197 (unknown macro)
TEST_CASE(symboldatabase42); // only put variables in variable list
TEST_CASE(symboldatabase43); // #4738
TEST_CASE(symboldatabase44);
TEST_CASE(symboldatabase45); // #6125
TEST_CASE(symboldatabase46); // #6171 (anonymous namespace)
TEST_CASE(symboldatabase47); // #6308
TEST_CASE(symboldatabase48); // #6417
TEST_CASE(symboldatabase49); // #6424
TEST_CASE(symboldatabase50); // #6432
TEST_CASE(symboldatabase51); // #6538
TEST_CASE(symboldatabase52); // #6581
TEST_CASE(symboldatabase53); // #7124 (library podtype)
TEST_CASE(symboldatabase54); // #7257
TEST_CASE(symboldatabase55); // #7767 (return unknown macro)
TEST_CASE(symboldatabase56); // #7909
TEST_CASE(symboldatabase57);
TEST_CASE(symboldatabase58); // #6985 (using namespace type lookup)
TEST_CASE(symboldatabase59);
TEST_CASE(symboldatabase60);
TEST_CASE(symboldatabase61);
TEST_CASE(symboldatabase62);
TEST_CASE(symboldatabase63);
TEST_CASE(symboldatabase64);
TEST_CASE(symboldatabase65);
TEST_CASE(symboldatabase66); // #8540
TEST_CASE(symboldatabase67); // #8538
TEST_CASE(symboldatabase68); // #8560
TEST_CASE(symboldatabase69);
TEST_CASE(symboldatabase70);
TEST_CASE(symboldatabase71);
TEST_CASE(symboldatabase72); // #8600
TEST_CASE(symboldatabase74); // #8838 - final
TEST_CASE(symboldatabase75);
TEST_CASE(symboldatabase76); // #9056
TEST_CASE(symboldatabase77); // #8663
TEST_CASE(symboldatabase78); // #9147
TEST_CASE(symboldatabase79); // #9392
TEST_CASE(symboldatabase80); // #9389
TEST_CASE(symboldatabase81); // #9411
TEST_CASE(symboldatabase82);
TEST_CASE(symboldatabase83); // #9431
TEST_CASE(symboldatabase84);
TEST_CASE(symboldatabase85);
TEST_CASE(symboldatabase86);
TEST_CASE(symboldatabase87); // #9922 'extern const char ( * x [ 256 ] ) ;'
TEST_CASE(symboldatabase88); // #10040 (using namespace)
TEST_CASE(symboldatabase89); // valuetype name
TEST_CASE(symboldatabase90);
TEST_CASE(symboldatabase91);
TEST_CASE(symboldatabase92); // daca crash
TEST_CASE(symboldatabase93); // alignas attribute
TEST_CASE(symboldatabase94); // structured bindings
TEST_CASE(symboldatabase95); // #10295
TEST_CASE(symboldatabase96); // #10126
TEST_CASE(symboldatabase97); // #10598 - final class
TEST_CASE(symboldatabase98); // #10451
TEST_CASE(symboldatabase99); // #10864
TEST_CASE(symboldatabase100); // #10174
TEST_CASE(symboldatabase101);
TEST_CASE(symboldatabase102);
TEST_CASE(symboldatabase103);
TEST_CASE(symboldatabase104);
TEST_CASE(symboldatabase105);
TEST_CASE(createSymbolDatabaseFindAllScopes1);
TEST_CASE(createSymbolDatabaseFindAllScopes2);
TEST_CASE(createSymbolDatabaseFindAllScopes3);
TEST_CASE(createSymbolDatabaseFindAllScopes4);
TEST_CASE(createSymbolDatabaseFindAllScopes5);
TEST_CASE(createSymbolDatabaseFindAllScopes6);
TEST_CASE(createSymbolDatabaseFindAllScopes7);
TEST_CASE(createSymbolDatabaseIncompleteVars);
TEST_CASE(enum1);
TEST_CASE(enum2);
TEST_CASE(enum3);
TEST_CASE(enum4);
TEST_CASE(enum5);
TEST_CASE(enum6);
TEST_CASE(enum7);
TEST_CASE(enum8);
TEST_CASE(enum9);
TEST_CASE(enum10); // #11001
TEST_CASE(enum11);
TEST_CASE(enum12);
TEST_CASE(enum13);
TEST_CASE(enum14);
TEST_CASE(enum15);
TEST_CASE(enum16);
TEST_CASE(enum17);
TEST_CASE(sizeOfType);
TEST_CASE(isImplicitlyVirtual);
TEST_CASE(isPure);
TEST_CASE(isFunction1); // UNKNOWN_MACRO(a,b) { .. }
TEST_CASE(isFunction2);
TEST_CASE(isFunction3);
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(findFunction12);
TEST_CASE(findFunction13);
TEST_CASE(findFunction14);
TEST_CASE(findFunction15);
TEST_CASE(findFunction16);
TEST_CASE(findFunction17);
TEST_CASE(findFunction18);
TEST_CASE(findFunction19);
TEST_CASE(findFunction20); // #8280
TEST_CASE(findFunction21);
TEST_CASE(findFunction22);
TEST_CASE(findFunction23);
TEST_CASE(findFunction24); // smart pointer
TEST_CASE(findFunction25); // std::vector>
TEST_CASE(findFunction26); // #8668 - pointer parameter in function call, const pointer function argument
TEST_CASE(findFunction27);
TEST_CASE(findFunction28);
TEST_CASE(findFunction29);
TEST_CASE(findFunction30);
TEST_CASE(findFunction31);
TEST_CASE(findFunction32); // C: relax type matching
TEST_CASE(findFunction33); // #9885 variadic function
TEST_CASE(findFunction34); // #10061
TEST_CASE(findFunction35);
TEST_CASE(findFunction36); // #10122
TEST_CASE(findFunction37); // #10124
TEST_CASE(findFunction38); // #10125
TEST_CASE(findFunction39); // #10127
TEST_CASE(findFunction40); // #10135
TEST_CASE(findFunction41); // #10202
TEST_CASE(findFunction42);
TEST_CASE(findFunction43); // #10087
TEST_CASE(findFunction44); // #11182
TEST_CASE(findFunction45);
TEST_CASE(findFunction46);
TEST_CASE(findFunction47);
TEST_CASE(findFunction48);
TEST_CASE(findFunction49); // #11888
TEST_CASE(findFunction50); // #11904 - method with same name and arguments in derived class
TEST_CASE(findFunction51); // #11975 - method with same name in derived class
TEST_CASE(findFunction52);
TEST_CASE(findFunction53);
TEST_CASE(findFunction54);
TEST_CASE(findFunctionContainer);
TEST_CASE(findFunctionExternC);
TEST_CASE(findFunctionGlobalScope); // ::foo
TEST_CASE(overloadedFunction1);
TEST_CASE(valueTypeMatchParameter); // ValueType::matchParameter
TEST_CASE(noexceptFunction1);
TEST_CASE(noexceptFunction2);
TEST_CASE(noexceptFunction3);
TEST_CASE(noexceptFunction4);
TEST_CASE(throwFunction1);
TEST_CASE(throwFunction2);
TEST_CASE(nothrowAttributeFunction);
TEST_CASE(nothrowDeclspecFunction);
TEST_CASE(noreturnAttributeFunction);
TEST_CASE(nodiscardAttributeFunction);
TEST_CASE(varTypesIntegral); // known integral
TEST_CASE(varTypesFloating); // known floating
TEST_CASE(varTypesOther); // (un)known
TEST_CASE(functionPrototype); // #5867
TEST_CASE(lambda); // #5867
TEST_CASE(lambda2); // #7473
TEST_CASE(lambda3);
TEST_CASE(lambda4);
TEST_CASE(lambda5);
TEST_CASE(circularDependencies); // #6298
TEST_CASE(executableScopeWithUnknownFunction);
TEST_CASE(valueType1);
TEST_CASE(valueType2);
TEST_CASE(valueType3);
TEST_CASE(valueTypeThis);
TEST_CASE(variadic1); // #7453
TEST_CASE(variadic2); // #7649
TEST_CASE(variadic3); // #7387
TEST_CASE(noReturnType);
TEST_CASE(auto1);
TEST_CASE(auto2);
TEST_CASE(auto3);
TEST_CASE(auto4);
TEST_CASE(auto5);
TEST_CASE(auto6); // #7963 (segmentation fault)
TEST_CASE(auto7);
TEST_CASE(auto8);
TEST_CASE(auto9); // #8044 (segmentation fault)
TEST_CASE(auto10); // #8020
TEST_CASE(auto11); // #8964 - const auto startX = x;
TEST_CASE(auto12); // #8993 - const std::string &x; auto y = x; if (y.empty()) ..
TEST_CASE(auto13);
TEST_CASE(auto14);
TEST_CASE(auto15); // C++17 auto deduction from braced-init-list
TEST_CASE(auto16);
TEST_CASE(auto17); // #11163
TEST_CASE(auto18);
TEST_CASE(auto19);
TEST_CASE(auto20);
TEST_CASE(auto21);
TEST_CASE(auto22);
TEST_CASE(unionWithConstructor);
TEST_CASE(incomplete_type); // #9255 (infinite recursion)
TEST_CASE(exprIds);
}
void array() {
GET_SYMBOL_DB_C("int a[10+2];");
ASSERT(db != nullptr);
ASSERT(db->variableList().size() == 2); // the first one is not used
const Variable * v = db->getVariableFromVarId(1);
ASSERT(v != nullptr);
ASSERT(v->isArray());
ASSERT_EQUALS(1U, v->dimensions().size());
ASSERT_EQUALS(12U, v->dimension(0));
}
void array_ptr() {
GET_SYMBOL_DB("const char* a[] = { \"abc\" };\n"
"const char* b[] = { \"def\", \"ghijkl\" };");
ASSERT(db != nullptr);
ASSERT(db->variableList().size() == 3); // the first one is not used
const Variable* v = db->getVariableFromVarId(1);
ASSERT(v != nullptr);
ASSERT(v->isArray());
ASSERT(v->isPointerArray());
ASSERT_EQUALS(1U, v->dimensions().size());
ASSERT_EQUALS(1U, v->dimension(0));
v = db->getVariableFromVarId(2);
ASSERT(v != nullptr);
ASSERT(v->isArray());
ASSERT(v->isPointerArray());
ASSERT_EQUALS(1U, v->dimensions().size());
ASSERT_EQUALS(2U, v->dimension(0));
}
void stlarray1() {
GET_SYMBOL_DB("std::array arr;");
ASSERT(db != nullptr);
ASSERT_EQUALS(2, db->variableList().size()); // the first one is not used
const Variable * v = db->getVariableFromVarId(1);
ASSERT(v != nullptr);
ASSERT(v->isArray());
ASSERT_EQUALS(1U, v->dimensions().size());
ASSERT_EQUALS(20U, v->dimension(0));
}
void stlarray2() {
GET_SYMBOL_DB("constexpr int sz = 16; std::array arr;");
ASSERT(db != nullptr);
ASSERT_EQUALS(3, db->variableList().size()); // the first one is not used
const Variable * v = db->getVariableFromVarId(2);
ASSERT(v != nullptr);
ASSERT(v->isArray());
ASSERT_EQUALS(1U, v->dimensions().size());
ASSERT_EQUALS(20U, v->dimension(0));
}
void stlarray3() {
GET_SYMBOL_DB("std::array a;\n"
"std::array b[2];\n"
"const std::array& r = a;\n");
ASSERT(db != nullptr);
ASSERT_EQUALS(4, db->variableList().size()); // the first one is not used
auto it = db->variableList().begin() + 1;
ASSERT((*it)->isArray());
ASSERT(!(*it)->isPointer());
ASSERT(!(*it)->isReference());
ASSERT_EQUALS(1U, (*it)->dimensions().size());
ASSERT_EQUALS(4U, (*it)->dimension(0));
const ValueType* vt = (*it)->valueType();
ASSERT(vt && vt->container);
ASSERT_EQUALS(vt->pointer, 0);
const Token* tok = (*it)->nameToken();
ASSERT(tok && (vt = tok->valueType()));
ASSERT_EQUALS(vt->pointer, 0);
++it;
ASSERT((*it)->isArray());
ASSERT(!(*it)->isPointer());
ASSERT(!(*it)->isReference());
ASSERT_EQUALS(1U, (*it)->dimensions().size());
ASSERT_EQUALS(4U, (*it)->dimension(0));
vt = (*it)->valueType();
ASSERT_EQUALS(vt->pointer, 0);
tok = (*it)->nameToken();
ASSERT(tok && (vt = tok->valueType()));
ASSERT_EQUALS(vt->pointer, 1);
++it;
ASSERT((*it)->isArray());
ASSERT(!(*it)->isPointer());
ASSERT((*it)->isReference());
ASSERT((*it)->isConst());
ASSERT_EQUALS(1U, (*it)->dimensions().size());
ASSERT_EQUALS(4U, (*it)->dimension(0));
vt = (*it)->valueType();
ASSERT_EQUALS(vt->pointer, 0);
ASSERT(vt->reference == Reference::LValue);
tok = (*it)->nameToken();
ASSERT(tok && (vt = tok->valueType()));
ASSERT_EQUALS(vt->pointer, 0);
ASSERT_EQUALS(vt->constness, 1);
ASSERT(vt->reference == Reference::LValue);
}
void test_isVariableDeclarationCanHandleNull() {
reset();
GET_SYMBOL_DB("void main(){}");
const bool result = db->scopeList.front().isVariableDeclaration(nullptr, vartok, typetok);
ASSERT_EQUALS(false, result);
ASSERT(nullptr == vartok);
ASSERT(nullptr == typetok);
Variable v(nullptr, nullptr, nullptr, 0, AccessControl::Public, nullptr, nullptr, &settings1);
}
void test_isVariableDeclarationIdentifiesSimpleDeclaration() {
reset();
GET_SYMBOL_DB("int x;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("int", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesInitialization() {
reset();
GET_SYMBOL_DB("int x (1);");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("int", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesCpp11Initialization() {
reset();
GET_SYMBOL_DB("int x {1};");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("int", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesScopedDeclaration() {
reset();
GET_SYMBOL_DB("::int x;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("int", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesStdDeclaration() {
reset();
GET_SYMBOL_DB("std::string x;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("string", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesScopedStdDeclaration() {
reset();
GET_SYMBOL_DB("::std::string x;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("string", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesManyScopes() {
reset();
GET_SYMBOL_DB("AA::BB::CC::DD::EE x;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("x", vartok->str());
ASSERT_EQUALS("EE", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesPointers() {
{
reset();
GET_SYMBOL_DB("int* p;");
const bool result1 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result1);
ASSERT_EQUALS("p", vartok->str());
ASSERT_EQUALS("int", typetok->str());
Variable v1(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v1.isArray());
ASSERT(true == v1.isPointer());
ASSERT(false == v1.isReference());
}
{
reset();
const SimpleTokenizer constpointer(*this, "const int* p;");
Variable v2(constpointer.tokens()->tokAt(3), constpointer.tokens()->next(), constpointer.tokens()->tokAt(2), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v2.isArray());
ASSERT(true == v2.isPointer());
ASSERT(false == v2.isConst());
ASSERT(false == v2.isReference());
}
{
reset();
GET_SYMBOL_DB("int* const p;");
const bool result2 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result2);
ASSERT_EQUALS("p", vartok->str());
ASSERT_EQUALS("int", typetok->str());
Variable v3(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v3.isArray());
ASSERT(true == v3.isPointer());
ASSERT(true == v3.isConst());
ASSERT(false == v3.isReference());
}
}
void test_isVariableDeclarationIdentifiesPointers2() {
GET_SYMBOL_DB("void slurpInManifest() {\n"
" std::string tmpiostring(*tI);\n"
" if(tmpiostring==\"infoonly\"){}\n"
"}");
const Token *tok = Token::findsimplematch(tokenizer.tokens(), "tmpiostring ==");
ASSERT(tok->variable());
ASSERT(!tok->variable()->isPointer());
}
void test_isVariableDeclarationDoesNotIdentifyConstness() {
reset();
GET_SYMBOL_DB("const int* cp;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(false, result);
ASSERT(nullptr == vartok);
ASSERT(nullptr == typetok);
}
void test_isVariableDeclarationIdentifiesFirstOfManyVariables() {
reset();
GET_SYMBOL_DB("int first, second;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("first", vartok->str());
ASSERT_EQUALS("int", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesScopedPointerDeclaration() {
reset();
GET_SYMBOL_DB("AA::BB::CC::DD::EE* p;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("p", vartok->str());
ASSERT_EQUALS("EE", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesDeclarationWithIndirection() {
reset();
GET_SYMBOL_DB("int** pp;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("pp", vartok->str());
ASSERT_EQUALS("int", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesDeclarationWithMultipleIndirection() {
reset();
GET_SYMBOL_DB("int***** p;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("p", vartok->str());
ASSERT_EQUALS("int", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesArray() {
reset();
GET_SYMBOL_DB("::std::string v[3];");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("v", vartok->str());
ASSERT_EQUALS("string", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(true == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isPointerArray());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesPointerArray() {
reset();
GET_SYMBOL_DB("A *a[5];");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("a", vartok->str());
ASSERT_EQUALS("A", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isPointer());
ASSERT(true == v.isArray());
ASSERT(false == v.isPointerToArray());
ASSERT(true == v.isPointerArray());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesOfArrayPointers1() {
reset();
GET_SYMBOL_DB("A (*a)[5];");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("a", vartok->str());
ASSERT_EQUALS("A", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(true == v.isPointer());
ASSERT(false == v.isArray());
ASSERT(true == v.isPointerToArray());
ASSERT(false == v.isPointerArray());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesOfArrayPointers2() {
reset();
GET_SYMBOL_DB("A (*const a)[5];");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("a", vartok->str());
ASSERT_EQUALS("A", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(true == v.isPointer());
ASSERT(false == v.isArray());
ASSERT(true == v.isPointerToArray());
ASSERT(false == v.isPointerArray());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesOfArrayPointers3() {
reset();
GET_SYMBOL_DB("A (** a)[5];");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("a", vartok->str());
ASSERT_EQUALS("A", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(true == v.isPointer());
ASSERT(false == v.isArray());
ASSERT(true == v.isPointerToArray());
ASSERT(false == v.isPointerArray());
ASSERT(false == v.isReference());
}
void test_isVariableDeclarationIdentifiesArrayOfFunctionPointers() {
reset();
GET_SYMBOL_DB("int (*a[])(int) = { g };"); // #11596
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("a", vartok->str());
ASSERT_EQUALS("int", 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());
ASSERT(true == v.isInit());
}
void isVariableDeclarationIdentifiesTemplatedPointerVariable() {
reset();
GET_SYMBOL_DB("std::set* chars;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("chars", vartok->str());
ASSERT_EQUALS("set", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariableDeclarationIdentifiesTemplatedPointerToPointerVariable() {
reset();
GET_SYMBOL_DB("std::deque*** ints;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("ints", vartok->str());
ASSERT_EQUALS("deque", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariableDeclarationIdentifiesTemplatedArrayVariable() {
reset();
GET_SYMBOL_DB("std::deque ints[3];");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("ints", vartok->str());
ASSERT_EQUALS("deque", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(true == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariableDeclarationIdentifiesTemplatedVariable() {
reset();
GET_SYMBOL_DB("std::vector ints;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("ints", vartok->str());
ASSERT_EQUALS("vector", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariableDeclarationIdentifiesTemplatedVariableIterator() {
reset();
GET_SYMBOL_DB("std::list::const_iterator floats;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("floats", vartok->str());
ASSERT_EQUALS("const_iterator", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariableDeclarationIdentifiesNestedTemplateVariable() {
reset();
GET_SYMBOL_DB("std::deque > intsets;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
ASSERT_EQUALS("intsets", vartok->str());
ASSERT_EQUALS("deque", typetok->str());
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariableDeclarationIdentifiesReference() {
{
reset();
GET_SYMBOL_DB("int& foo;");
const bool result1 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result1);
Variable v1(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v1.isArray());
ASSERT(false == v1.isPointer());
ASSERT(true == v1.isReference());
}
{
reset();
GET_SYMBOL_DB("foo*& bar;");
const bool result2 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result2);
Variable v2(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v2.isArray());
ASSERT(true == v2.isPointer());
ASSERT(true == v2.isReference());
}
{
reset();
GET_SYMBOL_DB("std::vector& foo;");
const bool result3 = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result3);
Variable v3(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v3.isArray());
ASSERT(false == v3.isPointer());
ASSERT(true == v3.isReference());
}
}
void isVariableDeclarationDoesNotIdentifyTemplateClass() {
reset();
GET_SYMBOL_DB("template class SomeClass{};");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(false, result);
}
void isVariableDeclarationDoesNotIdentifyCppCast() {
reset();
GET_SYMBOL_DB("reinterpret_cast (code)[0] = 0;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(false, result);
}
void isVariableDeclarationPointerConst() {
reset();
GET_SYMBOL_DB("std::string const* s;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens()->next(), vartok, typetok);
ASSERT_EQUALS(true, result);
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariableDeclarationRValueRef() {
reset();
GET_SYMBOL_DB("int&& i;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(false == v.isPointer());
ASSERT(true == v.isReference());
ASSERT(true == v.isRValueReference());
ASSERT(tokenizer.tokens()->tokAt(2)->scope() != nullptr);
}
void isVariableDeclarationDoesNotIdentifyCase() {
GET_SYMBOL_DB_C("a b;\n"
"void f() {\n"
" switch (c) {\n"
" case b:;\n"
" }"
"}");
const Variable* b = db->getVariableFromVarId(1);
ASSERT_EQUALS("b", b->name());
ASSERT_EQUALS("a", b->typeStartToken()->str());
}
void isVariableDeclarationIf() {
GET_SYMBOL_DB("void foo() {\n"
" for (auto& elem : items) {\n"
" if (auto x = bar()) { int y = 3; }\n"
" }\n"
"}");
const Token *x = Token::findsimplematch(tokenizer.tokens(), "x");
ASSERT(x);
ASSERT(x->varId());
ASSERT(x->variable());
const Token *y = Token::findsimplematch(tokenizer.tokens(), "y");
ASSERT(y);
ASSERT(y->varId());
ASSERT(y->variable());
}
void VariableValueType1() {
GET_SYMBOL_DB("typedef uint8_t u8;\n"
"static u8 x;");
const Variable* x = db->getVariableFromVarId(1);
ASSERT_EQUALS("x", x->name());
ASSERT(x->valueType()->isIntegral());
}
void VariableValueType2() {
GET_SYMBOL_DB("using u8 = uint8_t;\n"
"static u8 x;");
const Variable* x = db->getVariableFromVarId(1);
ASSERT_EQUALS("x", x->name());
ASSERT(x->valueType()->isIntegral());
}
void VariableValueType3() {
// std::string::size_type
{
GET_SYMBOL_DB("void f(std::string::size_type x);");
const Variable* const x = db->getVariableFromVarId(1);
ASSERT_EQUALS("x", x->name());
// TODO: Configure std::string::size_type somehow.
TODO_ASSERT_EQUALS(ValueType::Type::LONGLONG, ValueType::Type::UNKNOWN_INT, x->valueType()->type);
ASSERT_EQUALS(ValueType::Sign::UNSIGNED, x->valueType()->sign);
}
// std::wstring::size_type
{
GET_SYMBOL_DB("void f(std::wstring::size_type x);");
const Variable* const x = db->getVariableFromVarId(1);
ASSERT_EQUALS("x", x->name());
// TODO: Configure std::wstring::size_type somehow.
TODO_ASSERT_EQUALS(ValueType::Type::LONGLONG, ValueType::Type::UNKNOWN_INT, x->valueType()->type);
ASSERT_EQUALS(ValueType::Sign::UNSIGNED, x->valueType()->sign);
}
// std::u16string::size_type
{
GET_SYMBOL_DB("void f(std::u16string::size_type x);");
const Variable* const x = db->getVariableFromVarId(1);
ASSERT_EQUALS("x", x->name());
// TODO: Configure std::u16string::size_type somehow.
TODO_ASSERT_EQUALS(ValueType::Type::LONGLONG, ValueType::Type::UNKNOWN_INT, x->valueType()->type);
ASSERT_EQUALS(ValueType::Sign::UNSIGNED, x->valueType()->sign);
}
// std::u32string::size_type
{
GET_SYMBOL_DB("void f(std::u32string::size_type x);");
const Variable* const x = db->getVariableFromVarId(1);
ASSERT_EQUALS("x", x->name());
// TODO: Configure std::u32string::size_type somehow.
TODO_ASSERT_EQUALS(ValueType::Type::LONGLONG, ValueType::Type::UNKNOWN_INT, x->valueType()->type);
ASSERT_EQUALS(ValueType::Sign::UNSIGNED, x->valueType()->sign);
}
}
void VariableValueType4() {
GET_SYMBOL_DB("class C {\n"
"public:\n"
" std::shared_ptr x;\n"
"};");
const Variable* const x = db->getVariableFromVarId(1);
ASSERT(x->valueType());
ASSERT(x->valueType()->smartPointerType);
}
void VariableValueType5() {
GET_SYMBOL_DB("class C {};\n"
"void foo(std::shared_ptr* p) {}");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->smartPointerTypeToken);
ASSERT(p->valueType()->pointer == 1);
}
void VariableValueTypeReferences() {
{
GET_SYMBOL_DB("void foo(int x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::None);
}
{
GET_SYMBOL_DB("void foo(volatile int x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 1);
ASSERT(p->valueType()->reference == Reference::None);
}
{
GET_SYMBOL_DB("void foo(int* x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::None);
}
{
GET_SYMBOL_DB("void foo(int& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::LValue);
}
{
GET_SYMBOL_DB("void foo(int&& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::RValue);
}
{
GET_SYMBOL_DB("void foo(int*& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::LValue);
}
{
GET_SYMBOL_DB("void foo(int*&& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::RValue);
}
{
GET_SYMBOL_DB("void foo(int**& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 2);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::LValue);
}
{
GET_SYMBOL_DB("void foo(int**&& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 2);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::RValue);
}
{
GET_SYMBOL_DB("void foo(const int& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 1);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::LValue);
}
{
GET_SYMBOL_DB("void foo(const int&& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 1);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::RValue);
}
{
GET_SYMBOL_DB("void foo(const int*& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 1);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::LValue);
}
{
GET_SYMBOL_DB("void foo(const int*&& x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 1);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::RValue);
}
{
GET_SYMBOL_DB("void foo(int* const & x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 2);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::LValue);
}
{
GET_SYMBOL_DB("void foo(int* const && x) {}\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 2);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->reference == Reference::RValue);
}
{
GET_SYMBOL_DB("extern const volatile int* test[];\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 1);
ASSERT(p->valueType()->volatileness == 1);
ASSERT(p->valueType()->reference == Reference::None);
}
{
GET_SYMBOL_DB("extern const int* volatile test[];\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 1);
ASSERT(p->valueType()->volatileness == 2);
ASSERT(p->valueType()->reference == Reference::None);
}
{
GET_SYMBOL_DB_C("typedef unsigned char uint8_t;\n uint8_t ubVar = 0;\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->originalTypeName == "uint8_t");
ASSERT(p->valueType()->reference == Reference::None);
}
{
GET_SYMBOL_DB_C("typedef enum eEnumDef {CPPCHECK=0}eEnum_t;\n eEnum_t eVar = CPPCHECK;\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->originalTypeName == "eEnum_t");
ASSERT(p->valueType()->reference == Reference::None);
}
{
GET_SYMBOL_DB_C("typedef unsigned char uint8_t;\n typedef struct stStructDef {uint8_t ubTest;}stStruct_t;\n stStruct_t stVar;\n");
const Variable* p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->originalTypeName == "uint8_t");
ASSERT(p->valueType()->reference == Reference::None);
p = db->getVariableFromVarId(2);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 0);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->originalTypeName == "stStruct_t");
ASSERT(p->valueType()->reference == Reference::None);
}
{
GET_SYMBOL_DB_C("typedef int (*ubFunctionPointer_fp)(int);\n void test(ubFunctionPointer_fp functionPointer);\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->volatileness == 0);
ASSERT(p->valueType()->originalTypeName == "ubFunctionPointer_fp");
ASSERT(p->valueType()->reference == Reference::None);
}
}
void VariableValueTypeTemplate() {
{
GET_SYMBOL_DB("template \n" // #12393
"struct S {\n"
" struct U {\n"
" S* p;\n"
" };\n"
" U u;\n"
"};\n");
const Variable* const p = db->getVariableFromVarId(1);
ASSERT_EQUALS(p->name(), "p");
ASSERT(p->valueType());
ASSERT(p->valueType()->pointer == 1);
ASSERT(p->valueType()->constness == 0);
ASSERT(p->valueType()->reference == Reference::None);
ASSERT_EQUALS(p->scope()->className, "U");
ASSERT_EQUALS(p->typeScope()->className, "S");
}
}
void findVariableType1() {
GET_SYMBOL_DB("class A {\n"
"public:\n"
" struct B {};\n"
" void f();\n"
"};\n"
"\n"
"void f()\n"
"{\n"
" struct A::B b;\n"
" b.x = 1;\n"
"}");
ASSERT(db != nullptr);
const Variable* bvar = db->getVariableFromVarId(1);
ASSERT_EQUALS("b", bvar->name());
ASSERT(bvar->type() != nullptr);
}
void findVariableType2() {
GET_SYMBOL_DB("class A {\n"
"public:\n"
" class B {\n"
" public:\n"
" struct C {\n"
" int x;\n"
" int y;\n"
" };\n"
" };\n"
"\n"
" void f();\n"
"};\n"
"\n"
"void A::f()\n"
"{\n"
" struct B::C c;\n"
" c.x = 1;\n"
"}");
ASSERT(db != nullptr);
const Variable* cvar = db->getVariableFromVarId(3);
ASSERT_EQUALS("c", cvar->name());
ASSERT(cvar->type() != nullptr);
}
void findVariableType3() {
GET_SYMBOL_DB("namespace {\n"
" struct A {\n"
" int x;\n"
" int y;\n"
" };\n"
"}\n"
"\n"
"void f()\n"
"{\n"
" struct A a;\n"
" a.x = 1;\n"
"}");
(void)db;
const Variable* avar = Token::findsimplematch(tokenizer.tokens(), "a")->variable();
ASSERT(avar);
ASSERT(avar && avar->type() != nullptr);
}
void findVariableTypeExternC() {
GET_SYMBOL_DB("extern \"C\" { typedef int INT; }\n"
"void bar() {\n"
" INT x = 3;\n"
"}");
(void)db;
const Variable* avar = Token::findsimplematch(tokenizer.tokens(), "x")->variable();
ASSERT(avar);
ASSERT(avar->valueType() != nullptr);
ASSERT(avar->valueType()->str() == "signed int");
}
void rangeBasedFor() {
GET_SYMBOL_DB("void reset() {\n"
" for(auto& e : array)\n"
" foo(e);\n"
"}");
ASSERT(db != nullptr);
ASSERT(db->scopeList.back().type == Scope::eFor);
ASSERT_EQUALS(2, db->variableList().size());
const Variable* e = db->getVariableFromVarId(1);
ASSERT(e && e->isReference() && e->isLocal());
}
void isVariableStlType() {
{
reset();
GET_SYMBOL_DB("std::string s;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
Variable v(vartok, tokenizer.tokens(), tokenizer.list.back(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
static const std::set types = { "string", "wstring" };
static const std::set no_types = { "set" };
ASSERT_EQUALS(true, v.isStlType());
ASSERT_EQUALS(true, v.isStlType(types));
ASSERT_EQUALS(false, v.isStlType(no_types));
ASSERT_EQUALS(true, v.isStlStringType());
}
{
reset();
GET_SYMBOL_DB("std::vector v;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
Variable v(vartok, tokenizer.tokens(), tokenizer.list.back(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
static const std::set types = { "bitset", "set", "vector", "wstring" };
static const std::set no_types = { "bitset", "map", "set" };
ASSERT_EQUALS(true, v.isStlType());
ASSERT_EQUALS(true, v.isStlType(types));
ASSERT_EQUALS(false, v.isStlType(no_types));
ASSERT_EQUALS(false, v.isStlStringType());
}
{
reset();
GET_SYMBOL_DB("SomeClass s;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
Variable v(vartok, tokenizer.tokens(), tokenizer.list.back(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
static const std::set types = { "bitset", "set", "vector" };
ASSERT_EQUALS(false, v.isStlType());
ASSERT_EQUALS(false, v.isStlType(types));
ASSERT_EQUALS(false, v.isStlStringType());
}
}
void isVariablePointerToConstPointer() {
reset();
GET_SYMBOL_DB("char* const * s;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariablePointerToVolatilePointer() {
reset();
GET_SYMBOL_DB("char* volatile * s;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariablePointerToConstVolatilePointer() {
reset();
GET_SYMBOL_DB("char* const volatile * s;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens(), vartok, typetok);
ASSERT_EQUALS(true, result);
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void isVariableMultiplePointersAndQualifiers() {
reset();
GET_SYMBOL_DB("const char* const volatile * const volatile * const volatile * const volatile s;");
const bool result = db->scopeList.front().isVariableDeclaration(tokenizer.tokens()->next(), vartok, typetok);
ASSERT_EQUALS(true, result);
Variable v(vartok, typetok, vartok->previous(), 0, AccessControl::Public, nullptr, nullptr, &settings1);
ASSERT(false == v.isArray());
ASSERT(true == v.isPointer());
ASSERT(false == v.isReference());
}
void variableVolatile() {
GET_SYMBOL_DB("std::atomic x;\n"
"volatile int y;");
const Token *x = Token::findsimplematch(tokenizer.tokens(), "x");
ASSERT(x);
ASSERT(x->variable());
ASSERT(x->variable()->isVolatile());
const Token *y = Token::findsimplematch(tokenizer.tokens(), "y");
ASSERT(y);
ASSERT(y->variable());
ASSERT(y->variable()->isVolatile());
}
void variableConstexpr() {
GET_SYMBOL_DB("constexpr int x = 16;");
const Token *x = Token::findsimplematch(tokenizer.tokens(), "x");
ASSERT(x);
ASSERT(x->variable());
ASSERT(x->variable()->isConst());
ASSERT(x->variable()->isStatic());
ASSERT(x->valueType());
ASSERT(x->valueType()->pointer == 0);
ASSERT(x->valueType()->constness == 1);
ASSERT(x->valueType()->reference == Reference::None);
}
void isVariableDecltype() {
GET_SYMBOL_DB("int x;\n"
"decltype(x) a;\n"
"const decltype(x) b;\n"
"decltype(x) *c;\n");
ASSERT(db);
ASSERT_EQUALS(4, db->scopeList.front().varlist.size());
const Variable *a = Token::findsimplematch(tokenizer.tokens(), "a")->variable();
ASSERT(a);
ASSERT_EQUALS("a", a->name());
ASSERT(a->valueType());
ASSERT_EQUALS("signed int", a->valueType()->str());
const Variable *b = Token::findsimplematch(tokenizer.tokens(), "b")->variable();
ASSERT(b);
ASSERT_EQUALS("b", b->name());
ASSERT(b->valueType());
ASSERT_EQUALS("const signed int", b->valueType()->str());
const Variable *c = Token::findsimplematch(tokenizer.tokens(), "c")->variable();
ASSERT(c);
ASSERT_EQUALS("c", c->name());
ASSERT(c->valueType());
ASSERT_EQUALS("signed int *", c->valueType()->str());
}
void isVariableAlignas() {
GET_SYMBOL_DB_C("extern alignas(16) int x;\n"
"alignas(16) int x;\n");
ASSERT(db);
ASSERT_EQUALS(2, db->scopeList.front().varlist.size());
const Variable *x1 = Token::findsimplematch(tokenizer.tokens(), "x")->variable();
ASSERT(x1 && Token::simpleMatch(x1->typeStartToken(), "alignas ( 16 ) int x ;"));
}
void memberVar1() {
GET_SYMBOL_DB("struct Foo {\n"
" int x;\n"
"};\n"
"struct Bar : public Foo {};\n"
"void f() {\n"
" struct Bar bar;\n"
" bar.x = 123;\n" // <- x should get a variable() pointer
"}");
ASSERT(db != nullptr);
const Token *tok = Token::findsimplematch(tokenizer.tokens(), "x =");
ASSERT(tok->variable());
ASSERT(Token::simpleMatch(tok->variable()->typeStartToken(), "int x ;"));
}
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 arrayMemberVar4() {
GET_SYMBOL_DB("struct S { unsigned char* s; };\n"
"struct T { S s[38]; };\n"
"void f(T* t) {\n"
" t->s;\n"
"}\n");
const Token *tok = Token::findsimplematch(tokenizer.tokens(), ". s");
tok = tok ? tok->next() : nullptr;
ASSERT(db != nullptr);
ASSERT(tok && tok->variable() && Token::simpleMatch(tok->variable()->typeStartToken(), "S s [ 38 ] ;"));
ASSERT(tok && tok->varId() == 4U);
}
void staticMemberVar() {
GET_SYMBOL_DB("class Foo {\n"
" static const double d;\n"
"};\n"
"const double Foo::d = 5.0;");
const Variable* v = db->getVariableFromVarId(1);
ASSERT(v && db->variableList().size() == 2);
ASSERT(v && v->isStatic() && v->isConst() && v->isPrivate());
}
void getVariableFromVarIdBoundsCheck() {
GET_SYMBOL_DB("int x;\n"
"int y;");
const Variable* v = db->getVariableFromVarId(2);
// three elements: varId 0 also counts via a fake-entry
ASSERT(v && db->variableList().size() == 3);
ASSERT_THROW(db->getVariableFromVarId(3), std::out_of_range);
}
void hasRegularFunction() {
GET_SYMBOL_DB("void func() { }");
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2);
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->next());
ASSERT(scope && scope->className == "func");
ASSERT(scope->functionOf == nullptr);
const Function *function = findFunctionByName("func", &db->scopeList.front());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->next());
ASSERT(function && function->hasBody());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn != scope);
ASSERT(function && function->retDef == tokenizer.tokens());
}
void hasRegularFunction_trailingReturnType() {
GET_SYMBOL_DB("auto func() -> int { }");
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2);
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->next());
ASSERT(scope && scope->className == "func");
ASSERT(scope->functionOf == nullptr);
const Function *function = findFunctionByName("func", &db->scopeList.front());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == tokenizer.tokens()->next());
ASSERT(function && function->hasBody());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn != scope);
ASSERT(function && function->retDef == tokenizer.tokens()->tokAt(5));
}
void hasInlineClassFunction() {
GET_SYMBOL_DB("class Fred { void func() { } };");
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody() && function->isInline());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
ASSERT(function && function->retDef == functionToken->previous());
ASSERT(db && db->findScopeByName("Fred") && db->findScopeByName("Fred")->definedType->getFunction("func") == function);
}
void hasInlineClassFunction_trailingReturnType() {
GET_SYMBOL_DB("class Fred { auto func() -> int { } };");
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody() && function->isInline());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
ASSERT(function && function->retDef == functionToken->tokAt(4));
ASSERT(db && db->findScopeByName("Fred") && db->findScopeByName("Fred")->definedType->getFunction("func") == function);
}
void hasMissingInlineClassFunction() {
GET_SYMBOL_DB("class Fred { void func(); };");
// 2 scopes: Global and Class (no Function scope because there is no function implementation)
ASSERT(db && db->scopeList.size() == 2);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope == nullptr);
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && !function->hasBody());
}
void hasInlineClassOperatorTemplate() {
GET_SYMBOL_DB("struct Fred { template Foo & operator=(const Foo &) { return *this; } };");
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "operator=");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "operator=");
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
const Function *function = findFunctionByName("operator=", &db->scopeList.back());
ASSERT(function && function->token->str() == "operator=");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody() && function->isInline());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
ASSERT(function && function->retDef == functionToken->tokAt(-2));
ASSERT(db && db->findScopeByName("Fred") && db->findScopeByName("Fred")->definedType->getFunction("operator=") == function);
}
void hasClassFunction() {
GET_SYMBOL_DB("class Fred { void func(); }; void Fred::func() { }");
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens()->linkAt(2), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody() && !function->isInline());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
}
void hasClassFunction_trailingReturnType() {
GET_SYMBOL_DB("class Fred { auto func() -> int; }; auto Fred::func() -> int { }");
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens()->linkAt(2), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody() && !function->isInline());
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
}
void hasClassFunction_decltype_auto()
{
GET_SYMBOL_DB("struct d { decltype(auto) f() {} };");
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3);
const Token* const functionToken = Token::findsimplematch(tokenizer.tokens(), "f");
const Scope* scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "f");
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("d"));
const Function* function = findFunctionByName("f", &db->scopeList.back());
ASSERT(function && function->token->str() == "f");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody());
}
void hasRegularFunctionReturningFunctionPointer() {
GET_SYMBOL_DB("void (*func(int f))(char) { }");
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
const Function *function = findFunctionByName("func", &db->scopeList.front());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody());
}
void hasInlineClassFunctionReturningFunctionPointer() {
GET_SYMBOL_DB("class Fred { void (*func(int f))(char) { } };");
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody() && function->isInline());
}
void hasMissingInlineClassFunctionReturningFunctionPointer() {
GET_SYMBOL_DB("class Fred { void (*func(int f))(char); };");
// 2 scopes: Global and Class (no Function scope because there is no function implementation)
ASSERT(db && db->scopeList.size() == 2);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope == nullptr);
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && !function->hasBody());
}
void hasClassFunctionReturningFunctionPointer() {
GET_SYMBOL_DB("class Fred { void (*func(int f))(char); }; void (*Fred::func(int f))(char) { }");
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens()->linkAt(2), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody() && !function->isInline());
}
void methodWithRedundantScope() {
GET_SYMBOL_DB("class Fred { void Fred::func() {} };");
// 3 scopes: Global, Class, and Function
ASSERT(db && db->scopeList.size() == 3);
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func");
const Scope *scope = findFunctionScopeByToken(db, functionToken);
ASSERT(scope && scope->className == "func");
const Function *function = findFunctionByName("func", &db->scopeList.back());
ASSERT(function && function->token->str() == "func");
ASSERT(function && function->token == functionToken);
ASSERT(function && function->hasBody() && function->isInline());
}
void complexFunctionArrayPtr() {
GET_SYMBOL_DB("int(*p1)[10]; \n" // pointer to array 10 of int
"void(*p2)(char); \n" // pointer to function (char) returning void
"int(*(*p3)(char))[10];\n" // pointer to function (char) returning pointer to array 10 of int
"float(*(*p4)(char))(long); \n" // pointer to function (char) returning pointer to function (long) returning float
"short(*(*(*p5) (char))(long))(double);\n" // pointer to function (char) returning pointer to function (long) returning pointer to function (double) returning short
"int(*a1[10])(void); \n" // array 10 of pointer to function (void) returning int
"float(*(*a2[10])(char))(long);\n" // array 10 of pointer to func (char) returning pointer to func (long) returning float
"short(*(*(*a3[10])(char))(long))(double);\n" // array 10 of pointer to function (char) returning pointer to function (long) returning pointer to function (double) returning short
"::boost::rational(&r_)[9];\n" // reference to array of ::boost::rational
"::boost::rational(&r_)[9];"); // reference to array of ::boost::rational (template!)
ASSERT(db != nullptr);
ASSERT_EQUALS(10, db->variableList().size() - 1);
ASSERT_EQUALS(true, db->getVariableFromVarId(1) && db->getVariableFromVarId(1)->dimensions().size() == 1);
ASSERT_EQUALS(true, db->getVariableFromVarId(2) != nullptr);
// NOLINTNEXTLINE(readability-container-size-empty)
ASSERT_EQUALS(true, db->getVariableFromVarId(3) && db->getVariableFromVarId(3)->dimensions().size() == 0);
ASSERT_EQUALS(true, db->getVariableFromVarId(4) != nullptr);
ASSERT_EQUALS(true, db->getVariableFromVarId(5) != nullptr);
ASSERT_EQUALS(true, db->getVariableFromVarId(6) && db->getVariableFromVarId(6)->dimensions().size() == 1);
ASSERT_EQUALS(true, db->getVariableFromVarId(7) && db->getVariableFromVarId(7)->dimensions().size() == 1);
ASSERT_EQUALS(true, db->getVariableFromVarId(8) && db->getVariableFromVarId(8)->dimensions().size() == 1);
ASSERT_EQUALS(true, db->getVariableFromVarId(9) && db->getVariableFromVarId(9)->dimensions().size() == 1);
ASSERT_EQUALS(true, db->getVariableFromVarId(10) && db->getVariableFromVarId(10)->dimensions().size() == 1);
ASSERT_EQUALS("", errout_str());
}
void pointerToMemberFunction() {
GET_SYMBOL_DB("bool (A::*pFun)();"); // Pointer to member function of A, returning bool and taking no parameters
ASSERT(db != nullptr);
ASSERT_EQUALS(1, db->variableList().size() - 1);
ASSERT_EQUALS(true, db->getVariableFromVarId(1) != nullptr);
ASSERT_EQUALS("pFun", db->getVariableFromVarId(1)->name());
ASSERT_EQUALS("", errout_str());
}
void hasSubClassConstructor() {
GET_SYMBOL_DB("class Foo { class Sub; }; class Foo::Sub { Sub() {} };");
ASSERT(db != nullptr);
bool seen_something = false;
for (const Scope & scope : db->scopeList) {
for (std::list::const_iterator func = scope.functionList.cbegin(); func != scope.functionList.cend(); ++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);
}
{
GET_SYMBOL_DB("void f() { extern void f(); }");
ASSERT(db && db->scopeList.size() == 2);
const Function* f = findFunctionByName("f", &db->scopeList.back());
ASSERT(f && f->type == Function::eFunction);
}
}
void functionDeclarationTemplate() {
GET_SYMBOL_DB("std::map foo() {}");
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2 && findFunctionByName("foo", &db->scopeList.back()));
const Scope *scope = &db->scopeList.front();
ASSERT(scope && scope->functionList.size() == 1);
const Function *foo = &scope->functionList.front();
ASSERT(foo && foo->token->str() == "foo");
ASSERT(foo && foo->hasBody());
}
void functionDeclarations() {
GET_SYMBOL_DB("void foo();\nvoid foo();\nint foo(int i);\nvoid foo() {}");
// 2 scopes: Global and Function
ASSERT(db && db->scopeList.size() == 2 && findFunctionByName("foo", &db->scopeList.back()));
const Scope *scope = &db->scopeList.front();
ASSERT(scope && scope->functionList.size() == 2);
const Function *foo = &scope->functionList.front();
const Function *foo_int = &scope->functionList.back();
ASSERT(foo && foo->token->str() == "foo");
ASSERT(foo && foo->hasBody());
ASSERT(foo && foo->token->strAt(2) == ")");
ASSERT(foo_int && !foo_int->token);
ASSERT(foo_int && foo_int->tokenDef->str() == "foo");
ASSERT(foo_int && !foo_int->hasBody());
ASSERT(foo_int && foo_int->tokenDef->strAt(2) == "int");
ASSERT(&foo_int->argumentList.front() == db->getVariableFromVarId(1));
}
void functionDeclarations2() {
GET_SYMBOL_DB("std::array foo(int x);");
// 1 scopes: Global
ASSERT(db && db->scopeList.size() == 1);
const Scope *scope = &db->scopeList.front();
ASSERT(scope && scope->functionList.size() == 1);
const Function *foo = &scope->functionList.front();
ASSERT(foo);
ASSERT(foo->tokenDef->str() == "foo");
ASSERT(!foo->hasBody());
const Token*parenthesis = foo->tokenDef->next();
ASSERT(parenthesis->str() == "(" && parenthesis->previous()->str() == "foo");
ASSERT(parenthesis->valueType()->type == ValueType::Type::CONTAINER);
}
void constexprFunction() {
GET_SYMBOL_DB("constexpr int foo();");
// 1 scopes: Global
ASSERT(db && db->scopeList.size() == 1);
const Scope *scope = &db->scopeList.front();
ASSERT(scope && scope->functionList.size() == 1);
const Function *foo = &scope->functionList.front();
ASSERT(foo);
ASSERT(foo->tokenDef->str() == "foo");
ASSERT(!foo->hasBody());
ASSERT(foo->isConstexpr());
}
void constructorInitialization() {
GET_SYMBOL_DB("std::string logfile;\n"
"std::ofstream log(logfile.c_str(), std::ios::out);");
// 1 scope: Global
ASSERT(db && db->scopeList.size() == 1);
// No functions
ASSERT(db->scopeList.front().functionList.empty());
}
void memberFunctionOfUnknownClassMacro1() {
GET_SYMBOL_DB("class ScVbaFormatCondition { OUString getServiceImplName() SAL_OVERRIDE; };\n"
"void ScVbaValidation::getFormula1() {\n"
" sal_uInt16 nFlags = 0;\n"
" if (pDocSh && !getCellRangesForAddress(nFlags)) ;\n"
"}");
ASSERT(db && errout_str().empty());
const Scope *scope = db->findScopeByName("getFormula1");
ASSERT(scope != nullptr);
ASSERT(scope && scope->nestedIn == &db->scopeList.front());
}
void memberFunctionOfUnknownClassMacro2() {
GET_SYMBOL_DB("class ScVbaFormatCondition { OUString getServiceImplName() SAL_OVERRIDE {} };\n"
"void getFormula1() {\n"
" sal_uInt16 nFlags = 0;\n"
" if (pDocSh && !getCellRangesForAddress(nFlags)) ;\n"
"}");
ASSERT(db && errout_str().empty());
const Scope *scope = db->findScopeByName("getFormula1");
ASSERT(scope != nullptr);
ASSERT(scope && scope->nestedIn == &db->scopeList.front());
scope = db->findScopeByName("getServiceImplName");
ASSERT(scope != nullptr);
ASSERT(scope && scope->nestedIn && scope->nestedIn->className == "ScVbaFormatCondition");
}
void memberFunctionOfUnknownClassMacro3() {
GET_SYMBOL_DB("class ScVbaFormatCondition { OUString getServiceImplName() THROW(whatever); };\n"
"void ScVbaValidation::getFormula1() {\n"
" sal_uInt16 nFlags = 0;\n"
" if (pDocSh && !getCellRangesForAddress(nFlags)) ;\n"
"}");
ASSERT(db && errout_str().empty());
const Scope *scope = db->findScopeByName("getFormula1");
ASSERT(scope != nullptr);
ASSERT(scope && scope->nestedIn == &db->scopeList.front());
}
void functionLinkage() {
GET_SYMBOL_DB("static void f1() { }\n"
"void f2();\n"
"extern void f3();\n"
"void f4();\n"
"extern void f5() { };\n"
"void f6() { }");
ASSERT(db && errout_str().empty());
const Token *f = Token::findsimplematch(tokenizer.tokens(), "f1");
ASSERT(f && f->function() && f->function()->isStaticLocal() && f->function()->retDef->str() == "void");
f = Token::findsimplematch(tokenizer.tokens(), "f2");
ASSERT(f && f->function() && !f->function()->isStaticLocal() && f->function()->retDef->str() == "void");
f = Token::findsimplematch(tokenizer.tokens(), "f3");
ASSERT(f && f->function() && f->function()->isExtern() && f->function()->retDef->str() == "void");
f = Token::findsimplematch(tokenizer.tokens(), "f4");
ASSERT(f && f->function() && !f->function()->isExtern() && f->function()->retDef->str() == "void");
f = Token::findsimplematch(tokenizer.tokens(), "f5");
ASSERT(f && f->function() && f->function()->isExtern() && f->function()->retDef->str() == "void");
f = Token::findsimplematch(tokenizer.tokens(), "f6");
ASSERT(f && f->function() && !f->function()->isExtern() && f->function()->retDef->str() == "void");
}
void externalFunctionsInsideAFunction() {
GET_SYMBOL_DB("void foo( void )\n"
"{\n"
" extern void bar( void );\n"
" bar();\n"
"}\n");
ASSERT(db && errout_str().empty());
const Token *f = Token::findsimplematch(tokenizer.tokens(), "bar");
ASSERT(f && f->function() && f->function()->isExtern() && f == f->function()->tokenDef && f->function()->retDef->str() == "void");
const Token *call = Token::findsimplematch(f->next(), "bar");
ASSERT(call && call->function() == f->function());
}
void namespacedFunctionInsideExternBlock() {
// Should not crash
GET_SYMBOL_DB("namespace N {\n"
" void f();\n"
"}\n"
"extern \"C\" {\n"
" void f() {\n"
" N::f();\n"
" }\n"
"}\n");
ASSERT(db && errout_str().empty());
}
void classWithFriend() {
GET_SYMBOL_DB("class Foo {}; class Bar1 { friend class Foo; }; class Bar2 { friend Foo; };");
// 3 scopes: Global, 3 classes
ASSERT(db && db->scopeList.size() == 4);
const Scope* foo = db->findScopeByName("Foo");
ASSERT(foo != nullptr);
const Scope* bar1 = db->findScopeByName("Bar1");
ASSERT(bar1 != nullptr);
const Scope* bar2 = db->findScopeByName("Bar2");
ASSERT(bar2 != nullptr);
ASSERT(bar1->definedType->friendList.size() == 1 && bar1->definedType->friendList.front().nameEnd->str() == "Foo" && bar1->definedType->friendList.front().type == foo->definedType);
ASSERT(bar2->definedType->friendList.size() == 1 && bar2->definedType->friendList.front().nameEnd->str() == "Foo" && bar2->definedType->friendList.front().type == foo->definedType);
}
void parseFunctionCorrect() {
// ticket 3188 - "if" statement parsed as function
GET_SYMBOL_DB("void func(i) int i; { if (i == 1) return; }");
ASSERT(db != nullptr);
// 3 scopes: Global, function, if
ASSERT_EQUALS(3, db->scopeList.size());
ASSERT(findFunctionByName("func", &db->scopeList.back()) != nullptr);
ASSERT(findFunctionByName("if", &db->scopeList.back()) == nullptr);
}
void parseFunctionDeclarationCorrect() {
GET_SYMBOL_DB("void func();\n"
"int bar() {}\n"
"void func() {}");
ASSERT_EQUALS(3, db->findScopeByName("func")->bodyStart->linenr());
}
void Cpp11InitInInitList() {
GET_SYMBOL_DB("class Foo {\n"
" std::vector bar;\n"
" Foo() : bar({\"a\", \"b\"})\n"
" {}\n"
"};");
ASSERT_EQUALS(4, db->scopeList.front().nestedList.front()->nestedList.front()->bodyStart->linenr());
}
void hasGlobalVariables1() {
GET_SYMBOL_DB("int i;");
ASSERT(db && db->scopeList.size() == 1);
const std::list::const_iterator it = db->scopeList.cbegin();
ASSERT(it->varlist.size() == 1);
const std::list::const_iterator var = it->varlist.cbegin();
ASSERT(var->name() == "i");
ASSERT(var->typeStartToken()->str() == "int");
}
void hasGlobalVariables2() {
GET_SYMBOL_DB("int array[2][2];");
ASSERT(db && db->scopeList.size() == 1);
const std::list::const_iterator it = db->scopeList.cbegin();
ASSERT(it->varlist.size() == 1);
const std::list::const_iterator var = it->varlist.cbegin();
ASSERT(var->name() == "array");
ASSERT(var->typeStartToken()->str() == "int");
}
void hasGlobalVariables3() {
GET_SYMBOL_DB("int array[2][2] = { { 0, 0 }, { 0, 0 } };");
ASSERT(db && db->scopeList.size() == 1);
const std::list::const_iterator it = db->scopeList.cbegin();
ASSERT(it->varlist.size() == 1);
const std::list::const_iterator var = it->varlist.cbegin();
ASSERT(var->name() == "array");
ASSERT(var->typeStartToken()->str() == "int");
}
void checkTypeStartEndToken1() {
GET_SYMBOL_DB("static std::string i;\n"
"static const std::string j;\n"
"const std::string* k;\n"
"const char m[];\n"
"void f(const char* const l) {}");
ASSERT(db && db->variableList().size() == 6 && db->getVariableFromVarId(1) && db->getVariableFromVarId(2) && db->getVariableFromVarId(3) && db->getVariableFromVarId(4) && db->getVariableFromVarId(5));
ASSERT_EQUALS("std", db->getVariableFromVarId(1)->typeStartToken()->str());
ASSERT_EQUALS("std", db->getVariableFromVarId(2)->typeStartToken()->str());
ASSERT_EQUALS("std", db->getVariableFromVarId(3)->typeStartToken()->str());
ASSERT_EQUALS("char", db->getVariableFromVarId(4)->typeStartToken()->str());
ASSERT_EQUALS("char", db->getVariableFromVarId(5)->typeStartToken()->str());
ASSERT_EQUALS("string", db->getVariableFromVarId(1)->typeEndToken()->str());
ASSERT_EQUALS("string", db->getVariableFromVarId(2)->typeEndToken()->str());
ASSERT_EQUALS("*", db->getVariableFromVarId(3)->typeEndToken()->str());
ASSERT_EQUALS("char", db->getVariableFromVarId(4)->typeEndToken()->str());
ASSERT_EQUALS("*", db->getVariableFromVarId(5)->typeEndToken()->str());
}
void checkTypeStartEndToken2() {
GET_SYMBOL_DB("class CodeGenerator {\n"
" DiagnosticsEngine Diags;\n"
"public:\n"
" void Initialize() {\n"
" Builder.reset(Diags);\n"
" }\n"
"\n"
" void HandleTagDeclRequiredDefinition() LLVM_OVERRIDE {\n"
" if (Diags.hasErrorOccurred())\n"
" return;\n"
" }\n"
"};");
ASSERT_EQUALS("DiagnosticsEngine", db->getVariableFromVarId(1)->typeStartToken()->str());
}
void checkTypeStartEndToken3() {
GET_SYMBOL_DB("void f(const char) {}");
ASSERT(db && db->functionScopes.size()==1U);
const Function * const f = db->functionScopes.front()->function;
ASSERT_EQUALS(1U, f->argCount());
ASSERT_EQUALS(0U, f->initializedArgCount());
ASSERT_EQUALS(1U, f->minArgCount());
const Variable * const arg1 = f->getArgumentVar(0);
ASSERT_EQUALS("char", arg1->typeStartToken()->str());
ASSERT_EQUALS("char", arg1->typeEndToken()->str());
}
#define check(...) check_(__FILE__, __LINE__, __VA_ARGS__)
void check_(const char* file, int line, const char code[], bool debug = true, bool cpp = true, const Settings* pSettings = nullptr) {
// Check..
const Settings settings = settingsBuilder(pSettings ? *pSettings : settings1).debugwarnings(debug).build();
// Tokenize..
SimpleTokenizer tokenizer(settings, *this);
ASSERT_LOC(tokenizer.tokenize(code, cpp), file, line);
// force symbol database creation
tokenizer.createSymbolDatabase();
}
void functionArgs1() {
{
GET_SYMBOL_DB("void f(std::vector, const std::vector & v) { }");
ASSERT_EQUALS(1+1, db->variableList().size());
const Variable* v = db->getVariableFromVarId(1);
ASSERT(v && v->isReference() && v->isConst() && v->isArgument());
const Scope* f = db->findScopeByName("f");
ASSERT(f && f->type == Scope::eFunction && f->function);
ASSERT(f->function->argumentList.size() == 2 && f->function->argumentList.front().index() == 0 && f->function->argumentList.front().name().empty() && f->function->argumentList.back().index() == 1);
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB("void g(std::map > m) { }");
ASSERT_EQUALS(1+1, db->variableList().size());
const Variable* m = db->getVariableFromVarId(1);
ASSERT(m && !m->isReference() && !m->isConst() && m->isArgument() && m->isClass());
const Scope* g = db->findScopeByName("g");
ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().index() == 0);
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB("void g(std::map m = std::map()) { }");
const Scope* g = db->findScopeByName("g");
ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().index() == 0 && g->function->initializedArgCount() == 1);
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB("void g(int = 0) { }");
const Scope* g = db->findScopeByName("g");
ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().hasDefault());
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB("void g(int*) { }"); // unnamed pointer argument (#8052)
const Scope* g = db->findScopeByName("g");
ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().nameToken() == nullptr && g->function->argumentList.front().isPointer());
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB("void g(int* const) { }"); // 'const' is not the name of the variable - #5882
const Scope* g = db->findScopeByName("g");
ASSERT(g && g->type == Scope::eFunction && g->function && g->function->argumentList.size() == 1 && g->function->argumentList.front().nameToken() == nullptr);
ASSERT_EQUALS("", errout_str());
}
}
void functionArgs2() {
GET_SYMBOL_DB("void f(int a[][4]) { }");
const Variable *a = db->getVariableFromVarId(1);
ASSERT_EQUALS("a", a->nameToken()->str());
ASSERT_EQUALS(2UL, a->dimensions().size());
ASSERT_EQUALS(0UL, a->dimension(0));
ASSERT_EQUALS(false, a->dimensions()[0].known);
ASSERT_EQUALS(4UL, a->dimension(1));
ASSERT_EQUALS(true, a->dimensions()[1].known);
}
void functionArgs4() {
GET_SYMBOL_DB("void f1(char [10], struct foo [10]);");
ASSERT_EQUALS(true, db->scopeList.front().functionList.size() == 1UL);
const Function *func = &db->scopeList.front().functionList.front();
ASSERT_EQUALS(true, func && func->argumentList.size() == 2UL);
const Variable *first = &func->argumentList.front();
ASSERT_EQUALS(0UL, first->name().size());
ASSERT_EQUALS(1UL, first->dimensions().size());
ASSERT_EQUALS(10UL, first->dimension(0));
const Variable *second = &func->argumentList.back();
ASSERT_EQUALS(0UL, second->name().size());
ASSERT_EQUALS(1UL, second->dimensions().size());
ASSERT_EQUALS(10UL, second->dimension(0));
}
void functionArgs5() { // #7650
GET_SYMBOL_DB("class ABC {};\n"
"class Y {\n"
" enum ABC {A,B,C};\n"
" void f(enum ABC abc) {}\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( enum");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->isEnumType());
}
void functionArgs6() { // #7651
GET_SYMBOL_DB("class ABC {};\n"
"class Y {\n"
" enum ABC {A,B,C};\n"
" void f(ABC abc) {}\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( ABC");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->isEnumType());
}
void functionArgs7() { // #7652
{
GET_SYMBOL_DB("struct AB { int a; int b; };\n"
"int foo(struct AB *ab);\n"
"void bar() {\n"
" struct AB ab;\n"
" foo(&ab);\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->classDef->linenr() == 1);
}
{
GET_SYMBOL_DB("struct AB { int a; int b; };\n"
"int foo(AB *ab);\n"
"void bar() {\n"
" struct AB ab;\n"
" foo(&ab);\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->classDef->linenr() == 1);
}
{
GET_SYMBOL_DB("struct AB { int a; int b; };\n"
"int foo(struct AB *ab);\n"
"void bar() {\n"
" AB ab;\n"
" foo(&ab);\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->classDef->linenr() == 1);
}
{
GET_SYMBOL_DB("struct AB { int a; int b; };\n"
"int foo(AB *ab);\n"
"void bar() {\n"
" AB ab;\n"
" foo(&ab);\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( & ab");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 2 && func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->classDef->linenr() == 1);
}
}
void functionArgs8() { // #7653
GET_SYMBOL_DB("struct A { int i; };\n"
"struct B { double d; };\n"
"int foo(struct A a);\n"
"double foo(struct B b);\n"
"void bar() {\n"
" struct B b;\n"
" foo(b);\n"
"}");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo ( b");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->tokenDef->linenr() == 4 && func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->isStructType());
}
void functionArgs9() { // #7657
GET_SYMBOL_DB("struct A {\n"
" struct B {\n"
" enum C { };\n"
" };\n"
"};\n"
"void foo(A::B::C c) { }");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo (");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->isEnumType());
}
void functionArgs10() {
GET_SYMBOL_DB("class Fred {\n"
"public:\n"
" Fred(Whitespace = PRESERVE_WHITESPACE);\n"
"};\n"
"Fred::Fred(Whitespace whitespace) { }");
ASSERT_EQUALS(true, db != nullptr);
ASSERT_EQUALS(3, db->scopeList.size());
std::list::const_iterator scope = db->scopeList.cbegin();
++scope;
ASSERT_EQUALS((unsigned int)Scope::eClass, (unsigned int)scope->type);
ASSERT_EQUALS(1, scope->functionList.size());
ASSERT(scope->functionList.cbegin()->functionScope != nullptr);
const Scope * functionScope = scope->functionList.cbegin()->functionScope;
++scope;
ASSERT(functionScope == &*scope);
}
void functionArgs11() {
GET_SYMBOL_DB("class Fred {\n"
"public:\n"
" void foo(char a[16]);\n"
"};\n"
"void Fred::foo(char b[16]) { }");
ASSERT_EQUALS(true, db != nullptr);
ASSERT_EQUALS(3, db->scopeList.size());
std::list::const_iterator scope = db->scopeList.cbegin();
++scope;
ASSERT_EQUALS((unsigned int)Scope::eClass, (unsigned int)scope->type);
ASSERT_EQUALS(1, scope->functionList.size());
ASSERT(scope->functionList.cbegin()->functionScope != nullptr);
const Scope * functionScope = scope->functionList.cbegin()->functionScope;
++scope;
ASSERT(functionScope == &*scope);
}
void functionArgs12() { // #7661
GET_SYMBOL_DB("struct A {\n"
" enum E { };\n"
" int a[10];\n"
"};\n"
"struct B : public A {\n"
" void foo(B::E e) { }\n"
"};");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "foo (");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->isEnumType());
}
void functionArgs13() { // #7697
GET_SYMBOL_DB("struct A {\n"
" enum E { };\n"
" struct S { };\n"
"};\n"
"struct B : public A {\n"
" B(E e);\n"
" B(S s);\n"
"};\n"
"B::B(A::E e) { }\n"
"B::B(A::S s) { }");
ASSERT_EQUALS(true, db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "B ( A :: E");
ASSERT_EQUALS(true, f && f->function());
const Function *func = f->function();
ASSERT_EQUALS(true, func->argumentList.size() == 1 && func->argumentList.front().type());
const Type * type = func->argumentList.front().type();
ASSERT_EQUALS(true, type->isEnumType() && type->name() == "E");
f = Token::findsimplematch(tokenizer.tokens(), "B ( A :: S");
ASSERT_EQUALS(true, f && f->function());
const Function *func2 = f->function();
ASSERT_EQUALS(true, func2->argumentList.size() == 1 && func2->argumentList.front().type());
const Type * type2 = func2->argumentList.front().type();
ASSERT_EQUALS(true, type2->isStructType() && type2->name() == "S");
}
void functionArgs14() { // #7697
GET_SYMBOL_DB("void f(int (&a)[10], int (&b)[10]);");
(void)db;
const Function *func = tokenizer.tokens()->next()->function();
ASSERT_EQUALS(true, func != nullptr);
ASSERT_EQUALS(2, func ? func->argCount() : 0);
ASSERT_EQUALS(0, func ? func->initializedArgCount() : 1);
ASSERT_EQUALS(2, func ? func->minArgCount() : 0);
}
void functionArgs15() { // #7159
const char code[] =
"class Class {\n"
" void Method(\n"
" char c = []()->char {\n"
" int d = rand();\n"// the '=' on this line used to reproduce the defect
" return d;\n"
" }()\n"
" );\n"
"};\n";
GET_SYMBOL_DB(code);
ASSERT(db);
ASSERT_EQUALS(2, db->scopeList.size());
const Scope& classScope = db->scopeList.back();
ASSERT_EQUALS(Scope::eClass, classScope.type);
ASSERT_EQUALS("Class", classScope.className);
ASSERT_EQUALS(1, classScope.functionList.size());
const Function& method = classScope.functionList.front();
ASSERT_EQUALS("Method", method.name());
ASSERT_EQUALS(1, method.argCount());
ASSERT_EQUALS(1, method.initializedArgCount());
ASSERT_EQUALS(0, method.minArgCount());
}
void functionArgs16() { // #9591
const char code[] =
"struct A { int var; };\n"
"void foo(int x, decltype(A::var) *&p) {}";
GET_SYMBOL_DB(code);
ASSERT(db);
const Scope *scope = db->functionScopes.front();
const Function *func = scope->function;
ASSERT_EQUALS(2, func->argCount());
const Variable *arg2 = func->getArgumentVar(1);
ASSERT_EQUALS("p", arg2->name());
ASSERT(arg2->isPointer());
ASSERT(arg2->isReference());
}
void functionArgs17() {
const char code[] = "void f(int (*fp)(), int x, int y) {}";
GET_SYMBOL_DB(code);
ASSERT(db != nullptr);
const Scope *scope = db->functionScopes.front();
const Function *func = scope->function;
ASSERT_EQUALS(3, func->argCount());
}
void functionArgs18() {
const char code[] = "void f(int (*param1)[2], int param2) {}";
GET_SYMBOL_DB(code);
ASSERT(db != nullptr);
const Scope *scope = db->functionScopes.front();
const Function *func = scope->function;
ASSERT_EQUALS(2, func->argCount());
}
void functionArgs19() {
const char code[] = "void f(int (*fp)(int), int x, int y) {}";
GET_SYMBOL_DB(code);
ASSERT(db != nullptr);
const Scope *scope = db->functionScopes.front();
const Function *func = scope->function;
ASSERT_EQUALS(3, func->argCount());
}
void functionArgs20() {
{
const char code[] = "void f(void *(*g)(void *) = [](void *p) { return p; }) {}"; // #11769
GET_SYMBOL_DB(code);
ASSERT(db != nullptr);
const Scope *scope = db->functionScopes.front();
const Function *func = scope->function;
ASSERT_EQUALS(1, func->argCount());
const Variable* arg = func->getArgumentVar(0);
TODO_ASSERT(arg->hasDefault());
}
{
const char code[] = "void f() { auto g = [&](const std::function& h = [](int i) -> int { return i; }) {}; }"; // #12338
GET_SYMBOL_DB(code);
ASSERT(db != nullptr);
ASSERT_EQUALS(3, db->scopeList.size());
ASSERT_EQUALS(Scope::ScopeType::eLambda, db->scopeList.back().type);
}
{
const char code[] = "void f() {\n"
" auto g = [&](const std::function&(const std::vector&)>& h = [](const std::vector& v) -> const std::vector& { return v; }) {};\n"
"}\n";
GET_SYMBOL_DB(code);
ASSERT(db != nullptr);
ASSERT_EQUALS(3, db->scopeList.size());
ASSERT_EQUALS(Scope::ScopeType::eLambda, db->scopeList.back().type);
}
{
const char code[] = "void f() {\n"
" auto g = [&](const std::function& h = [](int i) -> decltype(0) { return i; }) {};\n"
"}\n";
GET_SYMBOL_DB(code);
ASSERT(db != nullptr);
ASSERT_EQUALS(3, db->scopeList.size());
ASSERT_EQUALS(Scope::ScopeType::eLambda, db->scopeList.back().type);
}
}
void functionArgs21() {
const char code[] = "void f(std::vector::size_type) {}\n" // #11408
"template\n"
"struct S { using t = int; };\n"
"template\n"
"S operator+(const S&lhs, typename S::t) { return lhs; }";
GET_SYMBOL_DB(code);
ASSERT(db != nullptr);
auto it = db->functionScopes.begin();
const Function *func = (*it)->function;
ASSERT_EQUALS("f", func->name());
ASSERT_EQUALS(1, func->argCount());
const Variable* arg = func->getArgumentVar(0);
ASSERT_EQUALS("", arg->name());
++it;
func = (*it)->function;
ASSERT_EQUALS("operator+", func->name());
ASSERT_EQUALS(2, func->argCount());
arg = func->getArgumentVar(1);
ASSERT_EQUALS("", arg->name());
}
void functionImplicitlyVirtual() {
GET_SYMBOL_DB("class base { virtual void f(); };\n"
"class derived : base { void f(); };\n"
"void derived::f() {}");
ASSERT(db != nullptr);
ASSERT_EQUALS(4, db->scopeList.size());
const Function *function = db->scopeList.back().function;
ASSERT_EQUALS(true, function && function->isImplicitlyVirtual(false));
}
void functionGetOverridden() {
GET_SYMBOL_DB("struct B { virtual void f(); };\n"
"struct D : B {\n"
"public:\n"
" void f() override;\n"
"};\n"
"struct D2 : D { void f() override {} };\n");
ASSERT(db != nullptr);
ASSERT_EQUALS(5, db->scopeList.size());
const Function *func = db->scopeList.back().function;
ASSERT(func && func->nestedIn);
ASSERT_EQUALS("D2", func->nestedIn->className);
bool foundAllBaseClasses{};
const Function* baseFunc = func->getOverriddenFunction(&foundAllBaseClasses);
ASSERT(baseFunc && baseFunc->nestedIn && foundAllBaseClasses);
ASSERT_EQUALS("D", baseFunc->nestedIn->className);
}
void functionIsInlineKeyword() {
GET_SYMBOL_DB("inline void fs() {}");
(void)db;
const Function *func = db->scopeList.back().function;
ASSERT(func);
ASSERT(func->isInlineKeyword());
}
void functionStatic() {
GET_SYMBOL_DB("static void fs() { }");
(void)db;
const Function *func = db->scopeList.back().function;
ASSERT(func);
ASSERT(func->isStatic());
}
void functionReturnsReference() {
GET_SYMBOL_DB("Fred::Reference foo();");
ASSERT_EQUALS(1, db->scopeList.back().functionList.size());
const Function &func = *db->scopeList.back().functionList.cbegin();
ASSERT(!Function::returnsReference(&func, false));
ASSERT(Function::returnsReference(&func, true));
}
void namespaces1() {
GET_SYMBOL_DB("namespace fred {\n"
" namespace barney {\n"
" class X { X(int); };\n"
" }\n"
"}\n"
"namespace barney { X::X(int) { } }");
// Locate the scope for the class..
auto it = std::find_if(db->scopeList.cbegin(), db->scopeList.cend(), [](const Scope& s) {
return s.isClassOrStruct();
});
const Scope *scope = (it == db->scopeList.end()) ? nullptr : &*it;
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..
auto it = std::find_if(db->scopeList.cbegin(), db->scopeList.cend(), [](const Scope& s) {
return s.isClassOrStruct();
});
const Scope* scope = (it == db->scopeList.end()) ? nullptr : &*it;
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 needInitialization() {
{
GET_SYMBOL_DB_DBG("template \n" // #10259
"struct A {\n"
" using type = T;\n"
" type t_;\n"
"};\n");
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB_DBG("class T;\n" // #12367
"struct S {\n"
" S(T& t);\n"
" T& _t;\n"
"};\n");
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB_DBG("struct S {\n" // #12395
" static S s;\n"
"};\n");
ASSERT_EQUALS("", errout_str());
const Variable* const s = db->getVariableFromVarId(1);
ASSERT(s->scope()->definedType->needInitialization == Type::NeedInitialization::False);
}
}
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:\n"
"foo() { }\n"
"};");
ASSERT_EQUALS("", errout_str());
check("class foo {\n"
"class bar;\n"
"foo() { }\n"
"};");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase3() {
check("typedef void (func_type)();\n"
"struct A {\n"
" friend func_type f : 2;\n"
"};");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase4() {
check("static void function_declaration_before(void) __attribute__((__used__));\n"
"static void function_declaration_before(void) {}\n"
"static void function_declaration_after(void) {}\n"
"static void function_declaration_after(void) __attribute__((__used__));");
ASSERT_EQUALS("", errout_str());
check("main(int argc, char *argv[]) { }", true, false);
ASSERT_EQUALS("", errout_str());
const Settings s = settingsBuilder(settings1).severity(Severity::portability).build();
check("main(int argc, char *argv[]) { }", false, false, &s);
ASSERT_EQUALS("[test.c:1]: (portability) Omitted return type of function 'main' defaults to int, this is not supported by ISO C99 and later standards.\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"
"[test.cpp:1]: (debug) Executable scope 'testing' with unknown function.\n", // duplicate
errout_str());
}
void symboldatabase5() {
// ticket #2178 - segmentation fault
ASSERT_THROW_INTERNAL(check("int CL_INLINE_DECL(integer_decode_float) (int x) {\n"
" return (sign ? cl_I() : 0);\n"
"}"), UNKNOWN_MACRO);
}
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_INTERNAL(check("struct B : A\n"), SYNTAX);
}
void symboldatabase17() {
// ticket #2657 - segmentation fault
check("{return f(){}}");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase19() {
// ticket #2991 - segmentation fault
check("::y(){x}");
ASSERT_EQUALS("[test.cpp:1]: (debug) Executable scope 'y' with unknown function.\n"
"[test.cpp:1]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable x\n"
"[test.cpp:1]: (debug) Executable scope 'y' with unknown function.\n", // duplicate
errout_str());
}
void symboldatabase20() {
// ticket #3013 - segmentation fault
ASSERT_THROW_INTERNAL(check("struct x : virtual y\n"), SYNTAX);
}
void symboldatabase21() {
check("class Fred {\n"
" class Foo { };\n"
" void func() const;\n"
"};\n"
"Fred::func() const {\n"
" Foo foo;\n"
"}");
ASSERT_EQUALS("", errout_str());
}
// ticket 3437 (segmentation fault)
void symboldatabase22() {
check("template struct A {};\n"
"A a;");
ASSERT_EQUALS("", errout_str());
}
// ticket 3435 (std::vector)
void symboldatabase23() {
GET_SYMBOL_DB("class A { std::vector ints; };");
ASSERT_EQUALS(2U, db->scopeList.size());
const Scope &scope = db->scopeList.back();
ASSERT_EQUALS(1U, scope.varlist.size());
const Variable &var = scope.varlist.front();
ASSERT_EQUALS(std::string("ints"), var.name());
ASSERT_EQUALS(true, var.isClass());
}
// ticket 3508 (constructor, destructor)
void symboldatabase24() {
GET_SYMBOL_DB("struct Fred {\n"
" ~Fred();\n"
" Fred();\n"
"};\n"
"Fred::Fred() { }\n"
"Fred::~Fred() { }");
// Global scope, Fred, Fred::Fred, Fred::~Fred
ASSERT_EQUALS(4U, db->scopeList.size());
// Find the scope for the Fred struct..
auto it = std::find_if(db->scopeList.cbegin(), db->scopeList.cend(), [&](const Scope& scope) {
return scope.isClassOrStruct() && scope.className == "Fred";
});
const Scope* fredScope = (it == db->scopeList.end()) ? nullptr : &*it;
ASSERT(fredScope != nullptr);
// The struct Fred has two functions, a constructor and a destructor
ASSERT_EQUALS(2U, fredScope->functionList.size());
// Get linenumbers where the bodies for the constructor and destructor are..
unsigned int constructor = 0;
unsigned int destructor = 0;
for (const Function& f : fredScope->functionList) {
if (f.type == Function::eConstructor)
constructor = f.token->linenr(); // line number for constructor body
if (f.type == Function::eDestructor)
destructor = f.token->linenr(); // line number for destructor body
}
// The body for the constructor is located at line 5..
ASSERT_EQUALS(5U, constructor);
// The body for the destructor is located at line 6..
ASSERT_EQUALS(6U, destructor);
}
// ticket #3561 (throw C++)
void symboldatabase25() {
const char str[] = "int main() {\n"
" foo bar;\n"
" throw bar;\n"
"}";
GET_SYMBOL_DB(str);
ASSERT_EQUALS("", errout_str());
ASSERT(db && db->variableList().size() == 2); // index 0 + 1 variable
}
// ticket #3561 (throw C)
void symboldatabase26() {
const char str[] = "int main() {\n"
" throw bar;\n"
"}";
GET_SYMBOL_DB_C(str);
ASSERT_EQUALS("", errout_str());
ASSERT(db && db->variableList().size() == 2); // index 0 + 1 variable
}
// ticket #3543 (segmentation fault)
void symboldatabase27() {
check("class C : public B1\n"
"{\n"
" B1()\n"
" {} C(int) : B1() class\n"
"};");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase28() {
GET_SYMBOL_DB("struct S {};\n"
"void foo(struct S s) {}");
ASSERT(db && db->getVariableFromVarId(1) && db->getVariableFromVarId(1)->typeScope() && db->getVariableFromVarId(1)->typeScope()->className == "S");
}
// ticket #4442 (segmentation fault)
void symboldatabase29() {
check("struct B : A {\n"
" B() : A {}\n"
"};");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase30() {
GET_SYMBOL_DB("struct A { void foo(const int a); };\n"
"void A::foo(int a) { }");
ASSERT(db && db->functionScopes.size() == 1 && db->functionScopes[0]->functionOf);
}
void symboldatabase31() {
GET_SYMBOL_DB("class Foo;\n"
"class Bar;\n"
"class Sub;\n"
"class Foo { class Sub; };\n"
"class Bar { class Sub; };\n"
"class Bar::Sub {\n"
" int b;\n"
"public:\n"
" Sub() { }\n"
" Sub(int);\n"
"};\n"
"Bar::Sub::Sub(int) { };\n"
"class ::Foo::Sub {\n"
" int f;\n"
"public:\n"
" ~Sub();\n"
" Sub();\n"
"};\n"
"::Foo::Sub::~Sub() { }\n"
"::Foo::Sub::Sub() { }\n"
"class Foo;\n"
"class Bar;\n"
"class Sub;");
ASSERT(db && db->typeList.size() == 5);
std::list::const_iterator i = db->typeList.cbegin();
const Type* Foo = &(*i++);
const Type* Bar = &(*i++);
const Type* Sub = &(*i++);
const Type* Foo_Sub = &(*i++);
const Type* Bar_Sub = &(*i);
ASSERT(Foo && Foo->classDef && Foo->classScope && Foo->enclosingScope && Foo->name() == "Foo");
ASSERT(Bar && Bar->classDef && Bar->classScope && Bar->enclosingScope && Bar->name() == "Bar");
ASSERT(Sub && Sub->classDef && !Sub->classScope && Sub->enclosingScope && Sub->name() == "Sub");
ASSERT(Foo_Sub && Foo_Sub->classDef && Foo_Sub->classScope && Foo_Sub->enclosingScope == Foo->classScope && Foo_Sub->name() == "Sub");
ASSERT(Bar_Sub && Bar_Sub->classDef && Bar_Sub->classScope && Bar_Sub->enclosingScope == Bar->classScope && Bar_Sub->name() == "Sub");
ASSERT(Foo_Sub && Foo_Sub->classScope && Foo_Sub->classScope->numConstructors == 1 && Foo_Sub->classScope->className == "Sub");
ASSERT(Bar_Sub && Bar_Sub->classScope && Bar_Sub->classScope->numConstructors == 2 && Bar_Sub->classScope->className == "Sub");
}
void symboldatabase32() {
GET_SYMBOL_DB("struct Base {\n"
" void foo() {}\n"
"};\n"
"class Deri : Base {\n"
"};");
ASSERT(db && db->findScopeByName("Deri") && db->findScopeByName("Deri")->definedType->getFunction("foo"));
}
void symboldatabase33() { // ticket #4682
GET_SYMBOL_DB("static struct A::B s;\n"
"static struct A::B t = { 0 };\n"
"static struct A::B u(0);\n"
"static struct A::B v{0};\n"
"static struct A::B w({0});\n"
"void foo() { }");
ASSERT(db && db->functionScopes.size() == 1);
}
void symboldatabase34() { // ticket #4694
check("typedef _Atomic(int(A::*)) atomic_mem_ptr_to_int;\n"
"typedef _Atomic(int)&atomic_int_ref;\n"
"struct S {\n"
" _Atomic union { int n; };\n"
"};");
ASSERT_EQUALS("[test.cpp:2]: (debug) Failed to parse 'typedef _Atomic ( int ) & atomic_int_ref ;'. The checking continues anyway.\n", errout_str());
}
void symboldatabase35() { // ticket #4806 and #4841
check("class FragmentQueue : public CL_NS(util)::PriorityQueue >\n"
"{};");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase36() { // ticket #4892
check("void struct ( ) { if ( 1 ) } int main ( ) { }");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase37() {
GET_SYMBOL_DB("class Fred {\n"
"public:\n"
" struct Wilma { };\n"
" struct Barney {\n"
" bool operator == (const struct Barney & b) const { return true; }\n"
" bool operator == (const struct Wilma & w) const { return true; }\n"
" };\n"
" Fred(const struct Barney & b) { barney = b; }\n"
"private:\n"
" struct Barney barney;\n"
"};");
ASSERT(db && db->typeList.size() == 3);
std::list::const_iterator i = db->typeList.cbegin();
const Type* Fred = &(*i++);
const Type* Wilma = &(*i++);
const Type* Barney = &(*i++);
ASSERT(Fred && Fred->classDef && Fred->classScope && Fred->enclosingScope && Fred->name() == "Fred");
ASSERT(Wilma && Wilma->classDef && Wilma->classScope && Wilma->enclosingScope && Wilma->name() == "Wilma");
ASSERT(Barney && Barney->classDef && Barney->classScope && Barney->enclosingScope && Barney->name() == "Barney");
ASSERT(db->variableList().size() == 5);
ASSERT(db->getVariableFromVarId(1) && db->getVariableFromVarId(1)->type() && db->getVariableFromVarId(1)->type()->name() == "Barney");
ASSERT(db->getVariableFromVarId(2) && db->getVariableFromVarId(2)->type() && db->getVariableFromVarId(2)->type()->name() == "Wilma");
ASSERT(db->getVariableFromVarId(3) && db->getVariableFromVarId(3)->type() && db->getVariableFromVarId(3)->type()->name() == "Barney");
}
void symboldatabase38() { // ticket #5125
check("template struct scoped_service;\n"
"struct service {};\n"
"template <> struct scoped_service {};\n"
"template \n"
"struct scoped_service : scoped_service\n"
"{\n"
" scoped_service( T* ptr ) : scoped_service(ptr), m_ptr(ptr) {}\n"
" T* const m_ptr;\n"
"};");
}
void symboldatabase40() { // ticket #5153
check("void f() {\n"
" try { }\n"
" catch (std::bad_alloc) { }\n"
"}");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase41() { // ticket #5197 (unknown macro)
GET_SYMBOL_DB("struct X1 { MACRO1 f(int spd) MACRO2; };");
ASSERT(db && db->findScopeByName("X1") && db->findScopeByName("X1")->functionList.size() == 1 && !db->findScopeByName("X1")->functionList.front().hasBody());
}
void symboldatabase42() { // only put variables in variable list
GET_SYMBOL_DB("void f() { extern int x(); }");
ASSERT(db != nullptr);
const Scope * const fscope = db ? db->findScopeByName("f") : nullptr;
ASSERT(fscope != nullptr);
ASSERT_EQUALS(0U, fscope ? fscope->varlist.size() : ~0U); // "x" is not a variable
}
void symboldatabase43() { // ticket #4738
check("void f() {\n"
" new int;\n"
"}");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase44() {
GET_SYMBOL_DB("int i { 1 };\n"
"int j ( i );\n"
"void foo() {\n"
" int k { 1 };\n"
" int l ( 1 );\n"
"}");
ASSERT(db != nullptr);
ASSERT_EQUALS(4U, db->variableList().size() - 1);
ASSERT_EQUALS(2U, db->scopeList.size());
for (std::size_t i = 1U; i < db->variableList().size(); i++)
ASSERT(db->getVariableFromVarId(i) != nullptr);
}
void symboldatabase45() {
GET_SYMBOL_DB("typedef struct {\n"
" unsigned long bits;\n"
"} S;\n"
"struct T {\n"
" S span;\n"
" int flags;\n"
"};\n"
"struct T f(int x) {\n"
" return (struct T) {\n"
" .span = (S) { 0UL },\n"
" .flags = (x ? 256 : 0),\n"
" };\n"
"}");
ASSERT(db != nullptr);
ASSERT_EQUALS(4U, db->variableList().size() - 1);
for (std::size_t i = 1U; i < db->variableList().size(); i++)
ASSERT(db->getVariableFromVarId(i) != nullptr);
ASSERT_EQUALS(4U, db->scopeList.size());
std::list::const_iterator scope = db->scopeList.cbegin();
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.cbegin();
ASSERT_EQUALS(Scope::eGlobal, scope->type);
++scope;
ASSERT_EQUALS(Scope::eStruct, scope->type);
ASSERT_EQUALS(scope->className, "S");
++scope;
ASSERT_EQUALS(Scope::eNamespace, scope->type);
ASSERT_EQUALS(scope->className, "");
++scope;
ASSERT_EQUALS(Scope::eStruct, scope->type);
ASSERT_EQUALS(scope->className, "S");
}
void symboldatabase47() { // #6308 - associate Function and Scope for destructors
GET_SYMBOL_DB("namespace NS {\n"
" class MyClass {\n"
" ~MyClass();\n"
" };\n"
"}\n"
"using namespace NS;\n"
"MyClass::~MyClass() {\n"
" delete Example;\n"
"}");
ASSERT(db && !db->functionScopes.empty() && db->functionScopes.front()->function && db->functionScopes.front()->function->functionScope == db->functionScopes.front());
}
void symboldatabase48() { // #6417
GET_SYMBOL_DB("namespace NS {\n"
" class MyClass {\n"
" MyClass();\n"
" ~MyClass();\n"
" };\n"
"}\n"
"using namespace NS;\n"
"MyClass::~MyClass() { }\n"
"MyClass::MyClass() { }");
ASSERT(db && !db->functionScopes.empty() && db->functionScopes.front()->function && db->functionScopes.front()->function->functionScope == db->functionScopes.front());
const Token *f = Token::findsimplematch(tokenizer.tokens(), "MyClass ( ) ;");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3 && f->function()->token->linenr() == 9);
f = Token::findsimplematch(tokenizer.tokens(), "~ MyClass ( ) ;");
f = f->next();
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4 && f->function()->token->linenr() == 8);
}
void symboldatabase49() { // #6424
GET_SYMBOL_DB("namespace Ns { class C; }\n"
"void f1() { char *p; *p = 0; }\n"
"class Ns::C* p;\n"
"void f2() { char *p; *p = 0; }");
ASSERT(db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "p ; void f2");
ASSERT_EQUALS(true, db && f && f->variable());
f = Token::findsimplematch(tokenizer.tokens(), "f2");
ASSERT_EQUALS(true, db && f && f->function());
}
void symboldatabase50() { // #6432
GET_SYMBOL_DB("template \n"
"class _ConstTessMemberResultCallback_0_0\n"
" {\n"
" public:\n"
" typedef void (T::*MemberSignature)() const;\n"
"\n"
" private:\n"
" const T* object_;\n"
" MemberSignature member_;\n"
"\n"
" public:\n"
" inline _ConstTessMemberResultCallback_0_0(\n"
" const T* object, MemberSignature member)\n"
" : object_(object),\n"
" member_(member) {\n"
" }\n"
"};");
ASSERT(db != nullptr);
const Token *f = Token::findsimplematch(tokenizer.tokens(), "_ConstTessMemberResultCallback_0_0 (");
ASSERT_EQUALS(true, db && f && f->function() && f->function()->isConstructor());
}
void symboldatabase51() { // #6538
GET_SYMBOL_DB("static const float f1 = 2 * foo1(a, b);\n"
"static const float f2 = 2 * ::foo2(a, b);\n"
"static const float f3 = 2 * std::foo3(a, b);\n"
"static const float f4 = c * foo4(a, b);\n"
"static const int i1 = 2 & foo5(a, b);\n"
"static const bool b1 = 2 > foo6(a, b);");
ASSERT(db != nullptr);
ASSERT(findFunctionByName("foo1", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo2", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo3", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo4", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo5", &db->scopeList.front()) == nullptr);
ASSERT(findFunctionByName("foo6", &db->scopeList.front()) == nullptr);
}
void symboldatabase52() { // #6581
GET_SYMBOL_DB("void foo() {\n"
" int i = 0;\n"
" S s{ { i }, 0 };\n"
"}");
ASSERT(db != nullptr);
ASSERT_EQUALS(2, db->scopeList.size());
ASSERT_EQUALS(2, db->variableList().size()-1);
ASSERT(db->getVariableFromVarId(1) != nullptr);
ASSERT(db->getVariableFromVarId(2) != nullptr);
}
void symboldatabase53() { // #7124
GET_SYMBOL_DB("int32_t x;"
"std::int32_t y;");
ASSERT(db != nullptr);
ASSERT(db->getVariableFromVarId(1) != nullptr);
ASSERT(db->getVariableFromVarId(2) != nullptr);
ASSERT_EQUALS(false, db->getVariableFromVarId(1)->isClass());
ASSERT_EQUALS(false, db->getVariableFromVarId(2)->isClass());
}
void symboldatabase54() { // #7343
GET_SYMBOL_DB("class A {\n"
" void getReg() const override {\n"
" assert(Kind == k_ShiftExtend);\n"
" }\n"
"};");
ASSERT(db != nullptr);
ASSERT_EQUALS(1U, db->functionScopes.size());
ASSERT_EQUALS("getReg", db->functionScopes.front()->className);
ASSERT_EQUALS(true, db->functionScopes.front()->function->hasOverrideSpecifier());
}
void symboldatabase55() { // #7767
GET_SYMBOL_DB("PRIVATE S32 testfunc(void) {\n"
" return 0;\n"
"}");
ASSERT(db != nullptr);
ASSERT_EQUALS(1U, db->functionScopes.size());
ASSERT_EQUALS("testfunc", db->functionScopes.front()->className);
}
void symboldatabase56() { // #7909
{
GET_SYMBOL_DB("class Class {\n"
" class NestedClass {\n"
" public:\n"
" virtual void f();\n"
" };\n"
" friend void NestedClass::f();\n"
"}");
ASSERT(db != nullptr);
ASSERT_EQUALS(0U, db->functionScopes.size());
ASSERT(db->scopeList.back().type == Scope::eClass && db->scopeList.back().className == "NestedClass");
ASSERT(db->scopeList.back().functionList.size() == 1U && !db->scopeList.back().functionList.front().hasBody());
}
{
GET_SYMBOL_DB("class Class {\n"
" friend void f1();\n"
" friend void f2() { }\n"
"}");
ASSERT(db != nullptr);
ASSERT_EQUALS(1U, db->functionScopes.size());
ASSERT(db->scopeList.back().type == Scope::eFunction && db->scopeList.back().className == "f2");
ASSERT(db->scopeList.back().function && db->scopeList.back().function->hasBody());
}
{
GET_SYMBOL_DB_C("friend f1();\n"
"friend f2() { }");
ASSERT(db != nullptr);
ASSERT_EQUALS(2U, db->scopeList.size());
ASSERT_EQUALS(2U, db->scopeList.cbegin()->functionList.size());
}
}
void symboldatabase57() {
GET_SYMBOL_DB("int bar(bool b)\n"
"{\n"
" if(b)\n"
" return 1;\n"
" else\n"
" return 1;\n"
"}");
ASSERT(db != nullptr);
ASSERT(db->scopeList.size() == 4U);
std::list::const_iterator it = db->scopeList.cbegin();
ASSERT(it->type == Scope::eGlobal);
ASSERT((++it)->type == Scope::eFunction);
ASSERT((++it)->type == Scope::eIf);
ASSERT((++it)->type == Scope::eElse);
}
void symboldatabase58() { // #6985 (using namespace type lookup)
GET_SYMBOL_DB("namespace N2\n"
"{\n"
"class B { };\n"
"}\n"
"using namespace N2;\n"
"class C {\n"
" class A : public B\n"
" {\n"
" };\n"
"};");
ASSERT(db != nullptr);
ASSERT(db->typeList.size() == 3U);
std::list::const_iterator it = db->typeList.cbegin();
const Type * classB = &(*it);
const Type * classC = &(*(++it));
const Type * classA = &(*(++it));
ASSERT(classA->name() == "A" && classB->name() == "B" && classC->name() == "C");
ASSERT(classA->derivedFrom.size() == 1U);
ASSERT(classA->derivedFrom[0].type != nullptr);
ASSERT(classA->derivedFrom[0].type == classB);
}
void symboldatabase59() { // #8465
GET_SYMBOL_DB("struct A::B ab[10];\n"
"void f() {}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 2);
}
void symboldatabase60() { // #8470
GET_SYMBOL_DB("struct A::someType A::bar() { return 0; }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 2);
}
void symboldatabase61() {
GET_SYMBOL_DB("struct Fred {\n"
" struct Info { };\n"
"};\n"
"void foo() {\n"
" struct Fred::Info* info;\n"
" info = new (nothrow) struct Fred::Info();\n"
" info = new struct Fred::Info();\n"
" memset(info, 0, sizeof(struct Fred::Info));\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 4);
}
void symboldatabase62() {
{
GET_SYMBOL_DB("struct A {\n"
"public:\n"
" struct X { int a; };\n"
" void Foo(const std::vector &includes);\n"
"};\n"
"void A::Foo(const std::vector &includes) {\n"
" for (std::vector::const_iterator it = includes.begin(); it != includes.end(); ++it) {\n"
" const struct A::X currentIncList = *it;\n"
" }\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 5);
const Scope *scope = db->findScopeByName("A");
ASSERT(scope != nullptr);
const Function *function = findFunctionByName("Foo", scope);
ASSERT(function != nullptr);
ASSERT(function->hasBody());
}
{
GET_SYMBOL_DB("class A {\n"
"public:\n"
" class X { public: int a; };\n"
" void Foo(const std::vector &includes);\n"
"};\n"
"void A::Foo(const std::vector &includes) {\n"
" for (std::vector::const_iterator it = includes.begin(); it != includes.end(); ++it) {\n"
" const class A::X currentIncList = *it;\n"
" }\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 5);
const Scope *scope = db->findScopeByName("A");
ASSERT(scope != nullptr);
const Function *function = findFunctionByName("Foo", scope);
ASSERT(function != nullptr);
ASSERT(function->hasBody());
}
{
GET_SYMBOL_DB("struct A {\n"
"public:\n"
" union X { int a; float b; };\n"
" void Foo(const std::vector &includes);\n"
"};\n"
"void A::Foo(const std::vector &includes) {\n"
" for (std::vector::const_iterator it = includes.begin(); it != includes.end(); ++it) {\n"
" const union A::X currentIncList = *it;\n"
" }\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 5);
const Scope *scope = db->findScopeByName("A");
ASSERT(scope != nullptr);
const Function *function = findFunctionByName("Foo", scope);
ASSERT(function != nullptr);
ASSERT(function->hasBody());
}
{
GET_SYMBOL_DB("struct A {\n"
"public:\n"
" enum X { a, b };\n"
" void Foo(const std::vector &includes);\n"
"};\n"
"void A::Foo(const std::vector &includes) {\n"
" for (std::vector::const_iterator it = includes.begin(); it != includes.end(); ++it) {\n"
" const enum A::X currentIncList = *it;\n"
" }\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 5);
const Scope *scope = db->findScopeByName("A");
ASSERT(scope != nullptr);
const Function *function = findFunctionByName("Foo", scope);
ASSERT(function != nullptr);
ASSERT(function->hasBody());
}
}
void symboldatabase63() {
{
GET_SYMBOL_DB("template class T ; void foo() { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 2);
}
{
GET_SYMBOL_DB("template struct T ; void foo() { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 2);
}
}
void symboldatabase64() {
{
GET_SYMBOL_DB("class Fred { struct impl; };\n"
"struct Fred::impl {\n"
" impl() { }\n"
" ~impl() { }\n"
" impl(const impl &) { }\n"
" void foo(const impl &, const impl &) const { }\n"
"};");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 7);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 3 &&
functionToken->function()->token->linenr() == 3);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 4 &&
functionToken->next()->function()->token->linenr() == 4);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 5);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 6);
}
{
GET_SYMBOL_DB("class Fred { struct impl; };\n"
"struct Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
"};\n"
"Fred::impl::impl() { }\n"
"Fred::impl::~impl() { }\n"
"Fred::impl::impl(const Fred::impl &) { }\n"
"void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 7);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 3 &&
functionToken->function()->token->linenr() == 8);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 4 &&
functionToken->next()->function()->token->linenr() == 9);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 10);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred :: impl & , const Fred :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 11);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" class Fred { struct impl; };\n"
" struct Fred::impl {\n"
" impl() { }\n"
" ~impl() { }\n"
" impl(const impl &) { }\n"
" void foo(const impl &, const impl &) const { }\n"
" };\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 4 &&
functionToken->function()->token->linenr() == 4);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 5 &&
functionToken->next()->function()->token->linenr() == 5);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 6);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 7);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" class Fred { struct impl; };\n"
" struct Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
" };\n"
" Fred::impl::impl() { }\n"
" Fred::impl::~impl() { }\n"
" Fred::impl::impl(const Fred::impl &) { }\n"
" void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 4 &&
functionToken->function()->token->linenr() == 9);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 5 &&
functionToken->next()->function()->token->linenr() == 10);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred :: impl & , const Fred :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 12);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" class Fred { struct impl; };\n"
" struct Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
" };\n"
"}\n"
"NS::Fred::impl::impl() { }\n"
"NS::Fred::impl::~impl() { }\n"
"NS::Fred::impl::impl(const NS::Fred::impl &) { }\n"
"void NS::Fred::impl::foo(const NS::Fred::impl &, const NS::Fred::impl &) const { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 4 &&
functionToken->function()->token->linenr() == 10);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 5 &&
functionToken->next()->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const NS :: Fred :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 12);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const NS :: Fred :: impl & , const NS :: Fred :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 13);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" class Fred { struct impl; };\n"
"}\n"
"struct NS::Fred::impl {\n"
" impl() { }\n"
" ~impl() { }\n"
" impl(const impl &) { }\n"
" void foo(const impl &, const impl &) const { }\n"
"};");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 5);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 6 &&
functionToken->next()->function()->token->linenr() == 6);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 7);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 8 &&
functionToken->function()->token->linenr() == 8);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" class Fred { struct impl; };\n"
"}\n"
"struct NS::Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
"};\n"
"NS::Fred::impl::impl() { }\n"
"NS::Fred::impl::~impl() { }\n"
"NS::Fred::impl::impl(const NS::Fred::impl &) { }\n"
"void NS::Fred::impl::foo(const NS::Fred::impl &, const NS::Fred::impl &) const { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 10);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 6 &&
functionToken->next()->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const NS :: Fred :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 12);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const NS :: Fred :: impl & , const NS :: Fred :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 8 &&
functionToken->function()->token->linenr() == 13);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" class Fred { struct impl; };\n"
"}\n"
"struct NS::Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
"};\n"
"namespace NS {\n"
" Fred::impl::impl() { }\n"
" Fred::impl::~impl() { }\n"
" Fred::impl::impl(const Fred::impl &) { }\n"
" void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 6 &&
functionToken->next()->function()->token->linenr() == 12);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 13);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred :: impl & , const Fred :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 8 &&
functionToken->function()->token->linenr() == 14);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" class Fred { struct impl; };\n"
"}\n"
"struct NS::Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
"};\n"
"using namespace NS;\n"
"Fred::impl::impl() { }\n"
"Fred::impl::~impl() { }\n"
"Fred::impl::impl(const Fred::impl &) { }\n"
"void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 6 &&
functionToken->next()->function()->token->linenr() == 12);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 13);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred :: impl & , const Fred :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 8 &&
functionToken->function()->token->linenr() == 14);
}
{
GET_SYMBOL_DB("template class Fred { struct impl; };\n"
"template struct Fred::impl {\n"
" impl() { }\n"
" ~impl() { }\n"
" impl(const impl &) { }\n"
" void foo(const impl &, const impl &) const { }\n"
"};");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 7);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 3 &&
functionToken->function()->token->linenr() == 3);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 4 &&
functionToken->next()->function()->token->linenr() == 4);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 5);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 6);
}
{
GET_SYMBOL_DB("template class Fred { struct impl; };\n"
"template struct Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
"};\n"
"template Fred::impl::impl() { }\n"
"template Fred::impl::~impl() { }\n"
"template Fred::impl::impl(const Fred::impl &) { }\n"
"template void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 7);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 3 &&
functionToken->function()->token->linenr() == 8);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 4 &&
functionToken->next()->function()->token->linenr() == 9);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred < A > :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 10);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred < A > :: impl & , const Fred < A > :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 11);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" template class Fred { struct impl; };\n"
" template struct Fred::impl {\n"
" impl() { }\n"
" ~impl() { }\n"
" impl(const impl &) { }\n"
" void foo(const impl &, const impl &) const { }\n"
" };\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 4 &&
functionToken->function()->token->linenr() == 4);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 5 &&
functionToken->next()->function()->token->linenr() == 5);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 6);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 7);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" template class Fred { struct impl; };\n"
" template struct Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
" };\n"
" template Fred::impl::impl() { }\n"
" template Fred::impl::~impl() { }\n"
" template Fred::impl::impl(const Fred::impl &) { }\n"
" template void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 4 &&
functionToken->function()->token->linenr() == 9);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 5 &&
functionToken->next()->function()->token->linenr() == 10);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred < A > :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred < A > :: impl & , const Fred < A > :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 12);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" template class Fred { struct impl; };\n"
" template struct Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
" };\n"
"}\n"
"template NS::Fred::impl::impl() { }\n"
"template NS::Fred::impl::~impl() { }\n"
"template NS::Fred::impl::impl(const NS::Fred::impl &) { }\n"
"template void NS::Fred::impl::foo(const NS::Fred::impl &, const NS::Fred::impl &) const { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 4 &&
functionToken->function()->token->linenr() == 10);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 5 &&
functionToken->next()->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const NS :: Fred < A > :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 6 &&
functionToken->function()->token->linenr() == 12);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const NS :: Fred < A > :: impl & , const NS :: Fred < A > :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 13);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" template class Fred { struct impl; };\n"
"}\n"
"template struct NS::Fred::impl {\n"
" impl() { }\n"
" ~impl() { }\n"
" impl(const impl &) { }\n"
" void foo(const impl &, const impl &) const { }\n"
"};");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 5);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 6 &&
functionToken->next()->function()->token->linenr() == 6);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 7);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const impl & , const impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 8 &&
functionToken->function()->token->linenr() == 8);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" template class Fred { struct impl; };\n"
"}\n"
"template struct NS::Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
"};\n"
"template NS::Fred::impl::impl() { }\n"
"template NS::Fred::impl::~impl() { }\n"
"template NS::Fred::impl::impl(const NS::Fred::impl &) { }\n"
"template void NS::Fred::impl::foo(const NS::Fred::impl &, const NS::Fred::impl &) const { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 10);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 6 &&
functionToken->next()->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const NS :: Fred < A > :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 12);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const NS :: Fred < A > :: impl & , const NS :: Fred < A > :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 8 &&
functionToken->function()->token->linenr() == 13);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" template class Fred { struct impl; };\n"
"}\n"
"template struct NS::Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
"};\n"
"namespace NS {\n"
" template Fred::impl::impl() { }\n"
" template Fred::impl::~impl() { }\n"
" template Fred::impl::impl(const Fred::impl &) { }\n"
" template void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }\n"
"}");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 6 &&
functionToken->next()->function()->token->linenr() == 12);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred < A > :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 13);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred < A > :: impl & , const Fred < A > :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 8 &&
functionToken->function()->token->linenr() == 14);
}
{
GET_SYMBOL_DB("namespace NS {\n"
" template class Fred { struct impl; };\n"
"}\n"
"template struct NS::Fred::impl {\n"
" impl();\n"
" ~impl();\n"
" impl(const impl &);\n"
" void foo(const impl &, const impl &) const;\n"
"};\n"
"using namespace NS;\n"
"template Fred::impl::impl() { }\n"
"template Fred::impl::~impl() { }\n"
"template Fred::impl::impl(const Fred::impl &) { }\n"
"template void Fred::impl::foo(const Fred::impl &, const Fred::impl &) const { }");
ASSERT(db != nullptr);
ASSERT(db && db->scopeList.size() == 8);
ASSERT(db && db->classAndStructScopes.size() == 2);
ASSERT(db && db->typeList.size() == 2);
ASSERT(db && db->functionScopes.size() == 4);
const Token * functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 5 &&
functionToken->function()->token->linenr() == 11);
functionToken = Token::findsimplematch(tokenizer.tokens(), "~ impl ( ) { }");
ASSERT(db && functionToken && functionToken->next()->function() &&
functionToken->next()->function()->functionScope &&
functionToken->next()->function()->tokenDef->linenr() == 6 &&
functionToken->next()->function()->token->linenr() == 12);
functionToken = Token::findsimplematch(tokenizer.tokens(), "impl ( const Fred < A > :: impl & ) { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 7 &&
functionToken->function()->token->linenr() == 13);
functionToken = Token::findsimplematch(tokenizer.tokens(), "foo ( const Fred < A > :: impl & , const Fred < A > :: impl & ) const { }");
ASSERT(db && functionToken && functionToken->function() &&
functionToken->function()->functionScope &&
functionToken->function()->tokenDef->linenr() == 8 &&
functionToken->function()->token->linenr() == 14);
}
}
void symboldatabase65() {
// don't crash on missing links from instantiation of template with typedef
check("int ( * X0 ) ( long ) < int ( ) ( long ) > :: f0 ( int * ) { return 0 ; }");
ASSERT_EQUALS("", errout_str());
check("int g();\n" // #11385
"void f(int i) {\n"
" if (i > ::g()) {}\n"
"}\n");
ASSERT_EQUALS("", 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 ( true ) ;") : 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 ( true ) 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 class c, class... f, template class d>\n"
"struct b, d<>>;\n"
"}\n"
"void e() { using c = a<>; }");
ASSERT(db != nullptr);
ASSERT_EQUALS("", errout_str());
}
void symboldatabase79() { // #9392
{
GET_SYMBOL_DB("class C { C(); };\n"
"C::C() = default;");
ASSERT(db->scopeList.size() == 2);
ASSERT(db->scopeList.back().functionList.size() == 1);
ASSERT(db->scopeList.back().functionList.front().isDefault() == true);
}
{
GET_SYMBOL_DB("namespace ns {\n"
"class C { C(); };\n"
"}\n"
"using namespace ns;\n"
"C::C() = default;");
ASSERT(db->scopeList.size() == 3);
ASSERT(db->scopeList.back().functionList.size() == 1);
ASSERT(db->scopeList.back().functionList.front().isDefault() == true);
}
{
GET_SYMBOL_DB("class C { ~C(); };\n"
"C::~C() = default;");
ASSERT(db->scopeList.size() == 2);
ASSERT(db->scopeList.back().functionList.size() == 1);
ASSERT(db->scopeList.back().functionList.front().isDefault() == true);
ASSERT(db->scopeList.back().functionList.front().isDestructor() == true);
}
{
GET_SYMBOL_DB("namespace ns {\n"
"class C { ~C(); };\n"
"}\n"
"using namespace ns;\n"
"C::~C() = default;");
ASSERT(db->scopeList.size() == 3);
ASSERT(db->scopeList.back().functionList.size() == 1);
ASSERT(db->scopeList.back().functionList.front().isDefault() == true);
ASSERT(db->scopeList.back().functionList.front().isDestructor() == true);
}
}
void symboldatabase80() { // #9389
{
GET_SYMBOL_DB("namespace ns {\n"
"class A {};\n"
"}\n"
"class AA {\n"
"private:\n"
" void f(const ns::A&);\n"
"};\n"
"using namespace ns;\n"
"void AA::f(const A&) { }");
ASSERT(db->scopeList.size() == 5);
ASSERT(db->functionScopes.size() == 1);
const Scope *scope = db->findScopeByName("AA");
ASSERT(scope);
ASSERT(scope->functionList.size() == 1);
ASSERT(scope->functionList.front().name() == "f");
ASSERT(scope->functionList.front().hasBody() == true);
}
{
GET_SYMBOL_DB("namespace ns {\n"
"namespace ns1 {\n"
"class A {};\n"
"}\n"
"}\n"
"class AA {\n"
"private:\n"
" void f(const ns::ns1::A&);\n"
"};\n"
"using namespace ns::ns1;\n"
"void AA::f(const A&) { }");
ASSERT(db->scopeList.size() == 6);
ASSERT(db->functionScopes.size() == 1);
const Scope *scope = db->findScopeByName("AA");
ASSERT(scope);
ASSERT(scope->functionList.size() == 1);
ASSERT(scope->functionList.front().name() == "f");
ASSERT(scope->functionList.front().hasBody() == true);
}
{
GET_SYMBOL_DB("namespace ns {\n"
"namespace ns1 {\n"
"class A {};\n"
"}\n"
"}\n"
"class AA {\n"
"private:\n"
" void f(const ns::ns1::A&);\n"
"};\n"
"using namespace ns;\n"
"void AA::f(const ns1::A&) { }");
ASSERT(db->scopeList.size() == 6);
ASSERT(db->functionScopes.size() == 1);
const Scope *scope = db->findScopeByName("AA");
ASSERT(scope);
ASSERT(scope->functionList.size() == 1);
ASSERT(scope->functionList.front().name() == "f");
ASSERT(scope->functionList.front().hasBody() == true);
}
}
void symboldatabase81() { // #9411
{
GET_SYMBOL_DB("namespace Terminal {\n"
" class Complete {\n"
" public:\n"
" std::string act(const Parser::Action *act);\n"
" };\n"
"}\n"
"using namespace std;\n"
"using namespace Parser;\n"
"using namespace Terminal;\n"
"string Complete::act(const Action *act) { }");
ASSERT(db->scopeList.size() == 4);
ASSERT(db->functionScopes.size() == 1);
const Scope *scope = db->findScopeByName("Complete");
ASSERT(scope);
ASSERT(scope->functionList.size() == 1);
ASSERT(scope->functionList.front().name() == "act");
ASSERT(scope->functionList.front().hasBody() == true);
}
{
GET_SYMBOL_DB("namespace Terminal {\n"
" class Complete {\n"
" public:\n"
" std::string act(const Foo::Parser::Action *act);\n"
" };\n"
"}\n"
"using namespace std;\n"
"using namespace Foo::Parser;\n"
"using namespace Terminal;\n"
"string Complete::act(const Action *act) { }");
ASSERT(db->scopeList.size() == 4);
ASSERT(db->functionScopes.size() == 1);
const Scope *scope = db->findScopeByName("Complete");
ASSERT(scope);
ASSERT(scope->functionList.size() == 1);
ASSERT(scope->functionList.front().name() == "act");
ASSERT(scope->functionList.front().hasBody() == true);
}
}
void symboldatabase82() {
GET_SYMBOL_DB("namespace foo { void foo() {} }");
ASSERT(db->functionScopes.size() == 1);
ASSERT_EQUALS(false, db->functionScopes[0]->function->isConstructor());
}
void symboldatabase83() { // #9431
GET_SYMBOL_DB_DBG("struct a { a() noexcept; };\n"
"a::a() noexcept = default;");
const Scope *scope = db->findScopeByName("a");
ASSERT(scope);
ASSERT(scope->functionList.size() == 1);
ASSERT(scope->functionList.front().name() == "a");
ASSERT(scope->functionList.front().hasBody() == false);
ASSERT(scope->functionList.front().isConstructor() == true);
ASSERT(scope->functionList.front().isDefault() == true);
ASSERT(scope->functionList.front().isNoExcept() == true);
ASSERT_EQUALS("", errout_str());
}
void symboldatabase84() {
{
GET_SYMBOL_DB_DBG("struct a { a() noexcept(false); };\n"
"a::a() noexcept(false) = default;");
const Scope *scope = db->findScopeByName("a");
ASSERT(scope);
ASSERT(scope->functionList.size() == 1);
ASSERT(scope->functionList.front().name() == "a");
ASSERT(scope->functionList.front().hasBody() == false);
ASSERT(scope->functionList.front().isConstructor() == true);
ASSERT(scope->functionList.front().isDefault() == true);
ASSERT(scope->functionList.front().isNoExcept() == false);
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB_DBG("struct a { a() noexcept(true); };\n"
"a::a() noexcept(true) = default;");
const Scope *scope = db->findScopeByName("a");
ASSERT(scope);
ASSERT(scope->functionList.size() == 1);
ASSERT(scope->functionList.front().name() == "a");
ASSERT(scope->functionList.front().hasBody() == false);
ASSERT(scope->functionList.front().isConstructor() == true);
ASSERT(scope->functionList.front().isDefault() == true);
ASSERT(scope->functionList.front().isNoExcept() == true);
ASSERT_EQUALS("", errout_str());
}
}
void symboldatabase85() {
GET_SYMBOL_DB("class Fred {\n"
" enum Mode { Mode1, Mode2, Mode3 };\n"
" void f() { _mode = x; }\n"
" Mode _mode;\n"
" DECLARE_PROPERTY_FIELD(_mode);\n"
"};");
const Token *vartok1 = Token::findsimplematch(tokenizer.tokens(), "_mode =");
ASSERT(vartok1);
ASSERT(vartok1->variable());
ASSERT(vartok1->variable()->scope());
const Token *vartok2 = Token::findsimplematch(tokenizer.tokens(), "( _mode ) ;")->next();
ASSERT_EQUALS(std::intptr_t(vartok1->variable()), std::intptr_t(vartok2->variable()));
}
void symboldatabase86() {
GET_SYMBOL_DB("class C { auto operator=(const C&) -> C&; };\n"
"auto C::operator=(const C&) -> C& = default;");
ASSERT(db->scopeList.size() == 2);
ASSERT(db->scopeList.back().functionList.size() == 1);
ASSERT(db->scopeList.back().functionList.front().isDefault() == true);
ASSERT(db->scopeList.back().functionList.front().hasBody() == false);
}
void symboldatabase87() { // #9922 'extern const char ( * x [ 256 ] ) ;'
GET_SYMBOL_DB("extern const char ( * x [ 256 ] ) ;");
const Token *xtok = Token::findsimplematch(tokenizer.tokens(), "x");
ASSERT(xtok->variable());
}
void symboldatabase88() { // #10040 (using namespace)
check("namespace external {\n"
"namespace ns {\n"
"enum class s { O };\n"
"}\n"
"}\n"
"namespace internal {\n"
"namespace ns1 {\n"
"template \n"
"void make(external::ns::s) {\n"
"}\n"
"}\n"
"}\n"
"using namespace external::ns;\n"
"struct A { };\n"
"static void make(external::ns::s ss) {\n"
" internal::ns1::make(ss);\n"
"}\n", true);
ASSERT_EQUALS("", errout_str());
}
void symboldatabase89() { // valuetype name
GET_SYMBOL_DB("namespace external {\n"
"namespace ns1 {\n"
"class A {\n"
"public:\n"
" struct S { };\n"
" A(const S&) { }\n"
"};\n"
"static const A::S AS = A::S();\n"
"}\n"
"}\n"
"using namespace external::ns1;\n"
"A a{AS};");
const Token *vartok1 = Token::findsimplematch(tokenizer.tokens(), "A a");
ASSERT(vartok1);
ASSERT(vartok1->next());
ASSERT(vartok1->next()->variable());
ASSERT(vartok1->next()->variable()->valueType());
ASSERT(vartok1->next()->variable()->valueType()->str() == "external::ns1::A");
}
void symboldatabase90() {
GET_SYMBOL_DB("struct Fred {\n"
" void foo(const int * const x);\n"
"};\n"
"void Fred::foo(const int * x) { }");
ASSERT_EQUALS("", errout_str());
const Token *functok = Token::findsimplematch(tokenizer.tokens(), "foo ( const int * x )");
ASSERT(functok);
ASSERT(functok->function());
ASSERT(functok->function()->name() == "foo");
}
void symboldatabase91() {
GET_SYMBOL_DB("namespace Fred {\n"
" struct Value {};\n"
" void foo(const std::vector> &callbacks);\n"
"}\n"
"void Fred::foo(const std::vector> &callbacks) { }");
ASSERT_EQUALS("", errout_str());
const Token *functok = Token::findsimplematch(tokenizer.tokens(),
"foo ( const std :: vector < std :: function < void ( const Fred :: Value & ) > > & callbacks ) { }");
ASSERT(functok);
ASSERT(functok->function());
ASSERT(functok->function()->name() == "foo");
}
void symboldatabase92() { // daca crash
{
GET_SYMBOL_DB("template struct a;\n"
"template \n"
"struct a : a<1, d...> {};\n"
"template struct f : a<0, e...> {};");
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB("b.f();");
ASSERT_EQUALS("", errout_str());
}
}
void symboldatabase93() { // alignas attribute
GET_SYMBOL_DB("struct alignas(int) A{\n"
"};\n"
);
ASSERT(db != nullptr);
const Scope* scope = db->findScopeByName("A");
ASSERT(scope);
}
void symboldatabase94() { // structured bindings
GET_SYMBOL_DB("int foo() { auto [x,y] = xy(); return x+y; }");
ASSERT(db != nullptr);
ASSERT(db->getVariableFromVarId(1) != nullptr);
ASSERT(db->getVariableFromVarId(2) != nullptr);
}
void symboldatabase95() { // #10295
GET_SYMBOL_DB("struct B {\n"
" void foo1(void);\n"
" void foo2();\n"
"};\n"
"void B::foo1() {}\n"
"void B::foo2(void) {}\n");
ASSERT_EQUALS("", errout_str());
const Token *functok = Token::findsimplematch(tokenizer.tokens(), "foo1 ( ) { }");
ASSERT(functok);
ASSERT(functok->function());
ASSERT(functok->function()->name() == "foo1");
functok = Token::findsimplematch(tokenizer.tokens(), "foo2 ( ) { }");
ASSERT(functok);
ASSERT(functok->function());
ASSERT(functok->function()->name() == "foo2");
}
void symboldatabase96() { // #10126
GET_SYMBOL_DB("struct A {\n"
" int i, j;\n"
"};\n"
"std::map m{ { 0, A{0,0} }, {0, A{0,0} } };\n");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase97() { // #10598 - final class
GET_SYMBOL_DB("template<> struct A final {\n"
" A() {}\n"
"};\n");
ASSERT(db);
ASSERT_EQUALS(3, db->scopeList.size());
const Token *functok = Token::findmatch(tokenizer.tokens(), "%name% (");
ASSERT(functok);
ASSERT(functok->function());
ASSERT_EQUALS(functok->function()->type, Function::Type::eConstructor);
}
void symboldatabase98() { // #10451
{
GET_SYMBOL_DB("struct A { typedef struct {} B; };\n"
"void f() {\n"
" auto g = [](A::B b) -> void { A::B b2 = b; };\n"
"};\n");
ASSERT(db);
ASSERT_EQUALS(5, db->scopeList.size());
}
{
GET_SYMBOL_DB("typedef union {\n"
" int i;\n"
"} U;\n"
"template \n"
"void f();\n");
ASSERT(db);
ASSERT_EQUALS(2, db->scopeList.size());
}
}
void symboldatabase99() { // #10864
check("void f() { std::map m; }");
ASSERT_EQUALS("", errout_str());
}
void symboldatabase100() {
{
GET_SYMBOL_DB("namespace N {\n" // #10174
" struct S {};\n"
" struct T { void f(S s); };\n"
" void T::f(N::S s) {}\n"
"}\n");
ASSERT(db);
ASSERT_EQUALS(1, db->functionScopes.size());
auto it = std::find_if(db->scopeList.cbegin(), db->scopeList.cend(), [](const Scope& s) {
return s.className == "T";
});
ASSERT(it != db->scopeList.end());
const Function* function = findFunctionByName("f", &*it);
ASSERT(function && function->token->str() == "f");
ASSERT(function->hasBody());
}
{
GET_SYMBOL_DB("namespace N {\n" // #10198
" class I {};\n"
" class A {\n"
" public:\n"
" A(I*);\n"
" };\n"
"}\n"
"using N::I;\n"
"namespace N {\n"
" A::A(I*) {}\n"
"}\n");
ASSERT(db);
ASSERT_EQUALS(1, db->functionScopes.size());
auto it = std::find_if(db->scopeList.cbegin(), db->scopeList.cend(), [](const Scope& s) {
return s.className == "A";
});
ASSERT(it != db->scopeList.end());
const Function* function = findFunctionByName("A", &*it);
ASSERT(function && function->token->str() == "A");
ASSERT(function->hasBody());
}
{
GET_SYMBOL_DB("namespace N {\n" // #10260
" namespace O {\n"
" struct B;\n"
" }\n"
"}\n"
"struct I {\n"
" using B = N::O::B;\n"
"};\n"
"struct A : I {\n"
" void f(B*);\n"
"};\n"
"void A::f(N::O::B*) {}\n");
ASSERT(db);
ASSERT_EQUALS(1, db->functionScopes.size());
auto it = std::find_if(db->scopeList.cbegin(), db->scopeList.cend(), [](const Scope& s) {
return s.className == "A";
});
ASSERT(it != db->scopeList.end());
const Function* function = findFunctionByName("f", &*it);
ASSERT(function && function->token->str() == "f");
ASSERT(function->hasBody());
}
}
void symboldatabase101() {
GET_SYMBOL_DB("struct A { bool b; };\n"
"void f(const std::vector& v) {\n"
" std::vector::const_iterator it = b.begin();\n"
" if (it->b) {}\n"
"}\n");
ASSERT(db);
const Token* it = Token::findsimplematch(tokenizer.tokens(), "it . b");
ASSERT(it);
ASSERT(it->tokAt(2));
ASSERT(it->tokAt(2)->variable());
}
void symboldatabase102() {
GET_SYMBOL_DB("std::string f() = delete;\n"
"void g() {}");
ASSERT(db);
ASSERT(db->scopeList.size() == 2);
ASSERT(db->scopeList.front().type == Scope::eGlobal);
ASSERT(db->scopeList.back().className == "g");
}
void symboldatabase103() {
GET_SYMBOL_DB("void f() {\n"
"using lambda = decltype([]() { return true; });\n"
"lambda{}();\n"
"}\n");
ASSERT(db != nullptr);
ASSERT_EQUALS("", errout_str());
}
void symboldatabase104() {
{
GET_SYMBOL_DB_DBG("struct S {\n" // #11535
" void f1(char* const c);\n"
" void f2(char* const c);\n"
" void f3(char* const);\n"
" void f4(char* c);\n"
" void f5(char* c);\n"
" void f6(char*);\n"
"};\n"
"void S::f1(char* c) {}\n"
"void S::f2(char*) {}\n"
"void S::f3(char* c) {}\n"
"void S::f4(char* const c) {}\n"
"void S::f5(char* const) {}\n"
"void S::f6(char* const c) {}\n");
ASSERT(db != nullptr);
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB_DBG("struct S2 {\n" // #11602
" enum E {};\n"
"};\n"
"struct S1 {\n"
" void f(S2::E) const;\n"
"};\n"
"void S1::f(const S2::E) const {}\n");
ASSERT(db != nullptr);
ASSERT_EQUALS("", errout_str());
}
{
GET_SYMBOL_DB_DBG("struct S {\n"
" void f(const bool b = false);\n"
"};\n"
"void S::f(const bool b) {}\n");
ASSERT(db != nullptr);
ASSERT_EQUALS("", errout_str());
}
}
void symboldatabase105() {
{
GET_SYMBOL_DB_DBG("template \n"
"struct S : public std::deque {\n"
" using std::deque::clear;\n"
" void f();\n"
"};\n"
"template \n"
"void S::f() {\n"
" clear();\n"
"}\n");
ASSERT(db != nullptr);
ASSERT_EQUALS("", errout_str());
const Token* const c = Token::findsimplematch(tokenizer.tokens(), "clear (");
ASSERT(!c->type());
}
}
void createSymbolDatabaseFindAllScopes1() {
GET_SYMBOL_DB("void f() { union {int x; char *p;} a={0}; }");
ASSERT(db->scopeList.size() == 3);
ASSERT_EQUALS(Scope::eUnion, db->scopeList.back().type);
}
void createSymbolDatabaseFindAllScopes2() {
GET_SYMBOL_DB("namespace ns { auto var1{0}; }\n"
"namespace ns { auto var2{0}; }\n");
ASSERT(db);
ASSERT_EQUALS(2, db->scopeList.size());
ASSERT_EQUALS(2, db->scopeList.back().varlist.size());
const Token* const var1 = Token::findsimplematch(tokenizer.tokens(), "var1");
const Token* const var2 = Token::findsimplematch(tokenizer.tokens(), "var2");
ASSERT(var1->variable());
ASSERT(var2->variable());
}
void createSymbolDatabaseFindAllScopes3() {
GET_SYMBOL_DB("namespace ns {\n"
"\n"
"namespace ns_details {\n"
"template struct has_A : std::false_type {};\n"
"template struct has_A::type> : std::true_type {};\n"
"template struct is_A_impl : public std::is_trivially_copyable {};\n"
"template struct is_A_impl : public std::is_same {};\n"
"}\n"
"\n"
"template struct is_A : ns_details::is_A_impl::value> {};\n"
"template struct is_A> : std::integral_constant::value && is_A::value> {};\n"
"}\n"
"\n"
"extern \"C\" {\n"
"static const int foo = 8;\n"
"}\n");
ASSERT(db);
ASSERT_EQUALS(6, db->scopeList.size());
ASSERT_EQUALS(1, db->scopeList.front().varlist.size());
auto list = db->scopeList;
list.pop_front();
ASSERT_EQUALS(true, std::all_of(list.cbegin(), list.cend(), [](const Scope& scope) {
return scope.varlist.empty();
}));
}
void createSymbolDatabaseFindAllScopes4()
{
GET_SYMBOL_DB("struct a {\n"
" void b() {\n"
" std::set c;\n"
" a{[&] {\n"
" auto d{c.lower_bound(0)};\n"
" c.emplace_hint(d);\n"
" }};\n"
" }\n"
" template a(e);\n"
"};\n");
ASSERT(db);
ASSERT_EQUALS(4, db->scopeList.size());
const Token* const var1 = Token::findsimplematch(tokenizer.tokens(), "d");
ASSERT(var1->variable());
}
void createSymbolDatabaseFindAllScopes5()
{
GET_SYMBOL_DB("class C {\n" // #11444
"public:\n"
" template\n"
" class D;\n"
" template\n"
" struct O : public std::false_type {};\n"
"};\n"
"template\n"
"struct C::O> : public std::true_type {};\n"
"template\n"
"class C::D {};\n"
"struct S {\n"
" S(int i) : m(i) {}\n"
" static const S IN;\n"
" int m;\n"
"};\n"
"const S S::IN(1);\n");
ASSERT(db);
ASSERT_EQUALS(6, db->scopeList.size());
const Token* const var = Token::findsimplematch(tokenizer.tokens(), "IN (");
ASSERT(var && var->variable());
ASSERT_EQUALS(var->variable()->name(), "IN");
auto it = db->scopeList.begin();
std::advance(it, 4);
ASSERT_EQUALS(it->className, "S");
ASSERT_EQUALS(var->variable()->scope(), &*it);
}
void createSymbolDatabaseFindAllScopes6()
{
GET_SYMBOL_DB("class A {\n"
"public:\n"
" class Nested {\n"
" public:\n"
" virtual ~Nested() = default;\n"
" };\n"
"};\n"
"class B {\n"
"public:\n"
" class Nested {\n"
" public:\n"
" virtual ~Nested() = default;\n"
" };\n"
"};\n"
"class C : public A, public B {\n"
"public:\n"
" class Nested : public A::Nested, public B::Nested {};\n"
"};\n");
ASSERT(db);
ASSERT_EQUALS(6, db->typeList.size());
auto it = db->typeList.cbegin();
const Type& classA = *it++;
const Type& classNA = *it++;
const Type& classB = *it++;
const Type& classNB = *it++;
const Type& classC = *it++;
const Type& classNC = *it++;
ASSERT(classA.name() == "A" && classB.name() == "B" && classC.name() == "C");
ASSERT(classNA.name() == "Nested" && classNB.name() == "Nested" && classNC.name() == "Nested");
ASSERT(classA.derivedFrom.empty() && classB.derivedFrom.empty());
ASSERT_EQUALS(classC.derivedFrom.size(), 2U);
ASSERT_EQUALS(classC.derivedFrom[0].type, &classA);
ASSERT_EQUALS(classC.derivedFrom[1].type, &classB);
ASSERT(classNA.derivedFrom.empty() && classNB.derivedFrom.empty());
ASSERT_EQUALS(classNC.derivedFrom.size(), 2U);
ASSERT_EQUALS(classNC.derivedFrom[0].type, &classNA);
ASSERT_EQUALS(classNC.derivedFrom[1].type, &classNB);
}
void createSymbolDatabaseFindAllScopes7()
{
{
GET_SYMBOL_DB("namespace {\n"
" struct S {\n"
" void f();\n"
" };\n"
"}\n"
"void S::f() {}\n");
ASSERT(db);
ASSERT_EQUALS(4, db->scopeList.size());
auto anon = db->scopeList.begin();
++anon;
ASSERT(anon->className.empty());
ASSERT_EQUALS(anon->type, Scope::eNamespace);
auto S = anon;
++S;
ASSERT_EQUALS(S->type, Scope::eStruct);
ASSERT_EQUALS(S->className, "S");
ASSERT_EQUALS(S->nestedIn, &*anon);
const Token* f = Token::findsimplematch(tokenizer.tokens(), "f ( ) {");
ASSERT(f && f->function() && f->function()->functionScope && f->function()->functionScope->bodyStart);
ASSERT_EQUALS(f->function()->functionScope->functionOf, &*S);
ASSERT_EQUALS(f->function()->functionScope->bodyStart->linenr(), 6);
}
{
GET_SYMBOL_DB("namespace {\n"
" int i = 0;\n"
"}\n"
"namespace N {\n"
" namespace {\n"
" template\n"
" struct S {\n"
" void f();\n"
" };\n"
" template\n"
" void S::f() {}\n"
" }\n"
" S g() { return {}; }\n"
"}\n");
ASSERT(db); // don't crash
ASSERT_EQUALS("", errout_str());
}
}
void createSymbolDatabaseIncompleteVars()
{
{
GET_SYMBOL_DB("void f() {\n"
" auto s1 = std::string{ \"abc\" };\n"
" auto s2 = std::string(\"def\");\n"
"}\n");
ASSERT(db && errout_str().empty());
const Token* s1 = Token::findsimplematch(tokenizer.tokens(), "string {");
ASSERT(s1 && !s1->isIncompleteVar());
const Token* s2 = Token::findsimplematch(s1, "string (");
ASSERT(s2 && !s2->isIncompleteVar());
}
{
GET_SYMBOL_DB("std::string f(int n, std::type_info t) {\n"
" std::vector v(n);\n"
" g();\n"
" if (static_cast(x)) {}\n"
" if (t == typeid(std::string)) {}\n"
" return (std::string) \"abc\";\n"
"}\n");
ASSERT(db && errout_str().empty());
const Token* s1 = Token::findsimplematch(tokenizer.tokens(), "string *");
ASSERT(s1 && !s1->isIncompleteVar());
const Token* s2 = Token::findsimplematch(s1, "string &");
ASSERT(s2 && !s2->isIncompleteVar());
const Token* x = Token::findsimplematch(s2, "x");
ASSERT(x && x->isIncompleteVar());
const Token* s3 = Token::findsimplematch(x, "string )");
ASSERT(s3 && !s3->isIncompleteVar());
const Token* s4 = Token::findsimplematch(s3->next(), "string )");
ASSERT(s4 && !s4->isIncompleteVar());
}
{
GET_SYMBOL_DB("void destroy(int*, void (*cb_dealloc)(void *));\n"
"void f(int* p, int* q, int* r) {\n"
" destroy(p, free);\n"
" destroy(q, std::free);\n"
" destroy(r, N::free);\n"
"}\n");
ASSERT(db && errout_str().empty());
const Token* free1 = Token::findsimplematch(tokenizer.tokens(), "free");
ASSERT(free1 && !free1->isIncompleteVar());
const Token* free2 = Token::findsimplematch(free1->next(), "free");
ASSERT(free2 && !free2->isIncompleteVar());
const Token* free3 = Token::findsimplematch(free2->next(), "free");
ASSERT(free3 && free3->isIncompleteVar());
}
{
GET_SYMBOL_DB("void f(QObject* p, const char* s) {\n"
" QWidget* w = dynamic_cast(p);\n"
" g(static_cast(s));\n"
" const std::uint64_t* const data = nullptr;\n"
"}\n");
ASSERT(db && errout_str().empty());
const Token* qw = Token::findsimplematch(tokenizer.tokens(), "QWidget * >");
ASSERT(qw && !qw->isIncompleteVar());
const Token* s = Token::findsimplematch(qw, "string >");
ASSERT(s && !s->isIncompleteVar());
const Token* u = Token::findsimplematch(s, "uint64_t");
ASSERT(u && !u->isIncompleteVar());
}
{
GET_SYMBOL_DB("void f() {\n"
" std::string* p = new std::string;\n"
" std::string* q = new std::string(\"abc\");\n"
" std::string* r = new std::string{ \"def\" };\n"
" std::string* s = new std::string[3]{ \"ghi\" };\n"
"}\n");
ASSERT(db && errout_str().empty());
const Token* s1 = Token::findsimplematch(tokenizer.tokens(), "string ;");
ASSERT(s1 && !s1->isIncompleteVar());
const Token* s2 = Token::findsimplematch(s1->next(), "string (");
ASSERT(s2 && !s2->isIncompleteVar());
const Token* s3 = Token::findsimplematch(s2->next(), "string {");
ASSERT(s3 && !s3->isIncompleteVar());
const Token* s4 = Token::findsimplematch(s3->next(), "string [");
ASSERT(s4 && !s4->isIncompleteVar());
}
{
GET_SYMBOL_DB("void f() {\n"
" T** p;\n"
" T*** q;\n"
" T** const * r;\n"
"}\n");
ASSERT(db && errout_str().empty());
const Token* p = Token::findsimplematch(tokenizer.tokens(), "p");
ASSERT(p && !p->isIncompleteVar());
const Token* q = Token::findsimplematch(p, "q");
ASSERT(q && !q->isIncompleteVar());
const Token* r = Token::findsimplematch(q, "r");
ASSERT(r && !r->isIncompleteVar());
}
{
GET_SYMBOL_DB("void f() {\n" // #12571
" auto g = []() -> std::string* {\n"
" return nullptr;\n"
" };\n"
"}\n");
ASSERT(db && errout_str().empty());
const Token* s = Token::findsimplematch(tokenizer.tokens(), "string");
ASSERT(s && !s->isIncompleteVar());
}
}
void enum1() {
GET_SYMBOL_DB("enum BOOL { FALSE, TRUE }; enum BOOL b;");
/* there is a enum scope with the name BOOL */
ASSERT(db && db->scopeList.back().type == Scope::eEnum && db->scopeList.back().className == "BOOL");
/* b is a enum variable, type is BOOL */
ASSERT(db && db->getVariableFromVarId(1)->isEnumType());
}
void enum2() {
GET_SYMBOL_DB("enum BOOL { FALSE, TRUE } b;");
/* there is a enum scope with the name BOOL */
ASSERT(db && db->scopeList.back().type == Scope::eEnum && db->scopeList.back().className == "BOOL");
/* b is a enum variable, type is BOOL */
ASSERT(db && db->getVariableFromVarId(1)->isEnumType());
}
void enum3() {
GET_SYMBOL_DB("enum ABC { A=11,B,C=A+B };");
ASSERT(db && db->scopeList.back().type == Scope::eEnum);
/* There is an enum A with value 11 */
const Enumerator *A = db->scopeList.back().findEnumerator("A");
ASSERT(A && A->value==11 && A->value_known);
/* There is an enum B with value 12 */
const Enumerator *B = db->scopeList.back().findEnumerator("B");
ASSERT(B && B->value==12 && B->value_known);
/* There is an enum C with value 23 */
const Enumerator *C = db->scopeList.back().findEnumerator("C");
ASSERT(C && C->value==23 && C->value_known);
}
void enum4() { // #7493
GET_SYMBOL_DB("enum Offsets { O1, O2, O3=5, O4 };\n"
"enum MyEnums { E1=O1+1, E2, E3=O3+1 };");
ASSERT(db != nullptr);
ASSERT_EQUALS(3U, db->scopeList.size());
// Assert that all enum values are known
std::list