[SourceKit] Add parameter.name.local and parameter.name.external tags

... for the fully annotated declarations. More substructure more better.
This has to go through a callback mechanism similar to printDeclLoc and
printDeclPre since it should be scheduled after both of those are
printed.

rdar://problem/24292226
This commit is contained in:
Ben Langmuir
2016-02-24 15:03:46 -08:00
parent b509fca173
commit d3e98f52ef
5 changed files with 92 additions and 19 deletions

View File

@@ -38,7 +38,8 @@ enum class PrintNameContext {
GenericParameter,
/// Function parameter context, where keywords other than let/var/inout are
/// not escaped.
FunctionParameter,
FunctionParameterExternal,
FunctionParameterLocal,
};
/// An abstract class used to print an AST.
@@ -47,6 +48,7 @@ class ASTPrinter {
unsigned PendingNewlines = 0;
const Decl *PendingDeclPreCallback = nullptr;
const Decl *PendingDeclLocCallback = nullptr;
Optional<PrintNameContext> PendingNamePreCallback;
const NominalTypeDecl *SynthesizeTarget = nullptr;
void printTextImpl(StringRef Text);
@@ -85,6 +87,11 @@ public:
virtual void printSynthesizedExtensionPost(const ExtensionDecl *ED,
const NominalTypeDecl *NTD) {}
/// Called before printing a name in the given context.
virtual void printNamePre(PrintNameContext Context) {}
/// Called after printing a name in the given context.
virtual void printNamePost(PrintNameContext Context) {}
// Helper functions.
void printSeparator(bool &first, StringRef separator) {
@@ -128,10 +135,18 @@ public:
PendingDeclPreCallback = D;
}
/// Schedule a \c printDeclLoc callback to be called as soon as a
/// non-whitespace character is printed.
void callPrintDeclLoc(const Decl *D) {
PendingDeclLocCallback = D;
}
/// Schedule a \c printNamePre callback to be called as soon as a
/// non-whitespace character is printed.
void callPrintNamePre(PrintNameContext Context) {
PendingNamePreCallback = Context;
}
/// To sanitize a malformed utf8 string to a well-formed one.
static std::string sanitizeUtf8(StringRef Text);
static bool printTypeInterface(Type Ty, DeclContext *DC, std::string &Result);

View File

@@ -333,8 +333,10 @@ void ASTPrinter::printTextImpl(StringRef Text) {
const Decl *PreD = PendingDeclPreCallback;
const Decl *LocD = PendingDeclLocCallback;
auto NameContext = PendingNamePreCallback;
PendingDeclPreCallback = nullptr;
PendingDeclLocCallback = nullptr;
PendingNamePreCallback.reset();
if (PreD) {
if (SynthesizeTarget && PreD->getKind() == DeclKind::Extension)
@@ -345,6 +347,9 @@ void ASTPrinter::printTextImpl(StringRef Text) {
if (LocD) {
printDeclLoc(LocD);
}
if (NameContext) {
printNamePre(*NameContext);
}
printText(Text);
}
@@ -395,12 +400,16 @@ static bool escapeKeywordInContext(StringRef keyword, PrintNameContext context){
case PrintNameContext::GenericParameter:
return keyword != "Self";
case PrintNameContext::FunctionParameter:
case PrintNameContext::FunctionParameterExternal:
case PrintNameContext::FunctionParameterLocal:
return !canBeArgumentLabel(keyword);
}
}
void ASTPrinter::printName(Identifier Name, PrintNameContext Context) {
callPrintNamePre(Context);
defer { printNamePost(Context); };
if (Name.empty()) {
*this << "_";
return;
@@ -1821,25 +1830,25 @@ void PrintAST::printOneParameter(const ParamDecl *param, bool Curried,
auto BodyName = param->getName();
switch (Options.ArgAndParamPrinting) {
case PrintOptions::ArgAndParamPrintingMode::ArgumentOnly:
Printer.printName(ArgName, PrintNameContext::FunctionParameter);
Printer.printName(ArgName, PrintNameContext::FunctionParameterExternal);
if (!ArgNameIsAPIByDefault && !ArgName.empty())
Printer << " _";
break;
case PrintOptions::ArgAndParamPrintingMode::MatchSource:
if (ArgName == BodyName && ArgNameIsAPIByDefault) {
Printer.printName(ArgName, PrintNameContext::FunctionParameter);
Printer.printName(ArgName, PrintNameContext::FunctionParameterExternal);
break;
}
if (ArgName.empty() && !ArgNameIsAPIByDefault) {
Printer.printName(BodyName, PrintNameContext::FunctionParameter);
Printer.printName(BodyName, PrintNameContext::FunctionParameterLocal);
break;
}
SWIFT_FALLTHROUGH;
case PrintOptions::ArgAndParamPrintingMode::BothAlways:
Printer.printName(ArgName, PrintNameContext::FunctionParameter);
Printer.printName(ArgName, PrintNameContext::FunctionParameterExternal);
Printer << " ";
Printer.printName(BodyName, PrintNameContext::FunctionParameter);
Printer.printName(BodyName, PrintNameContext::FunctionParameterLocal);
break;
}
Printer << ": ";
@@ -2843,7 +2852,8 @@ public:
}
if (TD.hasName()) {
Printer.printName(TD.getName(), PrintNameContext::FunctionParameter);
Printer.printName(TD.getName(),
PrintNameContext::FunctionParameterExternal);
Printer << ": ";
}

View File

@@ -78,6 +78,13 @@ private:
return OtherPrinter.printSynthesizedExtensionPost(ED, NTD);
}
void printNamePre(PrintNameContext Context) override {
return OtherPrinter.printNamePre(Context);
}
void printNamePost(PrintNameContext Context) override {
return OtherPrinter.printNamePost(Context);
}
// Prints regular comments of the header the clang node comes from, until
// the location of the node. Keeps track of the comments that were printed
// from the file and resumes printing for the next node from the same file.

View File

@@ -83,6 +83,8 @@ struct S2<T, U where T == U> {
class C4<T, U where T == U> {}
enum E1<T, U where T == U> {}
func nonDefaultArgNames(external1 local1: Int, _ local2: Int, external3 local3: Int, external4 _: Int, _: Int) {}
// RUN: rm -rf %t.tmp
// RUN: mkdir %t.tmp
// RUN: %swiftc_driver -emit-module -o %t.tmp/FooSwiftModule.swiftmodule %S/Inputs/FooSwiftModule.swift
@@ -100,7 +102,7 @@ enum E1<T, U where T == U> {}
// CHECK2-NEXT: Swift{{$}}
// CHECK2-NEXT: SYSTEM
// CHECK2-NEXT: <Declaration>func +(lhs: <Type usr="s:Si">Int</Type>, rhs: <Type usr="s:Si">Int</Type>) -&gt; <Type usr="s:Si">Int</Type></Declaration>
// CHECK2-NEXT: <decl.function.operator.infix>func <decl.name>+</decl.name>(<decl.var.parameter>lhs: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>, <decl.var.parameter>rhs: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>) -&gt; <ref.struct usr="s:Si">Int</ref.struct></decl.function.operator.infix>
// CHECK2-NEXT: <decl.function.operator.infix>func <decl.name>+</decl.name>(<decl.var.parameter><decl.var.parameter.name.local>lhs</decl.var.parameter.name.local>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.name.local>rhs</decl.var.parameter.name.local>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>) -&gt; <ref.struct usr="s:Si">Int</ref.struct></decl.function.operator.infix>
// RUN: %sourcekitd-test -req=cursor -pos=9:12 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck -check-prefix=CHECK3 %s
// CHECK3: source.lang.swift.ref.var.local (8:10-8:11)
@@ -109,6 +111,7 @@ enum E1<T, U where T == U> {}
// CHECK3-NEXT: Int{{$}}
// CHECK3-NEXT: <Declaration>let x: <Type usr="s:Si">Int</Type></Declaration>
// CHECK3-NEXT: <decl.var.parameter>let <decl.name>x</decl.name>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>
// FIXME: decl.name should be decl.var.parameter.name.local
// RUN: %sourcekitd-test -req=cursor -pos=9:18 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck -check-prefix=CHECK4 %s
// CHECK4: source.lang.swift.ref.var.global ({{.*}}Foo.framework/Headers/Foo.h:62:12-62:21)
@@ -151,7 +154,7 @@ enum E1<T, U where T == U> {}
// CHECK8-NEXT: s:FC11cursor_info2CCcFT1xSi_S0_
// CHECK8-NEXT: CC.Type -> (x: Int) -> CC
// CHECK8-NEXT: <Declaration>convenience init(x: <Type usr="s:Si">Int</Type>)</Declaration>
// CHECK8-NEXT: <decl.function.constructor>convenience <decl.name>init</decl.name>(<decl.var.parameter>x: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>)</decl.function.constructor>
// CHECK8-NEXT: <decl.function.constructor>convenience <decl.name>init</decl.name>(<decl.var.parameter><decl.var.parameter.name.external>x</decl.var.parameter.name.external>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>)</decl.function.constructor>
// RUN: %sourcekitd-test -req=cursor -pos=23:6 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck -check-prefix=CHECK9 %s
// CHECK9: source.lang.swift.decl.var.global (23:5-23:15)
@@ -167,16 +170,18 @@ enum E1<T, U where T == U> {}
// CHECK11: source.lang.swift.decl.var.parameter (26:19-26:23)
// CHECK11: <Declaration>let arg1: <Type usr="s:Si">Int</Type></Declaration>
// CHECK11: <decl.var.parameter>let <decl.name>arg1</decl.name>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>
// FIXME: decl.name should be decl.var.parameter.name.local
// RUN: %sourcekitd-test -req=cursor -pos=28:24 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck -check-prefix=CHECK12 %s
// CHECK12: source.lang.swift.decl.var.parameter (28:23-28:27)
// CHECK12: <Declaration>var arg1: <Type usr="s:Si">Int</Type></Declaration>
// CHECK12: <decl.var.parameter>var <decl.name>arg1</decl.name>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>
// FIXME: decl.name should be decl.var.parameter.name.local
// RUN: %sourcekitd-test -req=cursor -pos=31:7 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck -check-prefix=CHECK13 %s
// CHECK13: source.lang.swift.decl.function.free (31:6-31:37)
// CHECK13: <Declaration>func testDefaultParam(arg1: <Type usr="s:Si">Int</Type> = default)</Declaration>
// CHECK13: <decl.function.free>func <decl.name>testDefaultParam</decl.name>(<decl.var.parameter>arg1: <ref.struct usr="s:Si">Int</ref.struct> = default</decl.var.parameter>)</decl.function.free>
// CHECK13: <decl.function.free>func <decl.name>testDefaultParam</decl.name>(<decl.var.parameter><decl.var.parameter.name.local>arg1</decl.var.parameter.name.local>: <ref.struct usr="s:Si">Int</ref.struct> = default</decl.var.parameter>)</decl.function.free>
// RUN: %sourcekitd-test -req=cursor -pos=34:4 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck -check-prefix=CHECK14 %s
// CHECK14: source.lang.swift.ref.function.free ({{.*}}Foo.framework/Frameworks/FooSub.framework/Headers/FooSub.h:4:5-4:16)
@@ -188,7 +193,7 @@ enum E1<T, U where T == U> {}
// CHECK15: source.lang.swift.decl.function.free (38:6-38:40)
// CHECK15: myFunc
// CHECK15: <Declaration>func myFunc(arg1: <Type usr="s:SS">String</Type>, options: <Type usr="s:Si">Int</Type>)</Declaration>
// CHECK15: <decl.function.free>func <decl.name>myFunc</decl.name>(<decl.var.parameter>arg1: <ref.struct usr="s:SS">String</ref.struct></decl.var.parameter>, <decl.var.parameter>options: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>)</decl.function.free>
// CHECK15: <decl.function.free>func <decl.name>myFunc</decl.name>(<decl.var.parameter><decl.var.parameter.name.local>arg1</decl.var.parameter.name.local>: <ref.struct usr="s:SS">String</ref.struct></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.name.external>options</decl.var.parameter.name.external>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>)</decl.function.free>
// CHECK15: RELATED BEGIN
// CHECK15-NEXT: <RelatedName usr="s:F11cursor_info6myFuncFSST_">myFunc(_:)</RelatedName>
// CHECK15-NEXT: RELATED END
@@ -243,11 +248,11 @@ enum E1<T, U where T == U> {}
// RUN: %sourcekitd-test -req=cursor -pos=69:14 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck -check-prefix=CHECK27 %s
// CHECK27: <Declaration>public subscript(i: <Type usr="s:Si">Int</Type>) -&gt; <Type usr="s:Si">Int</Type> { get }</Declaration>
// CHECK27: <decl.function.subscript>public <decl.name>subscript</decl.name>(<decl.var.parameter>i: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>) -&gt; <ref.struct usr="s:Si">Int</ref.struct> { get }</decl.function.subscript>
// CHECK27: <decl.function.subscript>public <decl.name>subscript</decl.name>(<decl.var.parameter><decl.var.parameter.name.local>i</decl.var.parameter.name.local>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>) -&gt; <ref.struct usr="s:Si">Int</ref.struct> { get }</decl.function.subscript>
// RUN: %sourcekitd-test -req=cursor -pos=69:19 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck -check-prefix=CHECK28 %s
// CHECK28: <Declaration>public subscript(i: <Type usr="s:Si">Int</Type>) -&gt; <Type usr="s:Si">Int</Type> { get }</Declaration>
// CHECK28: <decl.function.subscript>public <decl.name>subscript</decl.name>(<decl.var.parameter>i: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>) -&gt; <ref.struct usr="s:Si">Int</ref.struct> { get }</decl.function.subscript>
// CHECK28: <decl.function.subscript>public <decl.name>subscript</decl.name>(<decl.var.parameter><decl.var.parameter.name.local>i</decl.var.parameter.name.local>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>) -&gt; <ref.struct usr="s:Si">Int</ref.struct> { get }</decl.function.subscript>
// RUN: %sourcekitd-test -req=cursor -pos=74:3 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck %s -check-prefix=CHECK29
// CHECK29: source.lang.swift.decl.function.destructor (74:3-74:9)
@@ -263,7 +268,7 @@ enum E1<T, U where T == U> {}
// CHECK30-NEXT: s:FC11cursor_info2C3cFT1xSi_GSQS0__
// CHECK30-NEXT: C3.Type -> (x: Int) -> C3!
// CHECK30-NEXT: <Declaration>init!(x: <Type usr="s:Si">Int</Type>)</Declaration>
// CHECK30-NEXT: <decl.function.constructor><decl.name>init</decl.name>!(<decl.var.parameter>x: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>)</decl.function.constructor>
// CHECK30-NEXT: <decl.function.constructor><decl.name>init</decl.name>!(<decl.var.parameter><decl.var.parameter.name.external>x</decl.var.parameter.name.external>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>)</decl.function.constructor>
// RUN: %sourcekitd-test -req=cursor -pos=76:3 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck %s -check-prefix=CHECK31
// CHECK31: source.lang.swift.decl.function.constructor (76:3-76:16)
@@ -271,7 +276,7 @@ enum E1<T, U where T == U> {}
// CHECK31-NEXT: s:FC11cursor_info2C3cFT1ySi_GSqS0__
// CHECK31-NEXT: C3.Type -> (y: Int) -> C3?
// CHECK31-NEXT: <Declaration>init?(y: <Type usr="s:Si">Int</Type>)</Declaration>
// CHECK31-NEXT: <decl.function.constructor><decl.name>init</decl.name>?(<decl.var.parameter>y: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>)</decl.function.constructor>
// CHECK31-NEXT: <decl.function.constructor><decl.name>init</decl.name>?(<decl.var.parameter><decl.var.parameter.name.external>y</decl.var.parameter.name.external>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>)</decl.function.constructor>
// RUN: %sourcekitd-test -req=cursor -pos=77:3 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck %s -check-prefix=CHECK32
// CHECK32: source.lang.swift.decl.function.constructor (77:3-77:15)
@@ -279,7 +284,7 @@ enum E1<T, U where T == U> {}
// CHECK32-NEXT: s:FC11cursor_info2C3cFzT1zSi_S0_
// CHECK32-NEXT: C3.Type -> (z: Int) throws -> C3
// CHECK32-NEXT: <Declaration>init(z: <Type usr="s:Si">Int</Type>) throws</Declaration>
// CHECK32-NEXT: <decl.function.constructor><decl.name>init</decl.name>(<decl.var.parameter>z: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>) throws</decl.function.constructor>
// CHECK32-NEXT: <decl.function.constructor><decl.name>init</decl.name>(<decl.var.parameter><decl.var.parameter.name.external>z</decl.var.parameter.name.external>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>) throws</decl.function.constructor>
// RUN: %sourcekitd-test -req=cursor -pos=80:8 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck %s -check-prefix=CHECK33
// CHECK33: source.lang.swift.decl.struct (80:8-80:10)
@@ -295,7 +300,7 @@ enum E1<T, U where T == U> {}
// CHECK34-NEXT: s:FV11cursor_info2S23foou0_rFFT_T_FT_T_
// CHECK34-NEXT: <T, U> (S2<T, U>) -> <V, W> (() -> ()) -> () -> ()
// CHECK34-NEXT: <Declaration>func foo&lt;V, W&gt;(closure: () -&gt; ()) -&gt; () -&gt; ()</Declaration>
// CHECK34-NEXT: <decl.function.method.instance>func <decl.name>foo</decl.name>&lt;V, W&gt;(<decl.var.parameter>closure: () -&gt; ()</decl.var.parameter>) -&gt; () -&gt; ()</decl.function.method.instance>
// CHECK34-NEXT: <decl.function.method.instance>func <decl.name>foo</decl.name>&lt;V, W&gt;(<decl.var.parameter><decl.var.parameter.name.local>closure</decl.var.parameter.name.local>: () -&gt; ()</decl.var.parameter>) -&gt; () -&gt; ()</decl.function.method.instance>
// RUN: %sourcekitd-test -req=cursor -pos=83:7 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck %s -check-prefix=CHECK35
// CHECK35: source.lang.swift.decl.class (83:7-83:9)
@@ -312,3 +317,11 @@ enum E1<T, U where T == U> {}
// CHECK36-NEXT: E1.Type
// CHECK36-NEXT: <Declaration>enum E1&lt;T, U&gt;</Declaration>
// CHECK36-NEXT: <decl.enum>enum <decl.name>E1</decl.name>&lt;T, U&gt;</decl.enum>
// RUN: %sourcekitd-test -req=cursor -pos=86:6 %s -- -F %S/../Inputs/libIDE-mock-sdk -I %t.tmp %mcp_opt %s | FileCheck %s -check-prefix=CHECK37
// CHECK37: source.lang.swift.decl.function.free (86:6-86:111)
// CHECK37-NEXT: nonDefaultArgNames(external1:_:external3:external4:_:)
// CHECK37-NEXT: s:F11cursor_info18nonDefaultArgNamesFT9external1SiSi9external3Si9external4SiSi_T_
// CHECK37-NEXT: (external1: Int, Int, external3: Int, external4: Int, Int) -> ()
// CHECK37-NEXT: <Declaration>func nonDefaultArgNames(external1 local1: <Type usr="s:Si">Int</Type>, _ local2: <Type usr="s:Si">Int</Type>, external3 local3: <Type usr="s:Si">Int</Type>, external4 _: <Type usr="s:Si">Int</Type>, _: <Type usr="s:Si">Int</Type>)</Declaration>
// CHECK37-NEXT: <decl.function.free>func <decl.name>nonDefaultArgNames</decl.name>(<decl.var.parameter><decl.var.parameter.name.external>external1</decl.var.parameter.name.external> <decl.var.parameter.name.local>local1</decl.var.parameter.name.local>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.name.external>_</decl.var.parameter.name.external> <decl.var.parameter.name.local>local2</decl.var.parameter.name.local>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.name.external>external3</decl.var.parameter.name.external> <decl.var.parameter.name.local>local3</decl.var.parameter.name.local>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.name.external>external4</decl.var.parameter.name.external> <decl.var.parameter.name.local>_</decl.var.parameter.name.local>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>, <decl.var.parameter><decl.var.parameter.name.external>_</decl.var.parameter.name.external>: <ref.struct usr="s:Si">Int</ref.struct></decl.var.parameter>)</decl.function.free>

View File

@@ -62,6 +62,9 @@ static StringRef getTagForDecl(const Decl *D, bool isRef) {
return UID.getName().drop_front(strlen(prefix));
}
static StringRef ExternalParamNameTag = "decl.var.parameter.name.external";
static StringRef LocalParamNameTag = "decl.var.parameter.name.local";
/// An ASTPrinter for annotating declarations with XML tags that describe the
/// key substructure of the declaration for CursorInfo/DocInfo.
///
@@ -90,6 +93,31 @@ private:
closeTag("decl.name");
}
void printNamePre(PrintNameContext context) override {
switch (context) {
case PrintNameContext::FunctionParameterExternal:
openTag(ExternalParamNameTag);
break;
case PrintNameContext::FunctionParameterLocal:
openTag(LocalParamNameTag);
break;
default:
break;
}
}
void printNamePost(PrintNameContext context) override {
switch (context) {
case PrintNameContext::FunctionParameterExternal:
closeTag(ExternalParamNameTag);
break;
case PrintNameContext::FunctionParameterLocal:
closeTag(LocalParamNameTag);
break;
default:
break;
}
}
void printTypeRef(const TypeDecl *TD, Identifier name) override {
auto tag = getTagForDecl(TD, /*isRef=*/true);
OS << "<" << tag << " usr=\"";