diff --git a/src/lib/data/parser/ParserClient.h b/src/lib/data/parser/ParserClient.h index e898be68..fcc70bcf 100644 --- a/src/lib/data/parser/ParserClient.h +++ b/src/lib/data/parser/ParserClient.h @@ -98,7 +98,7 @@ public: const NameHierarchy& templateNameHierarchy) = 0; virtual Id onTemplateDefaultArgumentTypeParsed( const ParseLocation& location, const NameHierarchy& defaultArgumentTypeNameHierarchy, - const NameHierarchy& templateArgumentTypeNameHierarchy) = 0; + const NameHierarchy& templateParameterNameHierarchy) = 0; virtual Id onTemplateSpecializationParsed( const ParseLocation& location, const NameHierarchy& specializedNameHierarchy, const NameHierarchy& specializedFromNameHierarchy) = 0; diff --git a/src/lib/data/parser/ParserClientImpl.h b/src/lib/data/parser/ParserClientImpl.h index 04483145..493666f3 100644 --- a/src/lib/data/parser/ParserClientImpl.h +++ b/src/lib/data/parser/ParserClientImpl.h @@ -71,7 +71,7 @@ public: const NameHierarchy& templateNameHierarchy); virtual Id onTemplateDefaultArgumentTypeParsed( const ParseLocation& location, const NameHierarchy& defaultArgumentTypeNameHierarchy, - const NameHierarchy& templateArgumentTypeNameHierarchy); + const NameHierarchy& templateParameterNameHierarchy); virtual Id onTemplateSpecializationParsed( const ParseLocation& location, const NameHierarchy& specializedNameHierarchy, const NameHierarchy& specializedFromNameHierarchy); diff --git a/src/lib_parser/data/parser/cxx/ASTVisitor.cpp b/src/lib_parser/data/parser/cxx/ASTVisitor.cpp index 9a732934..f4530519 100644 --- a/src/lib_parser/data/parser/cxx/ASTVisitor.cpp +++ b/src/lib_parser/data/parser/cxx/ASTVisitor.cpp @@ -6,13 +6,13 @@ #include #include +#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h" #include "data/parser/cxx/utilityCxx.h" #include "data/parser/ParseLocation.h" #include "utility/file/FileManager.h" #include "utility/ScopedSwitcher.h" - // TODO: For an array access, X[I], skip over the array-to-pointer decay. We // currently record that X's address is taken, which is technically true, but // the address does not generally escape. @@ -278,8 +278,8 @@ bool ASTVisitor::TraverseTemplateSpecializationTypeLoc(clang::TemplateSpecializa bool ASTVisitor::TraverseUnresolvedLookupExpr(clang::UnresolvedLookupExpr* e) // TODO: do this for unresolved and dependent stuff { - std::shared_ptr n; - ScopedSwitcher> sw(m_childContextNameGenerator, n); + std::shared_ptr clear; + ScopedSwitcher> sw(m_childContextNameGenerator, clear); return base::TraverseUnresolvedLookupExpr(e); } @@ -636,8 +636,8 @@ bool ASTVisitor::TraverseNestedNameSpecifierLoc( } } break; - default: - // TODO: Do these cases matter? + default: // case Global: case Super: + // do nothing for the remaining cases break; } } @@ -796,7 +796,7 @@ bool ASTVisitor::VisitDecl(clang::Decl *d) RecordDeclRef(nd, loc, refType, symbolType); if (fd->isFunctionTemplateSpecialization()) { - RecordDeclRef(nd, loc, refType, ST_FunctionTemplateSpecialization); // TODO: functiontemplatespec is more reftype than symboltype + RecordDeclRef(nd, loc, RT_TemplateSpecialization, symbolType); } //} } else if (clang::VarDecl *vd = llvm::dyn_cast(d)) { @@ -873,7 +873,7 @@ bool ASTVisitor::VisitDecl(clang::Decl *d) if (clang::isa(td)) { - RecordDeclRef(nd, loc, refType, ST_ClassTemplateSpecialization); // TODO: classtemplatespec is more reftype than symboltype + RecordDeclRef(nd, loc, RT_TemplateSpecialization, symbolType); } } else if (clang::UsingDirectiveDecl *ud = llvm::dyn_cast(d)) { RecordDeclRef( @@ -1127,7 +1127,7 @@ void ASTVisitor::RecordTypeRef( } else if (refType == RT_TemplateDefaultArgument) { - m_client->onTemplateDefaultArgumentTypeParsed( // TODO: rename second parameter to "parameter" + m_client->onTemplateDefaultArgumentTypeParsed( parseLocation, typeNameHierarchy, contextNameHierarchy); } else @@ -1138,36 +1138,6 @@ void ASTVisitor::RecordTypeRef( } } -bool ASTVisitor::isPartOfImplicitTemplateSpecialization(clang::Decl* d) const -{ - if (!d) - { - return false; - } - - if (clang::ClassTemplateSpecializationDecl* ctsd = clang::dyn_cast_or_null(d)) - { - if (!ctsd->isExplicitSpecialization()) - { - return true; - } - } - else if (clang::FunctionDecl* fd = clang::dyn_cast_or_null(d)) - { - if (fd->isTemplateInstantiation() && fd->getTemplateSpecializationKind() != clang::TSK_ExplicitSpecialization) // or undefined?? - { - return true; - } - } - - return isPartOfImplicitTemplateSpecialization(clang::dyn_cast_or_null(d->getDeclContext())); -} - -bool ASTVisitor::isImplicit(clang::Decl* d) const -{ - return d->isImplicit() || isPartOfImplicitTemplateSpecialization(d); -} - void ASTVisitor::RecordDeclRef( clang::NamedDecl* d, clang::SourceLocation beginLoc, @@ -1188,153 +1158,164 @@ void ASTVisitor::RecordDeclRef( bool fallback = false; - if ( - refType == RT_Declaration || - refType == RT_Definition - ) + switch (refType) { - switch (symbolType) + case RT_Declaration: + case RT_Definition: { - case ST_Typedef: - if (clang::TypedefDecl* typedefDecl = clang::dyn_cast(d)) + switch (symbolType) { - m_client->onTypedefParsed( - parseLocation, - declNameHierarchy, - convertAccessType(typedefDecl->getAccess()), - declIsImplicit); - } - break; - case ST_Class: - if (clang::RecordDecl* recordDecl = clang::dyn_cast(d)) - { - m_client->onClassParsed( - parseLocation, - declNameHierarchy, - convertAccessType(recordDecl->getAccess()), - (refType == RT_Definition ? getParseLocationOfRecordBody(recordDecl) : ParseLocation()), - declIsImplicit); - } - break; - case ST_Struct: - if (clang::RecordDecl* recordDecl = clang::dyn_cast(d)) - { - m_client->onStructParsed( - parseLocation, - declNameHierarchy, - convertAccessType(recordDecl->getAccess()), - (refType == RT_Definition ? getParseLocationOfRecordBody(recordDecl) : ParseLocation()), - declIsImplicit); - } - break; - case ST_GlobalVariable: - m_client->onGlobalVariableParsed( - parseLocation, - declNameHierarchy, - declIsImplicit); - break; - case ST_Field: - //if (clang::VarDecl* varDecl = clang::dyn_cast(d)) - { - m_client->onFieldParsed( - parseLocation, - declNameHierarchy, - convertAccessType(d->getAccess()), - declIsImplicit); - } - break; - case ST_Function: - if (clang::FunctionDecl* functionDecl = clang::dyn_cast(d)) - { - m_client->onFunctionParsed( - parseLocation, - declNameHierarchy, - (refType == RT_Definition ? getParseLocationOfFunctionBody(functionDecl) : ParseLocation()), - declIsImplicit); - } - break; - case ST_Constructor: - case ST_Destructor: - case ST_Method: - if (clang::CXXMethodDecl* methodDecl = clang::dyn_cast(d)) - { - m_client->onMethodParsed( - parseLocation, - declNameHierarchy, - convertAccessType(methodDecl->getAccess()), - getAbstractionType(methodDecl), - (refType == RT_Definition ? getParseLocationOfFunctionBody(methodDecl) : ParseLocation()), - declIsImplicit); - - for (clang::CXXMethodDecl::method_iterator it = methodDecl->begin_overridden_methods(); // iterate in traversal and use RT_Overridden or so.. - it != methodDecl->end_overridden_methods(); it++) + case ST_Typedef: + if (clang::TypedefDecl* typedefDecl = clang::dyn_cast(d)) { - m_client->onMethodOverrideParsed( + m_client->onTypedefParsed( parseLocation, - m_declNameCache->getValue(*it), - declNameHierarchy); + declNameHierarchy, + convertAccessType(typedefDecl->getAccess()), + declIsImplicit); } - - clang::MemberSpecializationInfo* memberSpecializationInfo = methodDecl->getMemberSpecializationInfo(); - if (memberSpecializationInfo) + break; + case ST_Class: + if (clang::RecordDecl* recordDecl = clang::dyn_cast(d)) { - clang::NamedDecl* specializedNamedDecl = memberSpecializationInfo->getInstantiatedFrom(); - if (clang::isa(specializedNamedDecl)) + m_client->onClassParsed( + parseLocation, + declNameHierarchy, + convertAccessType(recordDecl->getAccess()), + (refType == RT_Definition ? getParseLocationOfRecordBody(recordDecl) : ParseLocation()), + declIsImplicit); + } + break; + case ST_Struct: + if (clang::RecordDecl* recordDecl = clang::dyn_cast(d)) + { + m_client->onStructParsed( + parseLocation, + declNameHierarchy, + convertAccessType(recordDecl->getAccess()), + (refType == RT_Definition ? getParseLocationOfRecordBody(recordDecl) : ParseLocation()), + declIsImplicit); + } + break; + case ST_GlobalVariable: + m_client->onGlobalVariableParsed( + parseLocation, + declNameHierarchy, + declIsImplicit); + break; + case ST_Field: + //if (clang::VarDecl* varDecl = clang::dyn_cast(d)) + { + m_client->onFieldParsed( + parseLocation, + declNameHierarchy, + convertAccessType(d->getAccess()), + declIsImplicit); + } + break; + case ST_Function: + if (clang::FunctionDecl* functionDecl = clang::dyn_cast(d)) + { + m_client->onFunctionParsed( + parseLocation, + declNameHierarchy, + (refType == RT_Definition ? getParseLocationOfFunctionBody(functionDecl) : ParseLocation()), + declIsImplicit); + } + break; + case ST_Constructor: + case ST_Destructor: + case ST_Method: + if (clang::CXXMethodDecl* methodDecl = clang::dyn_cast(d)) + { + m_client->onMethodParsed( + parseLocation, + declNameHierarchy, + convertAccessType(methodDecl->getAccess()), + getAbstractionType(methodDecl), + (refType == RT_Definition ? getParseLocationOfFunctionBody(methodDecl) : ParseLocation()), + declIsImplicit); + + for (clang::CXXMethodDecl::method_iterator it = methodDecl->begin_overridden_methods(); // iterate in traversal and use RT_Overridden or so.. + it != methodDecl->end_overridden_methods(); it++) { - m_client->onTemplateMemberFunctionSpecializationParsed( + m_client->onMethodOverrideParsed( parseLocation, - declNameHierarchy, - m_declNameCache->getValue(specializedNamedDecl)); + m_declNameCache->getValue(*it), + declNameHierarchy); + } + + clang::MemberSpecializationInfo* memberSpecializationInfo = methodDecl->getMemberSpecializationInfo(); + if (memberSpecializationInfo) + { + clang::NamedDecl* specializedNamedDecl = memberSpecializationInfo->getInstantiatedFrom(); + if (clang::isa(specializedNamedDecl)) + { + m_client->onTemplateMemberFunctionSpecializationParsed( + parseLocation, + declNameHierarchy, + m_declNameCache->getValue(specializedNamedDecl)); + } } } - } - break; - case ST_Namespace: - if (clang::NamespaceDecl* namespaceDecl = clang::dyn_cast(d)) - { - m_client->onNamespaceParsed( - namespaceDecl->isAnonymousNamespace() ? ParseLocation() : parseLocation, - declNameHierarchy, - getParseLocation(namespaceDecl->getSourceRange()), - declIsImplicit); - } - else if (clang::NamespaceAliasDecl* namespaceAliasDecl = clang::dyn_cast(d)) - { - m_client->onNamespaceParsed( - parseLocation, - declNameHierarchy, - getParseLocation(namespaceAliasDecl->getAliasedNamespace()->getSourceRange()), - declIsImplicit); - } - break; - case ST_Enum: - if (clang::EnumDecl* enumDecl = clang::dyn_cast(d)) - { - m_client->onEnumParsed( - parseLocation, - declNameHierarchy, - convertAccessType(enumDecl->getAccess()), - getParseLocation(enumDecl->getSourceRange()), - declIsImplicit); - } - break; - case ST_Enumerator: - m_client->onEnumConstantParsed( - parseLocation, - declNameHierarchy, - declIsImplicit); - break; - case ST_TemplateParameter: - if (!d->getName().empty()) // We don't create symbols for unnamed template parameters. - { - m_client->onTemplateParameterTypeParsed( + break; + case ST_Namespace: + if (clang::NamespaceDecl* namespaceDecl = clang::dyn_cast(d)) + { + m_client->onNamespaceParsed( + namespaceDecl->isAnonymousNamespace() ? ParseLocation() : parseLocation, + declNameHierarchy, + getParseLocation(namespaceDecl->getSourceRange()), + declIsImplicit); + } + else if (clang::NamespaceAliasDecl* namespaceAliasDecl = clang::dyn_cast(d)) + { + m_client->onNamespaceParsed( + parseLocation, + declNameHierarchy, + getParseLocation(namespaceAliasDecl->getAliasedNamespace()->getSourceRange()), + declIsImplicit); + } + break; + case ST_Enum: + if (clang::EnumDecl* enumDecl = clang::dyn_cast(d)) + { + m_client->onEnumParsed( + parseLocation, + declNameHierarchy, + convertAccessType(enumDecl->getAccess()), + getParseLocation(enumDecl->getSourceRange()), + declIsImplicit); + } + break; + case ST_Enumerator: + m_client->onEnumConstantParsed( parseLocation, declNameHierarchy, declIsImplicit); + break; + case ST_TemplateParameter: + if (!d->getName().empty()) // We don't create symbols for unnamed template parameters. + { + m_client->onTemplateParameterTypeParsed( + parseLocation, + declNameHierarchy, + declIsImplicit); + } + break; + case ST_LocalVariable: + case ST_Parameter: + // Do nothing. + break; + default: + fallback = true; + break; } break; - case ST_ClassTemplateSpecialization: - if (clang::ClassTemplateSpecializationDecl* classTemplateSpecializationDecl = clang::dyn_cast(d)) // TODO: we need a different reftype here! and st_max? mabe rewrite TraverseClassTemplateSpecializationDecl() + } + case RT_TemplateSpecialization: + { + if (clang::ClassTemplateSpecializationDecl* classTemplateSpecializationDecl = clang::dyn_cast(d)) { clang::NamedDecl* specializedFromDecl; llvm::PointerUnion pu = classTemplateSpecializationDecl->getSpecializedTemplateOrPartial(); @@ -1350,100 +1331,91 @@ void ASTVisitor::RecordDeclRef( m_client->onTemplateSpecializationParsed( parseLocation, declNameHierarchy, - m_declNameCache->getValue(specializedFromDecl)); // use context and childcontext!! + m_declNameCache->getValue(specializedFromDecl)); // todo: use context and childcontext!! } - break; - case ST_FunctionTemplateSpecialization: - if (clang::FunctionDecl* functionDecl = clang::dyn_cast(d)) + else if (clang::FunctionDecl* functionDecl = clang::dyn_cast(d)) { m_client->onTemplateSpecializationParsed( parseLocation, declNameHierarchy, - m_declNameCache->getValue(functionDecl->getPrimaryTemplate()->getTemplatedDecl())); // TODO: use contect and childcontext!! + m_declNameCache->getValue(functionDecl->getPrimaryTemplate()->getTemplatedDecl())); // TODO: use context and childcontext!! } break; - case ST_LocalVariable: - case ST_Parameter: - // Do nothing. - break; - default: - fallback = true; - break; } - } - else - { - const NameHierarchy contextNameHierarchy = getContextName(); - switch (symbolType) + default: { - case ST_Field: - m_client->onFieldUsageParsed( - parseLocation, - contextNameHierarchy, - declNameHierarchy - ); - break; - case ST_GlobalVariable: - if (refType == RT_TemplateArgument) + const NameHierarchy contextNameHierarchy = getContextName(); + switch (symbolType) { - m_client->onTemplateArgumentTypeParsed( - parseLocation, declNameHierarchy, contextNameHierarchy); - } - else - { - m_client->onGlobalVariableUsageParsed( + case ST_Field: + m_client->onFieldUsageParsed( + parseLocation, + contextNameHierarchy, + declNameHierarchy + ); + break; + case ST_GlobalVariable: + if (refType == RT_TemplateArgument) + { + m_client->onTemplateArgumentTypeParsed( + parseLocation, declNameHierarchy, contextNameHierarchy); + } + else + { + m_client->onGlobalVariableUsageParsed( + parseLocation, + contextNameHierarchy, + declNameHierarchy); + } + break; + case ST_Enumerator: + m_client->onEnumConstantUsageParsed( parseLocation, contextNameHierarchy, declNameHierarchy); - } - break; - case ST_Enumerator: - m_client->onEnumConstantUsageParsed( - parseLocation, - contextNameHierarchy, - declNameHierarchy); - break; - case ST_Max: - switch (refType) - { - case RT_Called: - m_client->onCallParsed( - parseLocation, contextNameHierarchy, declNameHierarchy); break; - case RT_Reference: - m_client->onTypeUsageParsed( - parseLocation, contextNameHierarchy, declNameHierarchy); + case ST_Max: + switch (refType) + { + case RT_Called: + m_client->onCallParsed( + parseLocation, contextNameHierarchy, declNameHierarchy); + break; + case RT_Reference: + m_client->onTypeUsageParsed( + parseLocation, contextNameHierarchy, declNameHierarchy); + break; + case RT_TemplateArgument: + m_client->onTemplateArgumentTypeParsed( + parseLocation, declNameHierarchy, contextNameHierarchy); + break; + case RT_TemplateDefaultArgument: + m_client->onTemplateDefaultArgumentTypeParsed( + parseLocation, declNameHierarchy, contextNameHierarchy); + break; + case RT_BaseClass: + m_client->onInheritanceParsed( + parseLocation, contextNameHierarchy, declNameHierarchy, m_contextAccess); + break; + case RT_Assigned: + case RT_AddressTaken: + case RT_Read: + case RT_Qualifier: + // Do nothing. + break; + default: + fallback = true; + break; + } break; - case RT_TemplateArgument: - m_client->onTemplateArgumentTypeParsed( - parseLocation, declNameHierarchy, contextNameHierarchy); - break; - case RT_TemplateDefaultArgument: - m_client->onTemplateDefaultArgumentTypeParsed( - parseLocation, declNameHierarchy, contextNameHierarchy); - break; - case RT_BaseClass: - m_client->onInheritanceParsed( - parseLocation, contextNameHierarchy, declNameHierarchy, m_contextAccess); - break; - case RT_Assigned: - case RT_AddressTaken: - case RT_Read: - case RT_Qualifier: + case ST_LocalVariable: + case ST_Parameter: // Do nothing. break; default: fallback = true; break; } - break; - case ST_LocalVariable: - case ST_Parameter: - // Do nothing. - break; - default: - fallback = true; - break; } } @@ -1487,6 +1459,37 @@ void ASTVisitor::RecordDeclRef( // } //} } + +bool ASTVisitor::isPartOfImplicitTemplateSpecialization(clang::Decl* d) const +{ + if (!d) + { + return false; + } + + if (clang::ClassTemplateSpecializationDecl* ctsd = clang::dyn_cast_or_null(d)) + { + if (!ctsd->isExplicitSpecialization()) + { + return true; + } + } + else if (clang::FunctionDecl* fd = clang::dyn_cast_or_null(d)) + { + if (fd->isTemplateInstantiation() && fd->getTemplateSpecializationKind() != clang::TSK_ExplicitSpecialization) // or undefined?? + { + return true; + } + } + + return isPartOfImplicitTemplateSpecialization(clang::dyn_cast_or_null(d->getDeclContext())); +} + +bool ASTVisitor::isImplicit(clang::Decl* d) const +{ + return d->isImplicit() || isPartOfImplicitTemplateSpecialization(d); +} + bool ASTVisitor::isLocatedInUnparsedProjectFile(clang::SourceLocation loc) { clang::SourceManager& sourceManager = m_context->getSourceManager(); diff --git a/src/lib_parser/data/parser/cxx/ASTVisitor.h b/src/lib_parser/data/parser/cxx/ASTVisitor.h index a5219dd5..306486de 100644 --- a/src/lib_parser/data/parser/cxx/ASTVisitor.h +++ b/src/lib_parser/data/parser/cxx/ASTVisitor.h @@ -12,11 +12,6 @@ #include "utility/file/FileRegister.h" #include "utility/Cache.h" - - -#include "data/parser/cxx/name_resolver/CxxTypeNameResolver.h" -#include "data/parser/cxx/utilityCxx.h" - class ASTVisitor: clang::RecursiveASTVisitor { public: @@ -113,6 +108,7 @@ private: RT_Reference, RT_TemplateArgument, RT_TemplateDefaultArgument, + RT_TemplateSpecialization, RT_Undefinition, RT_Using, RT_UsingDirective, @@ -121,14 +117,12 @@ private: enum SymbolType : int { // we dont need this. decl already knows it! ST_Class, - ST_ClassTemplateSpecialization, ST_Constructor, ST_Destructor, ST_Enum, ST_Enumerator, ST_Field, ST_Function, - ST_FunctionTemplateSpecialization, ST_GlobalVariable, ST_LocalVariable, ST_Macro, @@ -143,12 +137,6 @@ private: ST_Max }; - struct Location { - unsigned int fileID; - unsigned int line; // 1-based - int column; // 1-based - }; - typedef unsigned int Context; clang::ASTContext* m_context; @@ -238,15 +226,15 @@ private: RefType refType, SymbolType symbolType = ST_Max); - bool isPartOfImplicitTemplateSpecialization(clang::Decl* d) const; - bool isImplicit(clang::Decl* d) const; - void RecordDeclRef( clang::NamedDecl *d, clang::SourceLocation beginLoc, RefType refType, SymbolType symbolType = ST_Max); + bool isPartOfImplicitTemplateSpecialization(clang::Decl* d) const; + bool isImplicit(clang::Decl* d) const; + bool isLocatedInUnparsedProjectFile(clang::SourceLocation loc); bool isLocatedInProjectFile(clang::SourceLocation loc); diff --git a/src/lib_parser/data/parser/cxx/utilityCxx.h b/src/lib_parser/data/parser/cxx/utilityCxx.h index 29b577c5..07b8910c 100644 --- a/src/lib_parser/data/parser/cxx/utilityCxx.h +++ b/src/lib_parser/data/parser/cxx/utilityCxx.h @@ -15,9 +15,6 @@ class NameHierarchy; namespace utility { - template - TypeLocType getNextTypeLoc(clang::TypeLoc loc); - std::shared_ptr qualTypeToDataType(clang::QualType qualType); NameHierarchy getDeclNameHierarchy(const clang::Decl* declaration); @@ -25,19 +22,4 @@ namespace utility NameHierarchy getTemplateSpecializationParentNameHierarchy(clang::ClassTemplateSpecializationDecl* declaration); } -template -TypeLocType utility::getNextTypeLoc(clang::TypeLoc loc) -{ - while (!loc.isNull()) - { - TypeLocType ret = loc.getAs(); - if (!ret.isNull()) - { - return ret; - } - loc = loc.getNextTypeLoc(); - } - return TypeLocType(); // isNull() of this object returns true. -} - #endif // UTILITY_CLANG_H diff --git a/src/test/CxxParserTestSuite.h b/src/test/CxxParserTestSuite.h index 607f6fb4..ca650680 100644 --- a/src/test/CxxParserTestSuite.h +++ b/src/test/CxxParserTestSuite.h @@ -76,10 +76,10 @@ public: std::shared_ptr client = parseCode( "class A\n" "{\n" - " int a;" + " int a;\n" "public:\n" " A() : d(0) {};\n" - " int b;" + " int b;\n" "protected:\n" " static int c;\n" "private:\n" @@ -89,9 +89,9 @@ public: TS_ASSERT_EQUALS(client->fields.size(), 4); TS_ASSERT_EQUALS(client->fields[0], "private A::a <3:6 3:6>"); - TS_ASSERT_EQUALS(client->fields[1], "public A::b <5:6 5:6>"); - TS_ASSERT_EQUALS(client->fields[2], "protected A::c <6:13 6:13>"); - TS_ASSERT_EQUALS(client->fields[3], "private A::d <8:12 8:12>"); + TS_ASSERT_EQUALS(client->fields[1], "public A::b <6:6 6:6>"); + TS_ASSERT_EQUALS(client->fields[2], "protected A::c <8:13 8:13>"); + TS_ASSERT_EQUALS(client->fields[3], "private A::d <10:12 10:12>"); } void test_cxx_parser_finds_function_declaration()