Index: llvm/test/tools/llvm-cxxfilt/delimiters.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-cxxfilt/delimiters.test @@ -0,0 +1,62 @@ +RUN: echo ",,_Z3Foo!" \ +RUN: "_Z3Foo\"" \ +RUN: "_Z3Foo\"" \ +RUN: "_Z3Foo#" \ +RUN: "_Z3Foo%" \ +RUN: "_Z3Foo&" \ +RUN: "_Z3Foo'" \ +RUN: "_Z3Foo(" \ +RUN: "_Z3Foo)" \ +RUN: "_Z3Foo*" \ +RUN: "_Z3Foo+" \ +RUN: "_Z3Foo," \ +RUN: "_Z3Foo-" \ +RUN: "_Z3Foo/" \ +RUN: "_Z3Foo:" \ +RUN: "_Z3Foo;" \ +RUN: "_Z3Foo<" \ +RUN: "_Z3Foo=" \ +RUN: "_Z3Foo>" \ +RUN: "_Z3Foo?" \ +RUN: "_Z3Foo@" \ +RUN: "_Z3Foo[" \ +RUN: "_Z3Foo\\" \ +RUN: "_Z3Foo]" \ +RUN: "_Z3Foo^" \ +RUN: "_Z3Foo\`" \ +RUN: "_Z3Foo{" \ +RUN: "_Z3Foo|" \ +RUN: "_Z3Foo}" \ +RUN: "_Z3Foo~,," \ +RUN: '_Z3Foo$ ._Z3Foo' | llvm-cxxfilt | FileCheck %s + +CHECK: ,,Foo! +CHECK: Foo" +CHECK: Foo# +CHECK: Foo% +CHECK: Foo& +CHECK: Foo' +CHECK: Foo( +CHECK: Foo) +CHECK: Foo* +CHECK: Foo+ +CHECK: Foo, +CHECK: Foo- +CHECK: Foo/ +CHECK: Foo: +CHECK: Foo; +CHECK: Foo< +CHECK: Foo= +CHECK: Foo> +CHECK: Foo? +CHECK: Foo@ +CHECK: Foo[ +CHECK: Foo\ +CHECK: Foo] +CHECK: Foo^ +CHECK: Foo` +CHECK: Foo{ +CHECK: Foo| +CHECK: Foo} +CHECK: Foo~,, +CHECK: _Z3Foo$ ._Z3Foo Index: llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp =================================================================== --- llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp +++ llvm/tools/llvm-cxxfilt/llvm-cxxfilt.cpp @@ -78,19 +78,52 @@ return Result; } +// Split 'Source' on any character that fails to pass 'IsLegalChar'. The +// returned vector consists of pairs where 'first' is the delimited word, and +// 'second' are the delimiters following that word. +static void SplitStringDelims( + StringRef Source, + SmallVectorImpl> &OutFragments, + function_ref IsLegalChar) { + // The beginning of the string. + StringRef::iterator First = Source.begin(); + + // Obtain any leading delimiters. + StringRef::iterator Start = + std::find_if(Source.begin(), Source.end(), IsLegalChar); + if (Start != First) + OutFragments.push_back({"", Source.slice(0, Start - First)}); + + // Capture each word and the delimiters following that word. + while (Start != Source.end()) { + Start = std::find_if(Start, Source.end(), IsLegalChar); + StringRef::iterator End = + std::find_if_not(Start, Source.end(), IsLegalChar); + StringRef::iterator DEnd = std::find_if(End, Source.end(), IsLegalChar); + OutFragments.push_back({Source.slice(Start - First, End - First), + Source.slice(End - First, DEnd - First)}); + Start = DEnd; + } +} + +// This returns true if 'C' is a character that can show up in an +// Itanium-mangled string. +static bool IsLegalItaniumChar(char C) { + // Itanium CXX ABI [External Names]p5.1.1: + // '$' and '.' in mangled names are reserved for private implementations. + return isalnum(C) || C == '.' || C == '$' || C == '_'; +} + // If 'Split' is true, then 'Mangled' is broken into individual words and each // word is demangled. Otherwise, the entire string is treated as a single // mangled item. The result is output to 'OS'. static void demangleLine(llvm::raw_ostream &OS, StringRef Mangled, bool Split) { std::string Result; if (Split) { - SmallVector Words; - SplitString(Mangled, Words); - for (auto Word : Words) - Result += demangle(OS, Word) + ' '; - // Remove the trailing space character. - if (Result.back() == ' ') - Result.pop_back(); + SmallVector, 16> Words; + SplitStringDelims(Mangled, Words, IsLegalItaniumChar); + for (auto &Word : Words) + Result += demangle(OS, Word.first) + Word.second.str(); } else Result = demangle(OS, Mangled); OS << Result << '\n';