llvm-project/lldb/source/Core/DemangledNameInfo.cpp
Michael Buch fac7453d2c
[lldb][Mangled] Move SuffixRange computation into TrackingOutputBuffer (#152483)
This way all the tracking is self-contained in `TrackingOutputBuffer`
and we can test the `SuffixRange` properly.
2025-08-07 14:39:52 +01:00

250 lines
6.3 KiB
C++

//===-- DemangledNameInfo.cpp ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/DemangledNameInfo.h"
using namespace llvm::itanium_demangle;
namespace lldb_private {
bool TrackingOutputBuffer::shouldTrack() const {
if (!isPrintingTopLevelFunctionType())
return false;
if (isGtInsideTemplateArgs())
return false;
if (NameInfo.ArgumentsRange.first > 0)
return false;
return true;
}
bool TrackingOutputBuffer::canFinalize() const {
if (!isPrintingTopLevelFunctionType())
return false;
if (isGtInsideTemplateArgs())
return false;
if (NameInfo.ArgumentsRange.first == 0)
return false;
return true;
}
void TrackingOutputBuffer::updateBasenameEnd() {
if (!shouldTrack())
return;
NameInfo.BasenameRange.second = getCurrentPosition();
}
void TrackingOutputBuffer::updateScopeStart() {
if (!shouldTrack())
return;
NameInfo.ScopeRange.first = getCurrentPosition();
}
void TrackingOutputBuffer::updateScopeEnd() {
if (!shouldTrack())
return;
NameInfo.ScopeRange.second = getCurrentPosition();
}
void TrackingOutputBuffer::finalizeArgumentEnd() {
if (!canFinalize())
return;
NameInfo.ArgumentsRange.second = getCurrentPosition();
}
void TrackingOutputBuffer::finalizeQualifiersStart() {
if (!canFinalize())
return;
NameInfo.QualifiersRange.first = getCurrentPosition();
}
void TrackingOutputBuffer::finalizeQualifiersEnd() {
if (!canFinalize())
return;
NameInfo.QualifiersRange.second = getCurrentPosition();
}
void TrackingOutputBuffer::finalizeStart() {
if (!shouldTrack())
return;
NameInfo.ArgumentsRange.first = getCurrentPosition();
// If nothing has set the end of the basename yet (for example when
// printing templates), then the beginning of the arguments is the end of
// the basename.
if (NameInfo.BasenameRange.second == 0)
NameInfo.BasenameRange.second = getCurrentPosition();
// There is something between the basename and the start of the function
// arguments. Assume those are template arguments (which *should* be true for
// C++ demangled names, but this assumption may change in the future, in
// which case this needs to be adjusted).
if (NameInfo.BasenameRange.second != NameInfo.ArgumentsRange.first)
NameInfo.TemplateArgumentsRange = {NameInfo.BasenameRange.second,
NameInfo.ArgumentsRange.first};
assert(!shouldTrack());
assert(canFinalize());
}
void TrackingOutputBuffer::finalizeEnd() {
if (!canFinalize())
return;
if (NameInfo.ScopeRange.first > NameInfo.ScopeRange.second)
NameInfo.ScopeRange.second = NameInfo.ScopeRange.first;
NameInfo.BasenameRange.first = NameInfo.ScopeRange.second;
// We call anything past the FunctionEncoding the "suffix".
// In practice this would be nodes like `DotSuffix` that wrap
// a FunctionEncoding.
NameInfo.SuffixRange.first = getCurrentPosition();
}
ScopedOverride<unsigned> TrackingOutputBuffer::enterFunctionTypePrinting() {
return {FunctionPrintingDepth, FunctionPrintingDepth + 1};
}
bool TrackingOutputBuffer::isPrintingTopLevelFunctionType() const {
return FunctionPrintingDepth == 1;
}
void TrackingOutputBuffer::printLeft(const Node &N) {
switch (N.getKind()) {
case Node::KFunctionType:
printLeftImpl(static_cast<const FunctionType &>(N));
break;
case Node::KFunctionEncoding:
printLeftImpl(static_cast<const FunctionEncoding &>(N));
break;
case Node::KNestedName:
printLeftImpl(static_cast<const NestedName &>(N));
break;
case Node::KNameWithTemplateArgs:
printLeftImpl(static_cast<const NameWithTemplateArgs &>(N));
break;
default:
OutputBuffer::printLeft(N);
}
// Keep updating suffix until we reach the end.
NameInfo.SuffixRange.second = getCurrentPosition();
}
void TrackingOutputBuffer::printRight(const Node &N) {
switch (N.getKind()) {
case Node::KFunctionType:
printRightImpl(static_cast<const FunctionType &>(N));
break;
case Node::KFunctionEncoding:
printRightImpl(static_cast<const FunctionEncoding &>(N));
break;
default:
OutputBuffer::printRight(N);
}
// Keep updating suffix until we reach the end.
NameInfo.SuffixRange.second = getCurrentPosition();
}
void TrackingOutputBuffer::printLeftImpl(const FunctionType &N) {
auto Scoped = enterFunctionTypePrinting();
OutputBuffer::printLeft(N);
}
void TrackingOutputBuffer::printRightImpl(const FunctionType &N) {
auto Scoped = enterFunctionTypePrinting();
OutputBuffer::printRight(N);
}
void TrackingOutputBuffer::printLeftImpl(const FunctionEncoding &N) {
auto Scoped = enterFunctionTypePrinting();
const Node *Ret = N.getReturnType();
if (Ret) {
printLeft(*Ret);
if (!Ret->hasRHSComponent(*this))
*this += " ";
}
updateScopeStart();
N.getName()->print(*this);
}
void TrackingOutputBuffer::printRightImpl(const FunctionEncoding &N) {
auto Scoped = enterFunctionTypePrinting();
finalizeStart();
printOpen();
N.getParams().printWithComma(*this);
printClose();
finalizeArgumentEnd();
const Node *Ret = N.getReturnType();
if (Ret)
printRight(*Ret);
finalizeQualifiersStart();
auto CVQuals = N.getCVQuals();
auto RefQual = N.getRefQual();
auto *Attrs = N.getAttrs();
auto *Requires = N.getRequires();
if (CVQuals & QualConst)
*this += " const";
if (CVQuals & QualVolatile)
*this += " volatile";
if (CVQuals & QualRestrict)
*this += " restrict";
if (RefQual == FrefQualLValue)
*this += " &";
else if (RefQual == FrefQualRValue)
*this += " &&";
if (Attrs != nullptr)
Attrs->print(*this);
if (Requires != nullptr) {
*this += " requires ";
Requires->print(*this);
}
finalizeQualifiersEnd();
finalizeEnd();
}
void TrackingOutputBuffer::printLeftImpl(const NestedName &N) {
N.Qual->print(*this);
*this += "::";
updateScopeEnd();
N.Name->print(*this);
updateBasenameEnd();
}
void TrackingOutputBuffer::printLeftImpl(const NameWithTemplateArgs &N) {
N.Name->print(*this);
updateBasenameEnd();
N.TemplateArgs->print(*this);
}
} // namespace lldb_private