diff --git a/Units/parser-cxx.r/signature.cpp.d/expected.tags b/Units/parser-cxx.r/signature.cpp.d/expected.tags index d924d88409..c6aa768a89 100644 --- a/Units/parser-cxx.r/signature.cpp.d/expected.tags +++ b/Units/parser-cxx.r/signature.cpp.d/expected.tags @@ -2,3 +2,10 @@ BAR::bar input.cpp /^char *BAR::bar (char *c, double d[]) const {}$/;" f class:B bar input.cpp /^char *BAR::bar (char *c, double d[]) const {}$/;" f class:BAR typeref:typename:char * signature:(char * c,double d[]) const foo input.cpp /^void foo (int a, char b) {}$/;" f typeref:typename:void signature:(int a,char b) foobar input.cpp /^void foobar __ARGS ((int a, char b));$/;" p typeref:typename:void file: signature:(int a,char b) +params1 input.cpp /^void params1(const char * c = "blah");$/;" p typeref:typename:void file: signature:(const char * c="blah") +params2 input.cpp /^void params2(char x = 'x');$/;" p typeref:typename:void file: signature:(char x='x') +params3 input.cpp /^void params3(char x = ' ');$/;" p typeref:typename:void file: signature:(char x=' ') +params4 input.cpp /^void params4(char x = ',');$/;" p typeref:typename:void file: signature:(char x=',') +params5 input.cpp /^void params5(char x = '\\n');$/;" p typeref:typename:void file: signature:(char x='\\n') +params6 input.cpp /^void params6(char x = '\\t',int n = 10,const char * v = "a string with\\na newline");$/;" p typeref:typename:void file: signature:(char x='\\t',int n=10,const char * v="a string with\\na newline") +params7 input.cpp /^void params7(char x = ' ', \/\/ This is tab char$/;" p typeref:typename:void file: signature:(char x='\t',float p=3.14,const char * v="a string with a tab char:\t") diff --git a/Units/parser-cxx.r/signature.cpp.d/input.cpp b/Units/parser-cxx.r/signature.cpp.d/input.cpp index 91f4e1803e..d843ac08d9 100644 --- a/Units/parser-cxx.r/signature.cpp.d/input.cpp +++ b/Units/parser-cxx.r/signature.cpp.d/input.cpp @@ -8,3 +8,15 @@ void foo (int a, char b) {} char *BAR::bar (char *c, double d[]) const {} void foobar __ARGS ((int a, char b)); + + +void params1(const char * c = "blah"); +void params2(char x = 'x'); +void params3(char x = ' '); +void params4(char x = ','); +void params5(char x = '\n'); +void params6(char x = '\t',int n = 10,const char * v = "a string with\na newline"); +void params7(char x = ' ', // This is tab char + float p = 3.14, + const char * v = "a string with a tab char: " + ); diff --git a/main/field.c b/main/field.c index 941ad27fde..7e32154e1e 100644 --- a/main/field.c +++ b/main/field.c @@ -46,6 +46,7 @@ static const char *renderFieldInput (const tagEntryInfo *const tag, const char * static const char *renderFieldInputNoEscape (const tagEntryInfo *const tag, const char *value, vString* b); static const char *renderFieldCompactInputLine (const tagEntryInfo *const tag, const char *value, vString* b); static const char *renderFieldSignature (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldSignatureNoEscape (const tagEntryInfo *const tag, const char *value, vString* b); static const char *renderFieldScope (const tagEntryInfo *const tag, const char *value, vString* b); static const char *renderFieldScopeNoEscape (const tagEntryInfo *const tag, const char *value, vString* b); static const char *renderFieldTyperef (const tagEntryInfo *const tag, const char *value, vString* b); @@ -68,6 +69,7 @@ static const char *renderFieldEnd (const tagEntryInfo *const tag, const char *va static bool hasWhitespaceInName (const tagEntryInfo *const tag, const char *value); static bool hasWhitespaceInInput (const tagEntryInfo *const tag, const char*value); static bool hasWhitespaceInFieldScope (const tagEntryInfo *const tag, const char *value); +static bool hasWhitespaceInSignature (const tagEntryInfo *const tag, const char *value); static bool isLanguageFieldAvailable (const tagEntryInfo *const tag); static bool isTyperefFieldAvailable (const tagEntryInfo *const tag); @@ -162,11 +164,12 @@ static fieldDefinition fieldDefinitionsExuberant [] = { "Line number of tag definition", FIELDTYPE_INTEGER, renderFieldLineNumber), - DEFINE_FIELD_FULL ('S', "signature", false, + DEFINE_FIELD_FULL ('S', "signature", false, "Signature of routine (e.g. prototype or parameter list)", isSignatureFieldAvailable, FIELDTYPE_STRING, - renderFieldSignature, NULL, NULL), + renderFieldSignature, renderFieldSignatureNoEscape, + hasWhitespaceInSignature), DEFINE_FIELD_FULL ('s', NULL, true, "Scope of tag definition (`p' can be used for printing its kind)", NULL, @@ -472,6 +475,18 @@ static const char *renderFieldSignature (const tagEntryInfo *const tag, const ch tag, b); } +static const char *renderFieldSignatureNoEscape (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b) +{ + return renderAsIs (b, WITH_DEFUALT_VALUE (tag->extensionFields.signature)); +} + +static bool hasWhitespaceInSignature (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED) +{ + return (tag->extensionFields.signature && strpbrk(tag->extensionFields.signature, " \t")) + ? true + : false; +} + static const char *renderFieldScope (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b) { const char* scope; diff --git a/main/vstring.h b/main/vstring.h index 5ac421d43e..58c4ec6f5e 100644 --- a/main/vstring.h +++ b/main/vstring.h @@ -102,4 +102,11 @@ CTAGS_INLINE void vStringPut (vString *const string, const int c) string->buffer [++string->length] = '\0'; } +CTAGS_INLINE void vStringPutWithLimit (vString *const string, const int c, + unsigned int maxlen) +{ + if (vStringLength (string) < maxlen || maxlen == 0) + vStringPut (string, c); +} + #endif /* CTAGS_MAIN_VSTRING_H */ diff --git a/parsers/cpreprocessor.c b/parsers/cpreprocessor.c index 3f9f367fba..744aad280d 100644 --- a/parsers/cpreprocessor.c +++ b/parsers/cpreprocessor.c @@ -77,6 +77,9 @@ typedef struct sCppState { int * ungetPointer; /* the current unget char: points in the middle of the buffer */ int ungetDataSize; /* the number of valid unget characters in the buffer */ + /* the contents of the last SYMBOL_CHAR or SYMBOL_STRING */ + vString * charOrStringContents; + bool resolveRequired; /* must resolve if/else/elif/endif branch */ bool hasAtLiteralStrings; /* supports @"c:\" strings */ bool hasCxxRawLiteralStrings; /* supports R"xxx(...)xxx" strings */ @@ -169,6 +172,7 @@ static cppState Cpp = { .ungetBufferSize = 0, .ungetPointer = NULL, .ungetDataSize = 0, + .charOrStringContents = NULL, .resolveRequired = false, .hasAtLiteralStrings = false, .hasCxxRawLiteralStrings = false, @@ -237,6 +241,9 @@ static void cppInitCommon(langType clientLang, Cpp.ungetBuffer = NULL; Cpp.ungetPointer = NULL; + CXX_DEBUG_ASSERT(!Cpp.charOrStringContents,"This string should be null when CPP is not initialized"); + Cpp.charOrStringContents = vStringNew(); + Cpp.resolveRequired = false; Cpp.hasAtLiteralStrings = hasAtLiteralStrings; Cpp.hasCxxRawLiteralStrings = hasCxxRawLiteralStrings; @@ -316,6 +323,12 @@ extern void cppTerminate (void) Cpp.ungetBuffer = NULL; } + if(Cpp.charOrStringContents) + { + vStringDelete(Cpp.charOrStringContents); + Cpp.charOrStringContents = NULL; + } + Cpp.clientLang = LANG_IGNORE; } @@ -982,6 +995,12 @@ static int skipOverDComment (void) return c; } +const vString * cppGetLastCharOrStringContents (void) +{ + CXX_DEBUG_ASSERT(Cpp.charOrStringContents,"Shouldn't be called when CPP is not initialized"); + return Cpp.charOrStringContents; +} + /* Skips to the end of a string, returning a special character to * symbolically represent a generic string. */ @@ -989,12 +1008,21 @@ static int skipToEndOfString (bool ignoreBackslash) { int c; + vStringClear(Cpp.charOrStringContents); + while ((c = cppGetcFromUngetBufferOrFile ()) != EOF) { if (c == BACKSLASH && ! ignoreBackslash) - cppGetcFromUngetBufferOrFile (); /* throw away next character, too */ + { + vStringPutWithLimit (Cpp.charOrStringContents, c, 1024); + c = cppGetcFromUngetBufferOrFile (); /* throw away next character, too */ + if (c != EOF) + vStringPutWithLimit (Cpp.charOrStringContents, c, 1024); + } else if (c == DOUBLE_QUOTE) break; + else + vStringPutWithLimit (Cpp.charOrStringContents, c, 1024); } return STRING_SYMBOL; /* symbolic representation of string */ } @@ -1052,16 +1080,23 @@ static int skipToEndOfCxxRawLiteralString (void) * special character to symbolically represent a generic character. * Also detects Vera numbers that include a base specifier (ie. 'b1010). */ -static int skipToEndOfChar (void) +static int skipToEndOfChar () { int c; int count = 0, veraBase = '\0'; + vStringClear(Cpp.charOrStringContents); + while ((c = cppGetcFromUngetBufferOrFile ()) != EOF) { ++count; if (c == BACKSLASH) - cppGetcFromUngetBufferOrFile (); /* throw away next character, too */ + { + vStringPutWithLimit (Cpp.charOrStringContents, c, 10); + c = cppGetcFromUngetBufferOrFile (); /* throw away next character, too */ + if (c != EOF) + vStringPutWithLimit (Cpp.charOrStringContents, c, 10); + } else if (c == SINGLE_QUOTE) break; else if (c == NEWLINE) @@ -1072,13 +1107,20 @@ static int skipToEndOfChar (void) else if (Cpp.hasSingleQuoteLiteralNumbers) { if (count == 1 && strchr ("DHOB", toupper (c)) != NULL) + { veraBase = c; + vStringPutWithLimit (Cpp.charOrStringContents, c, 10); + } else if (veraBase != '\0' && ! isalnum (c)) { cppUngetc (c); break; } + else + vStringPutWithLimit (Cpp.charOrStringContents, c, 10); } + else + vStringPutWithLimit (Cpp.charOrStringContents, c, 10); } return CHAR_SYMBOL; /* symbolic representation of character */ } diff --git a/parsers/cpreprocessor.h b/parsers/cpreprocessor.h index 76de33384e..b237ba5d11 100644 --- a/parsers/cpreprocessor.h +++ b/parsers/cpreprocessor.h @@ -89,6 +89,7 @@ extern void cppEndStatement (void); extern void cppUngetc (const int c); extern void cppUngetString(const char * string,int len); extern int cppGetc (void); +extern const vString * cppGetLastCharOrStringContents (void); /* notify the external parser state for the purpose of conditional branch choice. The CXX parser stores the block level here. */ diff --git a/parsers/cxx/cxx_parser_tokenizer.c b/parsers/cxx/cxx_parser_tokenizer.c index e15b1e707d..d5991929f8 100644 --- a/parsers/cxx/cxx_parser_tokenizer.c +++ b/parsers/cxx/cxx_parser_tokenizer.c @@ -28,11 +28,8 @@ static void cxxParserSkipToNonWhiteSpace(void) { - if(!cppIsspace(g_cxx.iChar)) - return; - do + while(cppIsspace(g_cxx.iChar)) g_cxx.iChar = cppGetc(); - while(cppIsspace(g_cxx.iChar)); } enum CXXCharType @@ -1366,6 +1363,7 @@ bool cxxParserParseNextToken(void) { t->eType = CXXTokenTypeStringConstant; vStringPut(t->pszWord,'"'); + vStringCat(t->pszWord,cppGetLastCharOrStringContents()); vStringPut(t->pszWord,'"'); g_cxx.iChar = cppGetc(); t->bFollowedBySpace = cppIsspace(g_cxx.iChar); @@ -1413,6 +1411,7 @@ bool cxxParserParseNextToken(void) { t->eType = CXXTokenTypeCharacterConstant; vStringPut(t->pszWord,'\''); + vStringCat(t->pszWord,cppGetLastCharOrStringContents()); vStringPut(t->pszWord,'\''); g_cxx.iChar = cppGetc(); t->bFollowedBySpace = cppIsspace(g_cxx.iChar);