diff --git a/Tmain/list-kinds-full.d/stdout-expected.txt b/Tmain/list-kinds-full.d/stdout-expected.txt index 6b1526cdac..310c463f05 100644 --- a/Tmain/list-kinds-full.d/stdout-expected.txt +++ b/Tmain/list-kinds-full.d/stdout-expected.txt @@ -19,8 +19,7 @@ z parameter no no 0 C function parameters inside function or prototype definitio A alias no no 0 NONE namespace aliases D macroparam no no 0 C parameters inside macro definitions L label no no 0 C goto labels -N name no no 0 NONE names imported via using scope::symbol -U using no yes 0 NONE using namespace statements +N name yes yes 1 NONE names imported via using scope::symbol Z tparam no no 0 NONE template parameters c class yes no 0 NONE classes d macro yes no 1 C macro definitions @@ -30,7 +29,7 @@ g enum yes no 0 C enumeration names h header yes yes 2 C included header files l local no no 0 C local variables m member yes no 0 C class, struct, and union members -n namespace yes no 0 NONE namespaces +n namespace yes no 1 NONE namespaces p prototype no no 0 C function prototypes s struct yes no 0 C structure names t typedef yes no 0 C typedefs diff --git a/Tmain/list-roles.d/stdout-expected.txt b/Tmain/list-roles.d/stdout-expected.txt index eadd803ed7..e28bb69ece 100644 --- a/Tmain/list-roles.d/stdout-expected.txt +++ b/Tmain/list-roles.d/stdout-expected.txt @@ -18,9 +18,11 @@ Automake d/directory script on directory for SCRIPT C d/macro undef on undefined C h/header local on local header C h/header system on system header +C++ N/name used on specified with "using foo::bar" C++ d/macro undef on undefined C++ h/header local on local header C++ h/header system on system header +C++ n/namespace used on specified with "using namespace" CPreProcessor d/macro undef on undefined CPreProcessor h/header local on local header CPreProcessor h/header system on system header @@ -109,9 +111,11 @@ Automake d/directory script on directory for SCRIPT C d/macro undef on undefined C h/header local on local header C h/header system on system header +C++ N/name used on specified with "using foo::bar" C++ d/macro undef on undefined C++ h/header local on local header C++ h/header system on system header +C++ n/namespace used on specified with "using namespace" CPreProcessor d/macro undef on undefined CPreProcessor h/header local on local header CPreProcessor h/header system on system header diff --git a/Units/parser-cxx.r/bug1093123.cpp.d/expected.tags b/Units/parser-cxx.r/bug1093123.cpp.d/expected.tags index 3773cb0191..3c63b06ef4 100644 --- a/Units/parser-cxx.r/bug1093123.cpp.d/expected.tags +++ b/Units/parser-cxx.r/bug1093123.cpp.d/expected.tags @@ -1,3 +1,2 @@ main input.cpp /^int main() {$/;" f typeref:typename:int -std input.cpp /^using namespace std;$/;" U function:main m input.cpp /^int m;$/;" l function:main typeref:typename:int file: diff --git a/Units/parser-cxx.r/bug834.cpp.d/expected.tags b/Units/parser-cxx.r/bug834.cpp.d/expected.tags index 30163fd55c..af5d2bf8be 100644 --- a/Units/parser-cxx.r/bug834.cpp.d/expected.tags +++ b/Units/parser-cxx.r/bug834.cpp.d/expected.tags @@ -1,4 +1,3 @@ -std input.cpp /^using namespace std;$/;" U file: C input.cpp /^vector> C;$/;" v typeref:typename:vector> A input.cpp /^struct A {$/;" s file: a input.cpp /^ int a;$/;" m struct:A typeref:typename:int file: diff --git a/Units/parser-cxx.r/using.cpp.d/expected.tags b/Units/parser-cxx.r/using.cpp.d/expected.tags index 0fe9e3ad11..7a3a0060a5 100644 --- a/Units/parser-cxx.r/using.cpp.d/expected.tags +++ b/Units/parser-cxx.r/using.cpp.d/expected.tags @@ -1,9 +1,14 @@ A input.cpp /^class A$/;" class file: roles:def B input.cpp /^class B : public A$/;" class file: roles:def -std input.cpp /^using namespace std;$/;" using file: roles:def +C input.cpp /^ class C : A$/;" class namespace:X file: roles:def +D input.cpp /^class D : X::C$/;" class file: roles:def +X input.cpp /^namespace X$/;" namespace file: roles:def +std input.cpp /^using namespace std;$/;" namespace file: roles:used string input.cpp /^#include /;" header roles:system -string input.cpp /^using std::string;$/;" name file: roles:def -test input.cpp /^ using A::test;$/;" name class:B roles:def +string input.cpp /^using std::string;$/;" name name:std roles:used +test input.cpp /^ using A::test;$/;" name name:A roles:used test input.cpp /^ void test();$/;" prototype class:A typeref:typename:void file: signature:() roles:def test input.cpp /^ void test(x t);$/;" prototype class:B typeref:typename:void file: signature:(x t) roles:def +test2 input.cpp /^ void test2();$/;" prototype class:X::C typeref:typename:void file: signature:() roles:def +test2 input.cpp /^ using X::C::test2;$/;" name name:X::C roles:used x input.cpp /^using x = std::string;$/;" typedef typeref:typename:std::string file: roles:def diff --git a/Units/parser-cxx.r/using.cpp.d/input.cpp b/Units/parser-cxx.r/using.cpp.d/input.cpp index 7e4cd8a879..6fa3eba3d8 100644 --- a/Units/parser-cxx.r/using.cpp.d/input.cpp +++ b/Units/parser-cxx.r/using.cpp.d/input.cpp @@ -15,4 +15,19 @@ class B : public A public: void test(x t); using A::test; -}; \ No newline at end of file +}; + +namespace X +{ + class C : A + { + public: + void test2(); + }; +} + +class D : X::C +{ +public: + using X::C::test2; +}; diff --git a/parsers/cxx/cxx_debug.c b/parsers/cxx/cxx_debug.c index c6ec096554..f4ad7c413d 100644 --- a/parsers/cxx/cxx_debug.c +++ b/parsers/cxx/cxx_debug.c @@ -172,6 +172,7 @@ const char* cxxDebugScopeDecode(enum CXXScopeType scope) [CXXScopeTypeVariable] = "variable", [CXXScopeTypePrototype] = "prototype", [CXXScopeTypeTypedef] = "typedef", + [CXXScopeTypeName] = "name", }; if (CXXScopeTypeLAST > scope) return table[scope]; diff --git a/parsers/cxx/cxx_parser_using.c b/parsers/cxx/cxx_parser_using.c index df0d2adba3..71cf956f06 100644 --- a/parsers/cxx/cxx_parser_using.c +++ b/parsers/cxx/cxx_parser_using.c @@ -118,6 +118,8 @@ bool cxxParserParseUsingClause(void) if(g_cxx.pTokenChain->iCount > 0) { tagEntryInfo * tag; + int iScopeCount = 0; + CXXTokenChain *pOriginalScope = NULL; if(bUsingNamespace) { @@ -134,7 +136,9 @@ bool cxxParserParseUsingClause(void) "Found using clause '%s' which extends scope", vStringValue(t->pszWord) ); - tag = cxxTagBegin(CXXTagCPPKindUSING,t); + tag = cxxRefTagBegin(CXXTagCPPKindNAMESPACE, + CXXTagCPPNamespaceRoleUSED,t); + } else { t = cxxTokenChainLast(g_cxx.pTokenChain); @@ -143,9 +147,34 @@ bool cxxParserParseUsingClause(void) "Found using clause '%s' which imports a name", vStringValue(t->pszWord) ); - tag = cxxTagBegin(CXXTagCPPKindNAME,t); - // FIXME: We need something like "nameref:" here! + // Backup the original scope stack + int iSize = cxxScopeGetSize(); + if(iSize > 0) + { + pOriginalScope = cxxTokenChainCreate(); + while(iSize--) + { + CXXToken *t0 = cxxScopeTakeTop(); + cxxTokenChainPrepend(pOriginalScope, t0); + } + } + + // Push temporary scopes for the name + while(cxxTokenChainFirst(g_cxx.pTokenChain) != t) + { + CXXToken *pTokenScope = cxxTokenChainTakeFirst(g_cxx.pTokenChain); + if(cxxTokenTypeIs(pTokenScope,CXXTokenTypeIdentifier)) + { + cxxScopePush(pTokenScope,CXXScopeTypeName,CXXScopeAccessUnknown); + iScopeCount++; + } + else + cxxTokenDestroy(pTokenScope); + } + + tag = cxxRefTagBegin(CXXTagCPPKindNAME, + CXXTagCPPNameRoleUSED, t); } if(tag) @@ -154,6 +183,19 @@ bool cxxParserParseUsingClause(void) (!isInputHeaderFile()); cxxTagCommit(); } + + // Destory the temporary scopes for the name + while(iScopeCount--) + cxxScopePop(); + + // Recover the original scope stack + if(pOriginalScope) + { + CXXToken *t0; + while((t0 = cxxTokenChainTakeFirst(pOriginalScope))) + cxxScopePushTop(t0); + cxxTokenChainDestroy(pOriginalScope); + } } } diff --git a/parsers/cxx/cxx_scope.c b/parsers/cxx/cxx_scope.c index f370c6efce..cbfad47b1d 100644 --- a/parsers/cxx/cxx_scope.c +++ b/parsers/cxx/cxx_scope.c @@ -112,6 +112,8 @@ unsigned int cxxScopeGetKind(void) return CXXTagKindVARIABLE; case CXXScopeTypeTypedef: return CXXTagKindTYPEDEF; + case CXXScopeTypeName: + return CXXTagCPPKindNAME; default: CXX_DEBUG_ASSERT(false,"Unhandled scope type!"); break; diff --git a/parsers/cxx/cxx_scope.h b/parsers/cxx/cxx_scope.h index dc7cddd20b..cf28dafdc4 100644 --- a/parsers/cxx/cxx_scope.h +++ b/parsers/cxx/cxx_scope.h @@ -32,6 +32,8 @@ enum CXXScopeType CXXScopeTypeVariable, // template variables, mainly CXXScopeTypePrototype, CXXScopeTypeTypedef, // template variables used in "using A = B" + CXXScopeTypeName, /* for representing scope information of + foo in "using some::thing::foo" */ CXXScopeTypeLAST }; diff --git a/parsers/cxx/cxx_tag.c b/parsers/cxx/cxx_tag.c index 74c080deeb..f45f268136 100644 --- a/parsers/cxx/cxx_tag.c +++ b/parsers/cxx/cxx_tag.c @@ -68,14 +68,22 @@ static kindDefinition g_aCXXCKinds [] = { CXX_COMMON_KINDS(C,"struct, and union members", LANG_IGNORE) }; +static roleDefinition g_aCXXCPPNamespaceRoles [] = { + { true, "used", "specified with \"using namespace\"" }, +}; + +static roleDefinition g_aCXXCPPNameRoles [] = { + { true, "used", "specified with \"using foo::bar\"" }, +}; + static kindDefinition g_aCXXCPPKinds [] = { CXX_COMMON_KINDS(CXX,"class, struct, and union members", LANG_AUTO), { true, 'c', "class", "classes" }, - { true, 'n', "namespace", "namespaces" }, + { true, 'n', "namespace", "namespaces", + .referenceOnly = false, ATTACH_ROLES(g_aCXXCPPNamespaceRoles) }, { false, 'A', "alias", "namespace aliases" }, - { false, 'N', "name", "names imported via using scope::symbol" }, - { false, 'U', "using", "using namespace statements", - .referenceOnly = true }, + { true, 'N', "name", "names imported via using scope::symbol", + .referenceOnly = true, ATTACH_ROLES(g_aCXXCPPNameRoles) }, { false, 'Z', "tparam", "template parameters" }, }; @@ -245,7 +253,7 @@ bool cxxTagFieldEnabled(unsigned int uField) static tagEntryInfo g_oCXXTag; -tagEntryInfo * cxxTagBegin(unsigned int uKind,CXXToken * pToken) +static tagEntryInfo * cxxTagBeginCommon(unsigned int uKind,unsigned int uRole,CXXToken * pToken) { kindDefinition * pKindDefinitions = g_cxx.pKindDefinitions; @@ -255,10 +263,11 @@ tagEntryInfo * cxxTagBegin(unsigned int uKind,CXXToken * pToken) return NULL; } - initTagEntry( + initRefTagEntry( &g_oCXXTag, vStringValue(pToken->pszWord), - uKind + uKind, + uRole ); g_oCXXTag.lineNumber = pToken->iLineNumber; @@ -277,6 +286,16 @@ tagEntryInfo * cxxTagBegin(unsigned int uKind,CXXToken * pToken) return &g_oCXXTag; } +tagEntryInfo * cxxRefTagBegin(unsigned int uKind, unsigned int uRole, CXXToken * pToken) +{ + return cxxTagBeginCommon(uKind, uRole, pToken); +} + +tagEntryInfo * cxxTagBegin(unsigned int uKind,CXXToken * pToken) +{ + return cxxTagBeginCommon(uKind, ROLE_DEFINITION_INDEX, pToken); +} + vString * cxxTagSetProperties(unsigned int uProperties) { if(uProperties == 0) diff --git a/parsers/cxx/cxx_tag.h b/parsers/cxx/cxx_tag.h index 8d8675aca1..fd61806680 100644 --- a/parsers/cxx/cxx_tag.h +++ b/parsers/cxx/cxx_tag.h @@ -46,10 +46,19 @@ enum CXXTagCPPKind CXXTagCPPKindNAMESPACE, CXXTagCPPKindALIAS, CXXTagCPPKindNAME, - CXXTagCPPKindUSING, CXXTagCPPKindTEMPLATEPARAM }; +enum CXXTagCPPNamespaceRole +{ + CXXTagCPPNamespaceRoleUSED, +}; + +enum CXXTagCPPNameRole +{ + CXXTagCPPNameRoleUSED, +}; + // The fields common to all (sub)languages this parser supports. enum CXXTagCommonField { @@ -99,6 +108,10 @@ bool cxxTagKindEnabled(unsigned int uTagKind); // The pToken ownership is NOT transferred. tagEntryInfo * cxxTagBegin(unsigned int uKind,CXXToken * pToken); +// Do the same as cxxTagBegin but attaching a role for making a +// reference tag. +tagEntryInfo * cxxRefTagBegin(unsigned int uKind,unsigned int uRole,CXXToken * pToken); + // Set the type of the current tag from the specified token sequence // (which must belong to the same chain!). // Before setting the type this function will check that the specified