Skip to content

Commit

Permalink
Merge pull request #1119 from pragmaware/fix-bug-1012
Browse files Browse the repository at this point in the history
CXX: Fix bug #1012
  • Loading branch information
pragmaware committed Sep 16, 2016
2 parents ff2e6d9 + 9cd2a6f commit 38aca09
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 14 deletions.
21 changes: 12 additions & 9 deletions Units/parser-cxx.r/functions.cpp.d/expected.tags
@@ -1,19 +1,21 @@
f01 input.cpp /^int f01(int f01a01,int f01a02)$/;" f typeref:typename:int signature:(int f01a01,int f01a02) end:33
f01 input.cpp /^int f01(int f01a01,int f01a02)$/;" f typeref:typename:int signature:(int f01a01,int f01a02) end:34
f01a01 input.cpp /^int f01(int f01a01,int f01a02)$/;" z function:f01 typeref:typename:int file:
f01a02 input.cpp /^int f01(int f01a01,int f01a02)$/;" z function:f01 typeref:typename:int file:
f02 input.cpp /^unsigned short int * f02(unsigned int & f02a01,...)$/;" f typeref:typename:unsigned short int * signature:(unsigned int & f02a01,...) end:38
f02 input.cpp /^unsigned short int * f02(unsigned int & f02a01,...)$/;" f typeref:typename:unsigned short int * signature:(unsigned int & f02a01,...) end:39
f02a01 input.cpp /^unsigned short int * f02(unsigned int & f02a01,...)$/;" z function:f02 typeref:typename:unsigned int & file:
f03 input.cpp /^auto f03(const int & f03a01,void * f03a02) -> const int &$/;" f typeref:typename:const int & signature:(const int & f03a01,void * f03a02) end:43
f03 input.cpp /^auto f03(const int & f03a01,void * f03a02) -> const int &$/;" f typeref:typename:const int & signature:(const int & f03a01,void * f03a02) end:44
f03a01 input.cpp /^auto f03(const int & f03a01,void * f03a02) -> const int &$/;" z function:f03 typeref:typename:const int & file:
f03a02 input.cpp /^auto f03(const int & f03a01,void * f03a02) -> const int &$/;" z function:f03 typeref:typename:void * file:
f04 input.cpp /^auto f04() -> int (*)(int)$/;" f typeref:typename:int (*)(int) signature:() end:48
f05 input.cpp /^static inline std::string f05(const int *** f05a01)$/;" f typeref:typename:std::string file: signature:(const int *** f05a01) end:53
f04 input.cpp /^auto f04() -> int (*)(int)$/;" f typeref:typename:int (*)(int) signature:() end:49
f05 input.cpp /^static inline std::string f05(const int *** f05a01)$/;" f typeref:typename:std::string file: signature:(const int *** f05a01) end:54
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)
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:58
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 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:63
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:
f08 input.cpp /^void (*f08(void (*)(int *f08a01)))(int *)$/;" f signature:(void (*)(int * f08a01)) end:69
f08a01 input.cpp /^void (*f08(void (*)(int *f08a01)))(int *)$/;" z function:f08 typeref:typename:void (*)(int *) file:
p01 input.cpp /^int p01(int p01a01,int p01a02);$/;" p typeref:typename:int file: signature:(int p01a01,int p01a02)
p02 input.cpp /^unsigned short int * p02(unsigned int & p02a01,...);$/;" p typeref:typename:unsigned short int * file: signature:(unsigned int & p02a01,...)
p03 input.cpp /^auto p03(const int & p03a01,void * p03a02) -> const int &;$/;" p typeref:typename:const int & file: signature:(const int & p03a01,void * p03a02)
Expand All @@ -22,7 +24,8 @@ p05 input.cpp /^static std::string p05(const int *** p05a01);$/;" p typeref:type
p06 input.cpp /^ auto p06(n01::c01 && p06a01) -> type01 *;$/;" p namespace:n01::n02 typeref:typename:type01 * file: signature:(n01::c01 && p06a01)
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)
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),...)
t01 input.cpp /^template <typename T> std::unique_ptr<T> t01(T && t01a01)$/;" f typeref:typename:std::unique_ptr<T> signature:(T && t01a01) end:69
p08 input.cpp /^void (*p08(void (*)(int *p08a01)))(int *);$/;" p file: signature:(void (*)(int * p08a01))
t01 input.cpp /^template <typename T> std::unique_ptr<T> t01(T && t01a01)$/;" f typeref:typename:std::unique_ptr<T> signature:(T && t01a01) end:75
t01a01 input.cpp /^template <typename T> std::unique_ptr<T> t01(T && t01a01)$/;" z function:t01 typeref:typename:T && file:
t02 input.cpp /^template <typename T> auto t02(T && t02a01) -> std::unique_ptr<T>$/;" f typeref:typename:std::unique_ptr<T> signature:(T && t02a01) end:74
t02 input.cpp /^template <typename T> auto t02(T && t02a01) -> std::unique_ptr<T>$/;" f typeref:typename:std::unique_ptr<T> signature:(T && t02a01) end:80
t02a01 input.cpp /^template <typename T> auto t02(T && t02a01) -> std::unique_ptr<T>$/;" z function:t02 typeref:typename:T && file:
6 changes: 6 additions & 0 deletions Units/parser-cxx.r/functions.cpp.d/input.cpp
Expand Up @@ -25,6 +25,7 @@ auto p04() -> int (*)(int);
static std::string p05(const int *** p05a01);
auto n01::n02::p06(n01::c01 && p06a01) -> n01::n02::type01 *;
unsigned int p07(int (*p07a01)(int * x1,int x2),...);
void (*p08(void (*)(int *p08a01)))(int *);

// Valid function declarations
int f01(int f01a01,int f01a02)
Expand Down Expand Up @@ -62,6 +63,11 @@ unsigned int f07(int (*f07a01)(int * x1,int x2),...)
return 0;
}

void (*f08(void (*)(int *f08a01)))(int *)
{
return 0;
}

// Valid function templates
template <typename T> std::unique_ptr<T> t01(T && t01a01)
{
Expand Down
63 changes: 60 additions & 3 deletions parsers/cxx/cxx_parser_function.c
Expand Up @@ -499,6 +499,9 @@ boolean cxxParserTokenChainLooksLikeConstructorParameterSet(
// cxxParserTokenChainLooksLikeFunctionParameterList() which will eventually
// fill it up.
//
// FIXME:
// WS_DLL_PUBLIC void (*except_unhandled_catcher(void (*)(except_t *)))(except_t *);
//
boolean cxxParserLookForFunctionSignature(
CXXTokenChain * pChain,
CXXFunctionSignatureInfo * pInfo,
Expand Down Expand Up @@ -537,6 +540,7 @@ boolean cxxParserLookForFunctionSignature(
CXXToken * pIdentifierEnd = NULL;
CXXToken * pTopLevelParenthesis = NULL;

boolean bTryToExtractType = TRUE;
boolean bStopScanning = FALSE;

while(pToken)
Expand Down Expand Up @@ -680,17 +684,65 @@ boolean cxxParserLookForFunctionSignature(

CXX_DEBUG_PRINT("Found parenthesis chain: check for identifier");

// parentheses at position 1 they are very likely to be macro invocations...
// but we still handle them in case we find nothing else
// parentheses at position 1 they are likely to be macro invocations...
// but we still handle them in case we find nothing else.

// must have an identifier before (this excludes things like __attribute__
// and declspec which are marked as keywords)

// FIXME: Check for double parenthesis chain: a function returning a function.

if(cxxTokenTypeIs(pToken->pPrev,CXXTokenTypeIdentifier))
{
// identifier before
CXX_DEBUG_PRINT("Got identifier before");
pIdentifierStart = pToken->pPrev;
pIdentifierEnd = pToken->pPrev;
} else if(
// check for double parenthesis, keep functions returning function pointers
// discard everything else.
//
// Possible cases:
// ret type (*variable)(params) <-- function pointer
// ret type (* const (variable[4]))(params) <-- function pointer
// ret type (*function_name())() <-- function returning function pointer
pToken->pNext &&
cxxTokenTypeIs(pToken->pNext,CXXTokenTypeParenthesisChain) &&
// the next parenthesis must look like a function parameter list (return function)
cxxParserTokenChainLooksLikeFunctionParameterList(
pToken->pNext->pChain,
NULL
) &&
// look for the identifier
(pIdentifierStart = cxxTokenChainFirstPossiblyNestedTokenOfType(
pToken->pChain,
CXXTokenTypeIdentifier
))
)
{
// Now pIdentifierStart points at the innermost identifier
// Check if it's followed by a parameter list
if(
pIdentifierStart->pNext &&
cxxTokenTypeIs(pIdentifierStart->pNext,CXXTokenTypeParenthesisChain) &&
cxxParserTokenChainLooksLikeFunctionParameterList(
pIdentifierStart->pNext->pChain,
NULL
)
)
{
CXX_DEBUG_PRINT("Looks like a function returning a function pointer");
pIdentifierEnd = pIdentifierStart;
pToken = pIdentifierStart->pNext; // point it to the correct parenthesis
bStopScanning = TRUE;
bTryToExtractType = FALSE; // don't attempt to extract type, it's too hard.
} else {
// Looks more like a function pointer or something else we can't figure out
CXX_DEBUG_LEAVE_TEXT(
"Does not look like a function returning a function pointer"
);
return FALSE;
}
} else if(
pToken->pPrev->pPrev &&
cxxTokenTypeIs(pToken->pPrev,CXXTokenTypeGreaterThanSign)
Expand Down Expand Up @@ -722,6 +774,11 @@ boolean cxxParserLookForFunctionSignature(
}
}

CXX_DEBUG_ASSERT(
cxxTokenTypeIs(pToken,CXXTokenTypeParenthesisChain),
"Must have found a parenthesis chain here"
);

// looks almost fine

CXXToken * pInner = cxxTokenChainAt(pToken->pChain,1);
Expand Down Expand Up @@ -921,7 +978,7 @@ boolean cxxParserLookForFunctionSignature(

// Check return type
pToken = pInfo->pScopeStart ? pInfo->pScopeStart : pInfo->pIdentifierStart;
if(pToken->pPrev)
if(pToken->pPrev && bTryToExtractType)
{
CXXToken * pParenthesisOrConst = pInfo->pSignatureConst ?
pInfo->pSignatureConst : pInfo->pParenthesis;
Expand Down
14 changes: 12 additions & 2 deletions parsers/cxx/cxx_parser_variable.c
Expand Up @@ -203,16 +203,26 @@ boolean cxxParserExtractVariableDeclarations(CXXTokenChain * pChain,unsigned int
{
// At a parenthesis chain we need some additional checks.
if(
// check for function pointers.
// Possible cases:
// ret type (*variable)(params)
// ret type (* const (variable[4]))(params)
t->pNext &&
cxxTokenTypeIs(t->pNext,CXXTokenTypeParenthesisChain) &&
cxxParserTokenChainLooksLikeFunctionParameterList(
t->pNext->pChain,
NULL
) &&
(pIdentifier = cxxTokenChainLastPossiblyNestedTokenOfType(
(pIdentifier = cxxTokenChainFirstPossiblyNestedTokenOfType(
t->pChain,
CXXTokenTypeIdentifier
))
)) &&
// Discard function declarations with function return types
// like void (*A(B))(C);
(
(!pIdentifier->pNext) ||
(!cxxTokenTypeIs(pIdentifier->pNext,CXXTokenTypeParenthesisChain))
)
)
{
// A function pointer.
Expand Down
27 changes: 27 additions & 0 deletions parsers/cxx/cxx_token_chain.c
Expand Up @@ -634,6 +634,33 @@ CXXToken * cxxTokenChainLastPossiblyNestedTokenOfType(

}

CXXToken * cxxTokenChainFirstPossiblyNestedTokenOfType(
CXXTokenChain * tc,
unsigned int uTokenTypes
)
{
if(!tc)
return NULL;
CXXToken * t = tc->pHead;
while(t)
{
if(t->eType & uTokenTypes)
return t;
if(t->eType == CXXTokenTypeParenthesisChain)
{
CXXToken * tmp = cxxTokenChainFirstPossiblyNestedTokenOfType(
t->pChain,
uTokenTypes
);
if(tmp)
return tmp;
}
t = t->pNext;
}
return NULL;

}


CXXToken * cxxTokenChainFirstTokenNotOfType(
CXXTokenChain * tc,
Expand Down
7 changes: 7 additions & 0 deletions parsers/cxx/cxx_token_chain.h
Expand Up @@ -75,6 +75,13 @@ CXXToken * cxxTokenChainLastPossiblyNestedTokenOfType(
unsigned int uTokenTypes
);

// Find the first token with one of the specified types. Look also
// in nested () chains (only (), not [], {}...)
CXXToken * cxxTokenChainFirstPossiblyNestedTokenOfType(
CXXTokenChain * tc,
unsigned int uTokenTypes
);

// Find the first token with type that is not one of the specified types
CXXToken * cxxTokenChainFirstTokenNotOfType(
CXXTokenChain * tc,
Expand Down

0 comments on commit 38aca09

Please sign in to comment.