From 93badeed0e5ae931bbfe8207423ab442ed2318bc Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Fri, 11 Jun 2021 07:02:25 +0900 Subject: [PATCH] Cxx: extract parameters in prototypes Close #3045. If types of parameters are declared in a prototype, this change generates anonymous names for them and makes tags. --- .../attribute.cpp.d/expected.tags | 1 + .../complex-macros.d/expected.tags | 4 ++ .../cxx11-lambdas.d/expected.tags | 32 +++++------ .../cxx11enum.cpp.d/expected.tags | 1 + .../functions.cpp.d/expected.tags | 11 ++++ .../template-specializations.d/expected.tags | 20 +++++++ parsers/cxx/cxx_parser.c | 8 ++- parsers/cxx/cxx_parser_function.c | 53 +++++++++++++++++-- parsers/cxx/cxx_parser_internal.h | 4 ++ parsers/cxx/cxx_tag.c | 2 +- parsers/cxx/cxx_token.c | 13 +++++ parsers/cxx/cxx_token.h | 3 ++ 12 files changed, 132 insertions(+), 20 deletions(-) diff --git a/Units/parser-cxx.r/attribute.cpp.d/expected.tags b/Units/parser-cxx.r/attribute.cpp.d/expected.tags index d4207e720f..678b748abe 100644 --- a/Units/parser-cxx.r/attribute.cpp.d/expected.tags +++ b/Units/parser-cxx.r/attribute.cpp.d/expected.tags @@ -18,6 +18,7 @@ e1e1 input.cpp /^ e1e1 __attribute__((deprecated)),$/;" e enum:e1 file: e1e2 input.cpp /^ e1e2$/;" e enum:e1 file: p1 input.cpp /^__attribute__((noreturn)) void p1(void),$/;" p typeref:typename:void file: signature:(void) p2 input.cpp /^ __attribute__((format(printf, 1, 2))) p2 (const char *, ...),$/;" p typeref:typename:void file: signature:(const char *,...) +__anon6f96ad27010d input.cpp /^ __attribute__((format(printf, 1, 2))) p2 (const char *, ...),$/;" z prototype:p2 typeref:typename:const char * file: p3 input.cpp /^ p3 (void);$/;" p typeref:typename:void file: signature:(void) p4 input.cpp /^void (__attribute__((noreturn)) ****p4) (void) __attribute__((deprecated));$/;" v typeref:typename:void (****)(void) properties:deprecated p5 input.cpp /^void p5() __attribute__ ((weak, alias ("p4")));$/;" p typeref:typename:void file: signature:() diff --git a/Units/parser-cxx.r/complex-macros.d/expected.tags b/Units/parser-cxx.r/complex-macros.d/expected.tags index c5bc755ea6..7b063299c0 100644 --- a/Units/parser-cxx.r/complex-macros.d/expected.tags +++ b/Units/parser-cxx.r/complex-macros.d/expected.tags @@ -11,6 +11,8 @@ _ret input.cpp /^#define DECLARE_FUNCTION_3(_ret,_name,...) _ret _name(__VA_ARGS _name input.cpp /^#define DECLARE_FUNCTION_3(_ret,_name,...) _ret _name(__VA_ARGS__);$/;" D macro:DECLARE_FUNCTION_3 DECLARE_FUNCTION_3 input.cpp /^#define DECLARE_FUNCTION_3(/;" d file: signature:(_ret,_name,...) p3 input.cpp /^DECLARE_FUNCTION_3(int,p3,int a,int b);$/;" p typeref:typename:int file: signature:(int a,int b) +a input.cpp /^DECLARE_FUNCTION_3(int,p3,int a,int b);$/;" z prototype:p3 typeref:typename:int file: +b input.cpp /^DECLARE_FUNCTION_3(int,p3,int a,int b);$/;" z prototype:p3 typeref:typename:int file: DEPRECATED input.cpp /^#define DEPRECATED(/;" d file: signature:(...) p4 input.cpp /^DEPRECATED(int p4());$/;" p typeref:typename:int file: signature:() properties:deprecated _prefix1 input.cpp /^#define DECLARE_TWO_VERSIONS_OF_FUNCTIONS(_prefix1,_prefix2) \\$/;" D macro:DECLARE_TWO_VERSIONS_OF_FUNCTIONS @@ -37,5 +39,7 @@ f1b input.cpp /^IMPLEMENT_FUNCTIONS(f1);$/;" f typeref:typename:void signature:( _prefix input.cpp /^#define DECLARE_VARS(_prefix) int _prefix ## a; int _prefix ## b;$/;" D macro:DECLARE_VARS DECLARE_VARS input.cpp /^#define DECLARE_VARS(/;" d file: signature:(_prefix) main input.cpp /^int main(int,char **)$/;" f typeref:typename:int signature:(int,char **) +__anonb64b5bec010d input.cpp /^int main(int,char **)$/;" z function:main typeref:typename:int file: +__anonb64b5bec020d input.cpp /^int main(int,char **)$/;" z function:main typeref:typename:char ** file: la input.cpp /^ DECLARE_VARS(l);$/;" l function:main typeref:typename:int file: lb input.cpp /^ DECLARE_VARS(l);$/;" l function:main typeref:typename:int file: diff --git a/Units/parser-cxx.r/cxx11-lambdas.d/expected.tags b/Units/parser-cxx.r/cxx11-lambdas.d/expected.tags index 530f217871..5314de6bec 100644 --- a/Units/parser-cxx.r/cxx11-lambdas.d/expected.tags +++ b/Units/parser-cxx.r/cxx11-lambdas.d/expected.tags @@ -17,24 +17,26 @@ l4 input.cpp /^ auto l4 = [a,b](int c){ return a+b+c; };$/;" local function:tes l3 input.cpp /^ auto l3 = [=](int a,int b) -> int {$/;" local function:test typeref:typename:auto file: end:21 __anon4e7b1b580502 input.cpp /^ auto l5 = [](X x,X) -> X { return X(); };$/;" function function:test typeref:typename:X file: signature:(X x,X) end:23 captures:[] x input.cpp /^ auto l5 = [](X x,X) -> X { return X(); };$/;" parameter function:test::__anon4e7b1b580502 typeref:typename:X file: +__anon4e7b1b58060d input.cpp /^ auto l5 = [](X x,X) -> X { return X(); };$/;" parameter function:test::__anon4e7b1b580502 typeref:typename:X file: l5 input.cpp /^ auto l5 = [](X x,X) -> X { return X(); };$/;" local function:test typeref:typename:auto file: -__anon4e7b1b580602 input.cpp /^ [l1,l2,l3](int a,int b) -> int {$/;" function function:test typeref:typename:int file: signature:(int a,int b) end:28 captures:[l1,l2,l3] -a input.cpp /^ [l1,l2,l3](int a,int b) -> int {$/;" parameter function:test::__anon4e7b1b580602 typeref:typename:int file: -b input.cpp /^ [l1,l2,l3](int a,int b) -> int {$/;" parameter function:test::__anon4e7b1b580602 typeref:typename:int file: +__anon4e7b1b580702 input.cpp /^ [l1,l2,l3](int a,int b) -> int {$/;" function function:test typeref:typename:int file: signature:(int a,int b) end:28 captures:[l1,l2,l3] +a input.cpp /^ [l1,l2,l3](int a,int b) -> int {$/;" parameter function:test::__anon4e7b1b580702 typeref:typename:int file: +b input.cpp /^ [l1,l2,l3](int a,int b) -> int {$/;" parameter function:test::__anon4e7b1b580702 typeref:typename:int file: v1 input.cpp /^ int v1 = call($/;" local function:test typeref:typename:int file: end:29 -__anon4e7b1b580702 input.cpp /^auto lg1 = [] { return 0; };$/;" function file: end:32 captures:[] +__anon4e7b1b580802 input.cpp /^auto lg1 = [] { return 0; };$/;" function file: end:32 captures:[] lg1 input.cpp /^auto lg1 = [] { return 0; };$/;" variable typeref:typename:auto end:32 -__anon4e7b1b580802 input.cpp /^auto lg2 = [](int a,int b) { return a > b ? a : b; };$/;" function file: signature:(int a,int b) end:34 captures:[] -a input.cpp /^auto lg2 = [](int a,int b) { return a > b ? a : b; };$/;" parameter function:__anon4e7b1b580802 typeref:typename:int file: -b input.cpp /^auto lg2 = [](int a,int b) { return a > b ? a : b; };$/;" parameter function:__anon4e7b1b580802 typeref:typename:int file: +__anon4e7b1b580902 input.cpp /^auto lg2 = [](int a,int b) { return a > b ? a : b; };$/;" function file: signature:(int a,int b) end:34 captures:[] +a input.cpp /^auto lg2 = [](int a,int b) { return a > b ? a : b; };$/;" parameter function:__anon4e7b1b580902 typeref:typename:int file: +b input.cpp /^auto lg2 = [](int a,int b) { return a > b ? a : b; };$/;" parameter function:__anon4e7b1b580902 typeref:typename:int file: lg2 input.cpp /^auto lg2 = [](int a,int b) { return a > b ? a : b; };$/;" variable typeref:typename:auto end:34 -__anon4e7b1b580902 input.cpp /^auto lg3 = [=](int a,int b) -> int {$/;" function typeref:typename:int file: signature:(int a,int b) end:39 captures:[=] -a input.cpp /^auto lg3 = [=](int a,int b) -> int {$/;" parameter function:__anon4e7b1b580902 typeref:typename:int file: -b input.cpp /^auto lg3 = [=](int a,int b) -> int {$/;" parameter function:__anon4e7b1b580902 typeref:typename:int file: -__anon4e7b1b580a02 input.cpp /^ auto lg4 = [a,b](int c){ return a+b+c; };$/;" function function:__anon4e7b1b580902 file: signature:(int c) end:37 captures:[a,b] -c input.cpp /^ auto lg4 = [a,b](int c){ return a+b+c; };$/;" parameter function:__anon4e7b1b580902::__anon4e7b1b580a02 typeref:typename:int file: -lg4 input.cpp /^ auto lg4 = [a,b](int c){ return a+b+c; };$/;" local function:__anon4e7b1b580902 typeref:typename:auto file: end:37 +__anon4e7b1b580a02 input.cpp /^auto lg3 = [=](int a,int b) -> int {$/;" function typeref:typename:int file: signature:(int a,int b) end:39 captures:[=] +a input.cpp /^auto lg3 = [=](int a,int b) -> int {$/;" parameter function:__anon4e7b1b580a02 typeref:typename:int file: +b input.cpp /^auto lg3 = [=](int a,int b) -> int {$/;" parameter function:__anon4e7b1b580a02 typeref:typename:int file: +__anon4e7b1b580b02 input.cpp /^ auto lg4 = [a,b](int c){ return a+b+c; };$/;" function function:__anon4e7b1b580a02 file: signature:(int c) end:37 captures:[a,b] +c input.cpp /^ auto lg4 = [a,b](int c){ return a+b+c; };$/;" parameter function:__anon4e7b1b580a02::__anon4e7b1b580b02 typeref:typename:int file: +lg4 input.cpp /^ auto lg4 = [a,b](int c){ return a+b+c; };$/;" local function:__anon4e7b1b580a02 typeref:typename:auto file: end:37 lg3 input.cpp /^auto lg3 = [=](int a,int b) -> int {$/;" variable typeref:typename:auto end:39 -__anon4e7b1b580b02 input.cpp /^auto lg5 = [](X x,X) -> X { return X(); };$/;" function typeref:typename:X file: signature:(X x,X) end:41 captures:[] -x input.cpp /^auto lg5 = [](X x,X) -> X { return X(); };$/;" parameter function:__anon4e7b1b580b02 typeref:typename:X file: +__anon4e7b1b580c02 input.cpp /^auto lg5 = [](X x,X) -> X { return X(); };$/;" function typeref:typename:X file: signature:(X x,X) end:41 captures:[] +x input.cpp /^auto lg5 = [](X x,X) -> X { return X(); };$/;" parameter function:__anon4e7b1b580c02 typeref:typename:X file: +__anon4e7b1b580d0d input.cpp /^auto lg5 = [](X x,X) -> X { return X(); };$/;" parameter function:__anon4e7b1b580c02 typeref:typename:X file: lg5 input.cpp /^auto lg5 = [](X x,X) -> X { return X(); };$/;" variable typeref:typename:auto diff --git a/Units/parser-cxx.r/cxx11enum.cpp.d/expected.tags b/Units/parser-cxx.r/cxx11enum.cpp.d/expected.tags index 153fab40c3..3616de41dd 100644 --- a/Units/parser-cxx.r/cxx11enum.cpp.d/expected.tags +++ b/Units/parser-cxx.r/cxx11enum.cpp.d/expected.tags @@ -47,5 +47,6 @@ CEC1_member1 input.cpp /^ enum class CEC1 : unsigned long int { CEC1_member1 };$ CES1 input.cpp /^ enum struct CES1 : int { CES1_member1 };$/;" g class:Class typeref:typename:int file: end:30 properties:scopedenum CES1_member1 input.cpp /^ enum struct CES1 : int { CES1_member1 };$/;" e enum:Class::CES1 file: Function1 input.cpp /^ virtual enum CEC1 Function1(enum CE1 parameter);$/;" p class:Class typeref:enum:CEC1 file: end:31 properties:virtual +parameter input.cpp /^ virtual enum CEC1 Function1(enum CE1 parameter);$/;" z prototype:Class::Function1 typeref:enum:CE1 file: E1_var1 input.cpp /^enum E1 E1_var1;$/;" v typeref:enum:E1 end:41 EC1_var1 input.cpp /^enum EC1 EC1_var1[10][10];$/;" v typeref:enum:EC1[10][10] end:42 diff --git a/Units/parser-cxx.r/functions.cpp.d/expected.tags b/Units/parser-cxx.r/functions.cpp.d/expected.tags index 1479bbc0b3..8779038c88 100644 --- a/Units/parser-cxx.r/functions.cpp.d/expected.tags +++ b/Units/parser-cxx.r/functions.cpp.d/expected.tags @@ -11,6 +11,7 @@ f05 input.cpp /^static inline std::string f05(const int *** f05a01)$/;" f typere f05a01 input.cpp /^static inline std::string f05(const int *** f05a01)$/;" z function:f05 typeref:typename:const int *** file: f06 input.cpp /^ auto f06(n01::c01 && f06a01) -> type01 *;$/;" p namespace:n01::n02 typeref:typename:type01 * file: signature:(n01::c01 && f06a01) end:15 f06 input.cpp /^auto n01::n02::f06(n01::c01 && f06a01) -> n01::n02::type01 *$/;" f class:n01::n02 typeref:typename:n01::n02::type01 * signature:(n01::c01 && f06a01) end:59 +f06a01 input.cpp /^ auto f06(n01::c01 && f06a01) -> type01 *;$/;" z prototype:n01::n02::f06 typeref:typename:n01::c01 && file: f06a01 input.cpp /^auto n01::n02::f06(n01::c01 && f06a01) -> n01::n02::type01 *$/;" z function:n01::n02::f06 typeref:typename:n01::c01 && file: f07 input.cpp /^unsigned int f07(int (*f07a01)(int * x1,int x2),...)$/;" f typeref:typename:unsigned int signature:(int (* f07a01)(int * x1,int x2),...) end:64 f07a01 input.cpp /^unsigned int f07(int (*f07a01)(int * x1,int x2),...)$/;" z function:f07 typeref:typename:int (*)(int * x1,int x2) file: @@ -25,14 +26,24 @@ f10a03 input.cpp /^int f10(int f10a01,int f10a02[],int f10a03[2][3],int (f10a04) f10a04 input.cpp /^int f10(int f10a01,int f10a02[],int f10a03[2][3],int (f10a04)[],int (f10a05)[][5])$/;" z function:f10 typeref:typename:int ()[] file: f10a05 input.cpp /^int f10(int f10a01,int f10a02[],int f10a03[2][3],int (f10a04)[],int (f10a05)[][5])$/;" z function:f10 typeref:typename:int ()[][5] file: p01 input.cpp /^int p01(int p01a01,int p01a02);$/;" p typeref:typename:int file: signature:(int p01a01,int p01a02) end:21 +p01a01 input.cpp /^int p01(int p01a01,int p01a02);$/;" z prototype:p01 typeref:typename:int file: +p01a02 input.cpp /^int p01(int p01a01,int p01a02);$/;" z prototype:p01 typeref:typename:int file: p02 input.cpp /^unsigned short int * p02(unsigned int & p02a01,...);$/;" p typeref:typename:unsigned short int * file: signature:(unsigned int & p02a01,...) end:22 +p02a01 input.cpp /^unsigned short int * p02(unsigned int & p02a01,...);$/;" z prototype:p02 typeref:typename:unsigned int & file: p03 input.cpp /^auto p03(const int & p03a01,void * p03a02) -> const int &;$/;" p typeref:typename:const int & file: signature:(const int & p03a01,void * p03a02) end:23 +p03a01 input.cpp /^auto p03(const int & p03a01,void * p03a02) -> const int &;$/;" z prototype:p03 typeref:typename:const int & file: +p03a02 input.cpp /^auto p03(const int & p03a01,void * p03a02) -> const int &;$/;" z prototype:p03 typeref:typename:void * file: p04 input.cpp /^auto p04() -> int (*)(int);$/;" p typeref:typename:int (*)(int) file: signature:() end:24 p05 input.cpp /^static std::string p05(const int *** p05a01);$/;" p typeref:typename:std::string file: signature:(const int *** p05a01) end:25 +p05a01 input.cpp /^static std::string p05(const int *** p05a01);$/;" z prototype:p05 typeref:typename:const int *** file: p06 input.cpp /^ auto p06(n01::c01 && p06a01) -> type01 *;$/;" p namespace:n01::n02 typeref:typename:type01 * file: signature:(n01::c01 && p06a01) end:16 p06 input.cpp /^auto n01::n02::p06(n01::c01 && p06a01) -> n01::n02::type01 *;$/;" p class:n01::n02 typeref:typename:n01::n02::type01 * file: signature:(n01::c01 && p06a01) end:26 +p06a01 input.cpp /^ auto p06(n01::c01 && p06a01) -> type01 *;$/;" z prototype:n01::n02::p06 typeref:typename:n01::c01 && file: +p06a01 input.cpp /^auto n01::n02::p06(n01::c01 && p06a01) -> n01::n02::type01 *;$/;" z prototype:n01::n02::p06 typeref:typename:n01::c01 && file: p07 input.cpp /^unsigned int p07(int (*p07a01)(int * x1,int x2),...);$/;" p typeref:typename:unsigned int file: signature:(int (* p07a01)(int * x1,int x2),...) end:27 +p07a01 input.cpp /^unsigned int p07(int (*p07a01)(int * x1,int x2),...);$/;" z prototype:p07 typeref:typename:int (*)(int * x1,int x2) file: p08 input.cpp /^void (*p08(void (*)(int *p08a01)))(int *);$/;" p typeref:typename:void (*)(int *) file: signature:(void (*)(int * p08a01)) end:28 +p08a01 input.cpp /^void (*p08(void (*)(int *p08a01)))(int *);$/;" z prototype:p08 typeref:typename:void (*)(int *) file: t01 input.cpp /^template std::unique_ptr t01(T && t01a01)$/;" f typeref:typename:std::unique_ptr signature:(T && t01a01) end:85 t01a01 input.cpp /^template std::unique_ptr t01(T && t01a01)$/;" z function:t01 typeref:typename:T && file: t02 input.cpp /^template auto t02(T && t02a01) -> std::unique_ptr$/;" f typeref:typename:std::unique_ptr signature:(T && t02a01) end:94 diff --git a/Units/parser-cxx.r/template-specializations.d/expected.tags b/Units/parser-cxx.r/template-specializations.d/expected.tags index dc1a92c55b..fe41d4d801 100644 --- a/Units/parser-cxx.r/template-specializations.d/expected.tags +++ b/Units/parser-cxx.r/template-specializations.d/expected.tags @@ -1,27 +1,47 @@ A input.cpp /^struct A {$/;" s file: template: T input.cpp /^template$/;" Z struct:A typeref:meta:typename f input.cpp /^ void f(T); \/\/ member, declared in the primary template$/;" p struct:A typeref:typename:void file: signature:(T) +__anonc12ce61d010d input.cpp /^ void f(T); \/\/ member, declared in the primary template$/;" z prototype:A::f typeref:typename:T file: h input.cpp /^ void h(T) {} \/\/ member, defined in the primary template$/;" f struct:A typeref:typename:void file: signature:(T) +__anonc12ce61d020d input.cpp /^ void h(T) {} \/\/ member, defined in the primary template$/;" z function:A::h typeref:typename:T file: g1 input.cpp /^ template void g1(T, X1); \/\/ member template$/;" p struct:A typeref:typename:void file: signature:(T,X1) template: X1 input.cpp /^ template void g1(T, X1); \/\/ member template$/;" Z prototype:A::g1 typeref:meta:class +__anonc12ce61d030d input.cpp /^ template void g1(T, X1); \/\/ member template$/;" z prototype:A::g1 typeref:typename:T file: +__anonc12ce61d040d input.cpp /^ template void g1(T, X1); \/\/ member template$/;" z prototype:A::g1 typeref:typename:X1 file: g2 input.cpp /^ template void g2(T, X2); \/\/ member template$/;" p struct:A typeref:typename:void file: signature:(T,X2) template: X2 input.cpp /^ template void g2(T, X2); \/\/ member template$/;" Z prototype:A::g2 typeref:meta:class +__anonc12ce61d050d input.cpp /^ template void g2(T, X2); \/\/ member template$/;" z prototype:A::g2 typeref:typename:T file: +__anonc12ce61d060d input.cpp /^ template void g2(T, X2); \/\/ member template$/;" z prototype:A::g2 typeref:typename:X2 file: f input.cpp /^template<> void A::f(int);$/;" p class:A typeref:typename:void file: signature:(int) template:<> properties:scopespecialization,specialization +__anonc12ce61d070d input.cpp /^template<> void A::f(int);$/;" z prototype:A::f typeref:typename:int file: h input.cpp /^template<> void A::h(int) {}$/;" f class:A typeref:typename:void signature:(int) template:<> properties:scopespecialization,specialization +__anonc12ce61d080d input.cpp /^template<> void A::h(int) {}$/;" z function:A::h typeref:typename:int file: g1 input.cpp /^template void A::g1(T, X1) { }$/;" f class:A typeref:typename:void signature:(T,X1) template: properties:scopespecialization,specialization X1 input.cpp /^template void A::g1(T, X1) { }$/;" Z function:A::g1 typeref:meta:class +__anonc12ce61d090d input.cpp /^template void A::g1(T, X1) { }$/;" z function:A::g1 typeref:typename:T file: +__anonc12ce61d0a0d input.cpp /^template void A::g1(T, X1) { }$/;" z function:A::g1 typeref:typename:X1 file: g1 input.cpp /^template void A::g1(int, X1);$/;" p class:A typeref:typename:void file: signature:(int,X1) template: properties:scopespecialization,specialization X1 input.cpp /^template void A::g1(int, X1);$/;" Z prototype:A::g1 typeref:meta:class +__anonc12ce61d0b0d input.cpp /^template void A::g1(int, X1);$/;" z prototype:A::g1 typeref:typename:int file: +__anonc12ce61d0c0d input.cpp /^template void A::g1(int, X1);$/;" z prototype:A::g1 typeref:typename:X1 file: g2 input.cpp /^template<> void A::g2(int, char); \/\/ for X2 = char$/;" p class:A typeref:typename:void file: signature:(int,char) template:<> specialization: properties:scopespecialization,specialization +__anonc12ce61d0d0d input.cpp /^template<> void A::g2(int, char); \/\/ for X2 = char$/;" z prototype:A::g2 typeref:typename:int file: +__anonc12ce61d0e0d input.cpp /^template<> void A::g2(int, char); \/\/ for X2 = char$/;" z prototype:A::g2 typeref:typename:char file: g1 input.cpp /^template<> void A::g1(int, char);$/;" p class:A typeref:typename:void file: signature:(int,char) template:<> properties:scopespecialization,specialization +__anonc12ce61d0f0d input.cpp /^template<> void A::g1(int, char);$/;" z prototype:A::g1 typeref:typename:int file: +__anonc12ce61d100d input.cpp /^template<> void A::g1(int, char);$/;" z prototype:A::g1 typeref:typename:char file: m input.cpp /^template void m(X)$/;" f typeref:typename:void signature:(X) template: X input.cpp /^template void m(X)$/;" Z function:m typeref:meta:typename +__anonc12ce61d110d input.cpp /^template void m(X)$/;" z function:m typeref:typename:X file: m input.cpp /^template<> void m(int)$/;" f typeref:typename:void signature:(int) template:<> specialization: properties:specialization +__anonc12ce61d120d input.cpp /^template<> void m(int)$/;" z function:m typeref:typename:int file: m input.cpp /^template<> void m>(A a)$/;" f typeref:typename:void signature:(A a) template:<> specialization:> properties:specialization a input.cpp /^template<> void m>(A a)$/;" z function:m typeref:typename:A file: B input.cpp /^struct B { };$/;" s file: m input.cpp /^template<> void m(B)$/;" f typeref:typename:void signature:(B) template:<> specialization: properties:specialization +__anonc12ce61d130d input.cpp /^template<> void m(B)$/;" z function:m typeref:typename:B file: m input.cpp /^template<> void m(char)$/;" f typeref:typename:void signature:(char) template:<> properties:specialization +__anonc12ce61d140d input.cpp /^template<> void m(char)$/;" z function:m typeref:typename:char file: C input.cpp /^class C {};$/;" c file: template: T1 input.cpp /^template$/;" Z class:C typeref:meta:class T2 input.cpp /^template$/;" Z class:C typeref:meta:class diff --git a/parsers/cxx/cxx_parser.c b/parsers/cxx/cxx_parser.c index fe1b283673..a6c390b297 100644 --- a/parsers/cxx/cxx_parser.c +++ b/parsers/cxx/cxx_parser.c @@ -1478,9 +1478,11 @@ void cxxParserAnalyzeOtherStatement(void) } // prefer function. + CXXTypedVariableSet oParamInfo; + const bool bPrototypeParams = cxxTagKindEnabled(CXXTagKindPROTOTYPE) && cxxTagKindEnabled(CXXTagKindPARAMETER); check_function_signature: - if(cxxParserLookForFunctionSignature(g_cxx.pTokenChain,&oInfo,NULL)) + if(cxxParserLookForFunctionSignature(g_cxx.pTokenChain,&oInfo,bPrototypeParams?&oParamInfo:NULL)) { CXX_DEBUG_PRINT("Found function prototype"); @@ -1500,6 +1502,10 @@ void cxxParserAnalyzeOtherStatement(void) CXXToken * t = cxxTokenChainLast(g_cxx.pTokenChain); cxxParserSetEndLineForTagInCorkQueue (piCorkQueueIndex, t->iLineNumber); } + + if(bPrototypeParams) + cxxParserEmitFunctionParameterTags(&oParamInfo); + while(iScopesPushed > 0) { cxxScopePop(); diff --git a/parsers/cxx/cxx_parser_function.c b/parsers/cxx/cxx_parser_function.c index b93797ccfa..ba1f55f915 100644 --- a/parsers/cxx/cxx_parser_function.c +++ b/parsers/cxx/cxx_parser_function.c @@ -21,6 +21,7 @@ #include "debug.h" #include "keyword.h" #include "read.h" +#include "trashbox.h" #include @@ -1789,8 +1790,9 @@ int cxxParserExtractFunctionSignatureBeforeOpeningBracket( cxxTokenChainDestroyLast(g_cxx.pTokenChain); CXXTypedVariableSet oParamInfo; + bool bParams = cxxTagKindEnabled(CXXTagKindPARAMETER); - if(!cxxParserLookForFunctionSignature(g_cxx.pTokenChain,pInfo,&oParamInfo)) + if(!cxxParserLookForFunctionSignature(g_cxx.pTokenChain,pInfo,bParams?&oParamInfo:NULL)) { CXX_DEBUG_LEAVE_TEXT("No parenthesis found: no function"); return 0; @@ -1806,7 +1808,7 @@ int cxxParserExtractFunctionSignatureBeforeOpeningBracket( piCorkQueueIndex ); - if(cxxTagKindEnabled(CXXTagKindPARAMETER)) + if(bParams) cxxParserEmitFunctionParameterTags(&oParamInfo); CXX_DEBUG_LEAVE(); @@ -1868,6 +1870,10 @@ void cxxParserEmitFunctionParameterTags(CXXTypedVariableSet * pInfo) } tag->isFileScope = true; + + if (pInfo->uAnonymous & (0x1u << i)) + markTagExtraBit(tag, XTAG_ANONYMOUS); + cxxTagCommit(); if(pTypeName) @@ -2148,10 +2154,22 @@ bool cxxParserTokenChainLooksLikeFunctionParameterList( } } - if(pIdentifier) + if(pIdentifier || isXtagEnabled(XTAG_ANONYMOUS)) { pParamInfo->aTypeStarts[pParamInfo->uCount] = pStart; pParamInfo->aTypeEnds[pParamInfo->uCount] = t->pPrev; + pParamInfo->uAnonymous &= ~(0x1u << pParamInfo->uCount); + if(!pIdentifier) + { + /* This block handles parameter having no name lie + * + * void f(int *); + */ + pIdentifier = cxxTokenCreateAnonymousIdentifier(CXXTagKindPARAMETER); + pIdentifier->iLineNumber = t->pPrev->iLineNumber; + pIdentifier->oFilePosition = t->pPrev->oFilePosition; + pParamInfo->uAnonymous |= (0x1u << pParamInfo->uCount); + } pParamInfo->aIdentifiers[pParamInfo->uCount] = pIdentifier; pParamInfo->uCount++; @@ -2176,6 +2194,35 @@ bool cxxParserTokenChainLooksLikeFunctionParameterList( } else { pParamInfo = NULL; // reset so condition will be faster to check } + } else if (pParamInfo + && (pParamInfo->uCount < CXX_TYPED_VARIABLE_SET_ITEM_COUNT) + && (!cxxTokenIsKeyword(pStart, CXXKeywordVOID)) + && (!cxxTokenTypeIs(pStart,CXXTokenTypeMultipleDots)) + && isXtagEnabled(XTAG_ANONYMOUS)) { + /* This block handles parameter having no name like + * + * int f (int); + * + * In C language, you will find such a thing in a prototype. + * In C++ language, you will find it even in a function definition. + * + */ + CXXToken * pFakeStart = cxxTokenCopy(pStart); + CXXToken * pFakeId = cxxTokenCreateAnonymousIdentifier(CXXTagKindPARAMETER); + pFakeId->iLineNumber = pStart->iLineNumber; + pFakeId->oFilePosition = pStart->oFilePosition; + + pFakeStart->pNext = pFakeId; + pFakeId->pPrev = pFakeStart; + + pParamInfo->aTypeStarts[pParamInfo->uCount] = pFakeStart; + pParamInfo->aTypeEnds[pParamInfo->uCount] = pFakeId; + pParamInfo->aIdentifiers[pParamInfo->uCount] = pFakeId; + pParamInfo->uAnonymous |= (0x1u << pParamInfo->uCount); + pParamInfo->uCount++; + + PARSER_TRASH_BOX (pFakeStart, cxxTokenDestroy); + /* pFakeId may be destroyed via pParamInfo->aIdentifiers[i]. */ } if(cxxTokenTypeIs(t,CXXTokenTypeClosingParenthesis)) diff --git a/parsers/cxx/cxx_parser_internal.h b/parsers/cxx/cxx_parser_internal.h index 926f4d0096..45cc96870e 100644 --- a/parsers/cxx/cxx_parser_internal.h +++ b/parsers/cxx/cxx_parser_internal.h @@ -160,6 +160,8 @@ int cxxParserExtractFunctionSignatureBeforeOpeningBracket( int * piCorkQueueIndex ); +/* This must be smaller than (sizeof(unsigned int) * 8). + * See CXXTypedVariableSet::uAnonymous. */ #define CXX_TYPED_VARIABLE_SET_ITEM_COUNT 24 typedef struct _CXXTypedVariableSet @@ -175,6 +177,8 @@ typedef struct _CXXTypedVariableSet CXXToken * aTypeEnds[CXX_TYPED_VARIABLE_SET_ITEM_COUNT]; // The identifier tokens CXXToken * aIdentifiers[CXX_TYPED_VARIABLE_SET_ITEM_COUNT]; + + unsigned int uAnonymous; } CXXTypedVariableSet; bool cxxParserTokenChainLooksLikeFunctionParameterList( diff --git a/parsers/cxx/cxx_tag.c b/parsers/cxx/cxx_tag.c index fbc50cbe3c..2602d08713 100644 --- a/parsers/cxx/cxx_tag.c +++ b/parsers/cxx/cxx_tag.c @@ -645,7 +645,7 @@ int cxxTagCommit(void) enum CXXScopeType eScopeType = cxxScopeGetType(); - if(eScopeType == CXXScopeTypeFunction) + if(eScopeType == CXXScopeTypeFunction || eScopeType == CXXScopeTypePrototype) { // old ctags didn't do this, and --extra=+q is mainly // for backward compatibility so... diff --git a/parsers/cxx/cxx_token.c b/parsers/cxx/cxx_token.c index 92989467d0..547dc15073 100644 --- a/parsers/cxx/cxx_token.c +++ b/parsers/cxx/cxx_token.c @@ -110,6 +110,19 @@ void cxxTokenForceDestroy(CXXToken * t) eFree(t); } +CXXToken * cxxTokenCopy(CXXToken * pToken) +{ + CXXToken * pRetToken = cxxTokenCreate(); + pRetToken->iLineNumber = pToken->iLineNumber; + pRetToken->oFilePosition = pToken->oFilePosition; + pRetToken->eType = pToken->eType; + pRetToken->eKeyword = pToken->eKeyword; + pToken->bFollowedBySpace = pToken->bFollowedBySpace; + vStringCat(pRetToken->pszWord,pToken->pszWord); + + return pRetToken; +} + CXXToken * cxxTokenCreateKeyword(int iLineNumber,MIOPos oFilePosition,CXXKeyword eKeyword) { CXXToken * pToken = cxxTokenCreate(); diff --git a/parsers/cxx/cxx_token.h b/parsers/cxx/cxx_token.h index 05689ff327..b320f09735 100644 --- a/parsers/cxx/cxx_token.h +++ b/parsers/cxx/cxx_token.h @@ -91,6 +91,9 @@ typedef struct _CXXToken CXXToken * cxxTokenCreate(void); void cxxTokenDestroy(CXXToken * t); +// A shortcut for quickly creating a fake token. +CXXToken * cxxTokenCopy(CXXToken *pToken); + // A shortcut for quickly creating keyword tokens. CXXToken * cxxTokenCreateKeyword(int iLineNumber,MIOPos oFilePosition,CXXKeyword eKeyword);