Skip to content

Commit 0875195

Browse files
committed
[llvm][ItaniumDemangle] Add function name location tracking
1 parent 491d3df commit 0875195

File tree

10 files changed

+635
-49
lines changed

10 files changed

+635
-49
lines changed

libcxxabi/src/demangle/ItaniumDemangle.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,11 +851,13 @@ class FunctionType final : public Node {
851851
// by printing out the return types's left, then print our parameters, then
852852
// finally print right of the return type.
853853
void printLeft(OutputBuffer &OB) const override {
854+
auto Scoped = OB.enterFunctionTypePrinting();
854855
Ret->printLeft(OB);
855856
OB += " ";
856857
}
857858

858859
void printRight(OutputBuffer &OB) const override {
860+
auto Scoped = OB.enterFunctionTypePrinting();
859861
OB.printOpen();
860862
Params.printWithComma(OB);
861863
OB.printClose();
@@ -971,18 +973,32 @@ class FunctionEncoding final : public Node {
971973
const Node *getName() const { return Name; }
972974

973975
void printLeft(OutputBuffer &OB) const override {
976+
// Nested FunctionEncoding parsing can happen with following productions:
977+
// * <local-name>
978+
// * <expr-primary>
979+
auto Scoped = OB.enterFunctionTypePrinting();
980+
974981
if (Ret) {
975982
Ret->printLeft(OB);
976983
if (!Ret->hasRHSComponent(OB))
977984
OB += " ";
978985
}
986+
987+
OB.FunctionInfo.updateScopeStart(OB);
988+
979989
Name->print(OB);
980990
}
981991

982992
void printRight(OutputBuffer &OB) const override {
993+
auto Scoped = OB.enterFunctionTypePrinting();
994+
OB.FunctionInfo.finalizeStart(OB);
995+
983996
OB.printOpen();
984997
Params.printWithComma(OB);
985998
OB.printClose();
999+
1000+
OB.FunctionInfo.finalizeArgumentEnd(OB);
1001+
9861002
if (Ret)
9871003
Ret->printRight(OB);
9881004

@@ -1005,6 +1021,8 @@ class FunctionEncoding final : public Node {
10051021
OB += " requires ";
10061022
Requires->print(OB);
10071023
}
1024+
1025+
OB.FunctionInfo.finalizeEnd(OB);
10081026
}
10091027
};
10101028

@@ -1072,7 +1090,9 @@ struct NestedName : Node {
10721090
void printLeft(OutputBuffer &OB) const override {
10731091
Qual->print(OB);
10741092
OB += "::";
1093+
OB.FunctionInfo.updateScopeEnd(OB);
10751094
Name->print(OB);
1095+
OB.FunctionInfo.updateBasenameEnd(OB);
10761096
}
10771097
};
10781098

@@ -1633,6 +1653,7 @@ struct NameWithTemplateArgs : Node {
16331653

16341654
void printLeft(OutputBuffer &OB) const override {
16351655
Name->print(OB);
1656+
OB.FunctionInfo.updateBasenameEnd(OB);
16361657
TemplateArgs->print(OB);
16371658
}
16381659
};

libcxxabi/src/demangle/Utility.cpp

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
//===--- Utility.cpp ------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Provide some utility classes for use in the demangler.
10+
// There are two copies of this file in the source tree. The one in libcxxabi
11+
// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
12+
// the copy. See README.txt for more details.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
16+
#include "Utility.h"
17+
#include "DemangleConfig.h"
18+
19+
DEMANGLE_NAMESPACE_BEGIN
20+
21+
bool FunctionNameInfo::startedPrintingArguments() const {
22+
return ArgumentLocs.first > 0;
23+
}
24+
25+
bool FunctionNameInfo::shouldTrack(OutputBuffer &OB) const {
26+
if (!OB.isPrintingTopLevelFunctionType())
27+
return false;
28+
29+
if (OB.isGtInsideTemplateArgs())
30+
return false;
31+
32+
if (startedPrintingArguments())
33+
return false;
34+
35+
return true;
36+
}
37+
38+
bool FunctionNameInfo::canFinalize(OutputBuffer &OB) const {
39+
if (!OB.isPrintingTopLevelFunctionType())
40+
return false;
41+
42+
if (OB.isGtInsideTemplateArgs())
43+
return false;
44+
45+
if (!startedPrintingArguments())
46+
return false;
47+
48+
return true;
49+
}
50+
51+
void FunctionNameInfo::updateBasenameEnd(OutputBuffer &OB) {
52+
if (!shouldTrack(OB))
53+
return;
54+
55+
BasenameLocs.second = OB.getCurrentPosition();
56+
}
57+
58+
void FunctionNameInfo::updateScopeStart(OutputBuffer &OB) {
59+
if (!shouldTrack(OB))
60+
return;
61+
62+
ScopeLocs.first = OB.getCurrentPosition();
63+
}
64+
65+
void FunctionNameInfo::updateScopeEnd(OutputBuffer &OB) {
66+
if (!shouldTrack(OB))
67+
return;
68+
69+
ScopeLocs.second = OB.getCurrentPosition();
70+
}
71+
72+
void FunctionNameInfo::finalizeArgumentEnd(OutputBuffer &OB) {
73+
if (!canFinalize(OB))
74+
return;
75+
76+
OB.FunctionInfo.ArgumentLocs.second = OB.getCurrentPosition();
77+
}
78+
79+
void FunctionNameInfo::finalizeStart(OutputBuffer &OB) {
80+
if (!shouldTrack(OB))
81+
return;
82+
83+
OB.FunctionInfo.ArgumentLocs.first = OB.getCurrentPosition();
84+
85+
// If nothing has set the end of the basename yet (for example when
86+
// printing templates), then the beginning of the arguments is the end of
87+
// the basename.
88+
if (BasenameLocs.second == 0)
89+
OB.FunctionInfo.BasenameLocs.second = OB.getCurrentPosition();
90+
91+
DEMANGLE_ASSERT(!shouldTrack(OB), "");
92+
DEMANGLE_ASSERT(canFinalize(OB), "");
93+
}
94+
95+
void FunctionNameInfo::finalizeEnd(OutputBuffer &OB) {
96+
if (!canFinalize(OB))
97+
return;
98+
99+
if (ScopeLocs.first > OB.FunctionInfo.ScopeLocs.second)
100+
ScopeLocs.second = OB.FunctionInfo.ScopeLocs.first;
101+
BasenameLocs.first = OB.FunctionInfo.ScopeLocs.second;
102+
}
103+
104+
bool FunctionNameInfo::hasBasename() const {
105+
return BasenameLocs.first != BasenameLocs.second && BasenameLocs.second > 0;
106+
}
107+
108+
ScopedOverride<unsigned> OutputBuffer::enterFunctionTypePrinting() {
109+
return {FunctionPrintingDepth, FunctionPrintingDepth + 1};
110+
}
111+
112+
DEMANGLE_NAMESPACE_END

libcxxabi/src/demangle/Utility.h

Lines changed: 75 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,77 @@
2727

2828
DEMANGLE_NAMESPACE_BEGIN
2929

30+
template <class T> class ScopedOverride {
31+
T &Loc;
32+
T Original;
33+
34+
public:
35+
ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
36+
37+
ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
38+
Loc_ = std::move(NewVal);
39+
}
40+
~ScopedOverride() { Loc = std::move(Original); }
41+
42+
ScopedOverride(const ScopedOverride &) = delete;
43+
ScopedOverride &operator=(const ScopedOverride &) = delete;
44+
};
45+
46+
class OutputBuffer;
47+
48+
// Stores information about parts of a demangled function name.
49+
struct FunctionNameInfo {
50+
/// A [start, end) pair for the function basename.
51+
/// The basename is the name without scope qualifiers
52+
/// and without template parameters. E.g.,
53+
/// \code{.cpp}
54+
/// void foo::bar<int>::someFunc<float>(int) const &&
55+
/// ^ ^
56+
/// Start End
57+
/// \endcode
58+
std::pair<size_t, size_t> BasenameLocs;
59+
60+
/// A [start, end) pair for the function scope qualifiers.
61+
/// E.g., for
62+
/// \code{.cpp}
63+
/// void foo::bar<int>::qux<float>(int) const &&
64+
/// ^ ^
65+
/// Start End
66+
/// \endcode
67+
std::pair<size_t, size_t> ScopeLocs;
68+
69+
/// Indicates the [start, end) of the function argument lits.
70+
/// E.g.,
71+
/// \code{.cpp}
72+
/// int (*getFunc<float>(float, double))(int, int)
73+
/// ^ ^
74+
/// start end
75+
/// \endcode
76+
std::pair<size_t, size_t> ArgumentLocs;
77+
78+
bool startedPrintingArguments() const;
79+
bool shouldTrack(OutputBuffer &OB) const;
80+
bool canFinalize(OutputBuffer &OB) const;
81+
void updateBasenameEnd(OutputBuffer &OB);
82+
void updateScopeStart(OutputBuffer &OB);
83+
void updateScopeEnd(OutputBuffer &OB);
84+
void finalizeArgumentEnd(OutputBuffer &OB);
85+
void finalizeStart(OutputBuffer &OB);
86+
void finalizeEnd(OutputBuffer &OB);
87+
bool hasBasename() const;
88+
};
89+
3090
// Stream that AST nodes write their string representation into after the AST
3191
// has been parsed.
3292
class OutputBuffer {
3393
char *Buffer = nullptr;
3494
size_t CurrentPosition = 0;
3595
size_t BufferCapacity = 0;
3696

97+
/// When a function type is being printed this value is incremented.
98+
/// When printing of the type is finished the value is decremented.
99+
unsigned FunctionPrintingDepth = 0;
100+
37101
// Ensure there are at least N more positions in the buffer.
38102
void grow(size_t N) {
39103
size_t Need = N + CurrentPosition;
@@ -92,8 +156,19 @@ class OutputBuffer {
92156
/// Use a counter so we can simply increment inside parentheses.
93157
unsigned GtIsGt = 1;
94158

159+
/// When printing the mangle tree, this object will hold information about
160+
/// the function name being printed (if any).
161+
FunctionNameInfo FunctionInfo;
162+
163+
/// Called when we start printing a function type.
164+
[[nodiscard]] ScopedOverride<unsigned> enterFunctionTypePrinting();
165+
95166
bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
96167

168+
bool isPrintingTopLevelFunctionType() const {
169+
return FunctionPrintingDepth == 1;
170+
}
171+
97172
void printOpen(char Open = '(') {
98173
GtIsGt++;
99174
*this += Open;
@@ -182,22 +257,6 @@ class OutputBuffer {
182257
size_t getBufferCapacity() const { return BufferCapacity; }
183258
};
184259

185-
template <class T> class ScopedOverride {
186-
T &Loc;
187-
T Original;
188-
189-
public:
190-
ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
191-
192-
ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
193-
Loc_ = std::move(NewVal);
194-
}
195-
~ScopedOverride() { Loc = std::move(Original); }
196-
197-
ScopedOverride(const ScopedOverride &) = delete;
198-
ScopedOverride &operator=(const ScopedOverride &) = delete;
199-
};
200-
201260
DEMANGLE_NAMESPACE_END
202261

203262
#endif

libcxxabi/src/demangle/cp-to-llvm.sh

Lines changed: 45 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,58 @@ set -e
77

88
cd $(dirname $0)
99
HDRS="ItaniumDemangle.h ItaniumNodes.def StringViewExtras.h Utility.h"
10-
LLVM_DEMANGLE_DIR=$1
10+
SRCS="Utility.cpp"
11+
LLVM_DEMANGLE_INCLUDE_DIR=$1
12+
LLVM_DEMANGLE_SOURCE_DIR=$2
1113

12-
if [[ -z "$LLVM_DEMANGLE_DIR" ]]; then
13-
LLVM_DEMANGLE_DIR="../../../llvm/include/llvm/Demangle"
14+
if [[ -z "$LLVM_DEMANGLE_INCLUDE_DIR" ]]; then
15+
LLVM_DEMANGLE_INCLUDE_DIR="../../../llvm/include/llvm/Demangle"
1416
fi
1517

16-
if [[ ! -d "$LLVM_DEMANGLE_DIR" ]]; then
17-
echo "No such directory: $LLVM_DEMANGLE_DIR" >&2
18+
if [[ -z "$LLVM_DEMANGLE_SOURCE_DIR" ]]; then
19+
LLVM_DEMANGLE_SOURCE_DIR="../../../llvm/lib/Demangle"
20+
fi
21+
22+
if [[ ! -d "$LLVM_DEMANGLE_INCLUDE_DIR" ]]; then
23+
echo "No such directory: $LLVM_DEMANGLE_INCLUDE_DIR" >&2
24+
exit 1
25+
fi
26+
27+
if [[ ! -d "$LLVM_DEMANGLE_SOURCE_DIR" ]]; then
28+
echo "No such directory: $LLVM_DEMANGLE_SOURCE_DIR" >&2
1829
exit 1
1930
fi
2031

21-
read -p "This will overwrite the copies of $HDRS in $LLVM_DEMANGLE_DIR; are you sure? [y/N]" -n 1 -r ANSWER
32+
read -p "This will overwrite the copies of $HDRS in $LLVM_DEMANGLE_INCLUDE_DIR and $SRCS in $LLVM_DEMANGLE_SOURCE_DIR; are you sure? [y/N]" -n 1 -r ANSWER
2233
echo
2334

24-
if [[ $ANSWER =~ ^[Yy]$ ]]; then
25-
cp -f README.txt $LLVM_DEMANGLE_DIR
26-
chmod -w $LLVM_DEMANGLE_DIR/README.txt
27-
for I in $HDRS ; do
28-
rm -f $LLVM_DEMANGLE_DIR/$I
29-
dash=$(echo "$I---------------------------" | cut -c -27 |\
30-
sed 's|[^-]*||')
31-
sed -e '1s|^//=*-* .*\..* -*.*=*// *$|//===--- '"$I $dash"'-*- mode:c++;eval:(read-only-mode) -*-===//|' \
32-
-e '2s|^// *$|// Do not edit! See README.txt.|' \
33-
$I >$LLVM_DEMANGLE_DIR/$I
34-
chmod -w $LLVM_DEMANGLE_DIR/$I
35+
function copy_files() {
36+
local dest_dir=$1
37+
local files=$2
38+
local adjust_include_paths=$3
39+
40+
cp -f README.txt $dest_dir
41+
chmod -w $dest_dir/README.txt
42+
for I in $files ; do
43+
rm -f $dest_dir/$I
44+
dash=$(echo "$I---------------------------" | cut -c -27 |\
45+
sed 's|[^-]*||')
46+
sed -e '1s|^//=*-* .*\..* -*.*=*// *$|//===--- '"$I $dash"'-*- mode:c++;eval:(read-only-mode) -*-===//|' \
47+
-e '2s|^// *$|// Do not edit! See README.txt.|' \
48+
$I >$dest_dir/$I
49+
50+
if [[ "$adjust_include_paths" = true ]]; then
51+
sed -i '' \
52+
-e 's|#include "DemangleConfig.h"|#include "llvm/Demangle/DemangleConfig.h"|' \
53+
-e 's|#include "Utility.h"|#include "llvm/Demangle/Utility.h"|' \
54+
$dest_dir/$I
55+
fi
56+
57+
chmod -w $dest_dir/$I
3558
done
59+
}
60+
61+
if [[ $ANSWER =~ ^[Yy]$ ]]; then
62+
copy_files $LLVM_DEMANGLE_INCLUDE_DIR "$HDRS" false
63+
copy_files $LLVM_DEMANGLE_SOURCE_DIR "$SRCS" true
3664
fi

0 commit comments

Comments
 (0)