Skip to content

Commit 0ab44d5

Browse files
authored
Merge pull request swiftlang#61246 from skrtks/SourceKit_qualified_types
[SourceKit] add qualified types in type requests
2 parents f49bab2 + 1bd0d97 commit 0ab44d5

File tree

11 files changed

+119
-69
lines changed

11 files changed

+119
-69
lines changed

include/swift/Sema/IDETypeChecking.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,10 @@ namespace swift {
231231

232232
/// Collect type information for every expression in \c SF; all types will
233233
/// be printed to \c OS.
234-
ArrayRef<ExpressionTypeInfo> collectExpressionType(SourceFile &SF,
235-
ArrayRef<const char *> ExpectedProtocols,
236-
std::vector<ExpressionTypeInfo> &scratch,
237-
bool CanonicalType,
238-
llvm::raw_ostream &OS);
234+
ArrayRef<ExpressionTypeInfo> collectExpressionType(
235+
SourceFile &SF, ArrayRef<const char *> ExpectedProtocols,
236+
std::vector<ExpressionTypeInfo> &scratch, bool FullyQualified,
237+
bool CanonicalType, llvm::raw_ostream &OS);
239238

240239
/// Resolve a list of mangled names to accessible protocol decls from
241240
/// the decl context.
@@ -265,6 +264,7 @@ namespace swift {
265264
/// \c VariableTypeInfos will index into the string that backs this
266265
/// stream.
267266
void collectVariableType(SourceFile &SF, SourceRange Range,
267+
bool FullyQualified,
268268
std::vector<VariableTypeInfo> &VariableTypeInfos,
269269
llvm::raw_ostream &OS);
270270

lib/IDE/IDETypeChecking.cpp

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,9 @@ class ExpressionTypeCollector: public SourceEntityWalker {
630630
// these protocols.
631631
llvm::MapVector<ProtocolDecl*, StringRef> &InterestedProtocols;
632632

633+
// Specified by the client whether we should print fully qualified types
634+
const bool FullyQualified;
635+
633636
// Specified by the client whether we should canonicalize types before printing
634637
const bool CanonicalType;
635638

@@ -676,16 +679,15 @@ class ExpressionTypeCollector: public SourceEntityWalker {
676679

677680

678681
public:
679-
ExpressionTypeCollector(SourceFile &SF,
680-
llvm::MapVector<ProtocolDecl*, StringRef> &InterestedProtocols,
681-
std::vector<ExpressionTypeInfo> &Results,
682-
bool CanonicalType,
683-
llvm::raw_ostream &OS): Module(*SF.getParentModule()),
684-
SM(SF.getASTContext().SourceMgr),
685-
BufferId(*SF.getBufferID()),
686-
Results(Results), OS(OS),
687-
InterestedProtocols(InterestedProtocols),
688-
CanonicalType(CanonicalType) {}
682+
ExpressionTypeCollector(
683+
SourceFile &SF,
684+
llvm::MapVector<ProtocolDecl *, StringRef> &InterestedProtocols,
685+
std::vector<ExpressionTypeInfo> &Results, bool FullyQualified,
686+
bool CanonicalType, llvm::raw_ostream &OS)
687+
: Module(*SF.getParentModule()), SM(SF.getASTContext().SourceMgr),
688+
BufferId(*SF.getBufferID()), Results(Results), OS(OS),
689+
InterestedProtocols(InterestedProtocols),
690+
FullyQualified(FullyQualified), CanonicalType(CanonicalType) {}
689691
bool walkToExprPre(Expr *E) override {
690692
if (E->getSourceRange().isInvalid())
691693
return true;
@@ -701,10 +703,12 @@ class ExpressionTypeCollector: public SourceEntityWalker {
701703
{
702704
llvm::raw_svector_ostream OS(Buffer);
703705
auto Ty = E->getType()->getRValueType();
706+
PrintOptions printOptions = PrintOptions();
707+
printOptions.FullyQualifiedTypes = FullyQualified;
704708
if (CanonicalType) {
705-
Ty->getCanonicalType()->print(OS);
709+
Ty->getCanonicalType()->print(OS, printOptions);
706710
} else {
707-
Ty->reconstituteSugar(true)->print(OS);
711+
Ty->reconstituteSugar(true)->print(OS, printOptions);
708712
}
709713
}
710714
auto Ty = getTypeOffsets(Buffer.str());
@@ -729,12 +733,10 @@ ProtocolDecl* swift::resolveProtocolName(DeclContext *dc, StringRef name) {
729733
nullptr);
730734
}
731735

732-
ArrayRef<ExpressionTypeInfo>
733-
swift::collectExpressionType(SourceFile &SF,
734-
ArrayRef<const char *> ExpectedProtocols,
735-
std::vector<ExpressionTypeInfo> &Scratch,
736-
bool CanonicalType,
737-
llvm::raw_ostream &OS) {
736+
ArrayRef<ExpressionTypeInfo> swift::collectExpressionType(
737+
SourceFile &SF, ArrayRef<const char *> ExpectedProtocols,
738+
std::vector<ExpressionTypeInfo> &Scratch, bool FullyQualified,
739+
bool CanonicalType, llvm::raw_ostream &OS) {
738740
llvm::MapVector<ProtocolDecl*, StringRef> InterestedProtocols;
739741
for (auto Name: ExpectedProtocols) {
740742
if (auto *pd = resolveProtocolName(&SF, Name)) {
@@ -744,7 +746,7 @@ swift::collectExpressionType(SourceFile &SF,
744746
}
745747
}
746748
ExpressionTypeCollector Walker(SF, InterestedProtocols, Scratch,
747-
CanonicalType, OS);
749+
FullyQualified, CanonicalType, OS);
748750
Walker.walk(SF);
749751
return Scratch;
750752
}
@@ -759,6 +761,9 @@ class VariableTypeCollector : public SourceEntityWalker {
759761
/// The range in which variable types are to be collected.
760762
SourceRange TotalRange;
761763

764+
// Specified by the client whether we should print fully qualified types
765+
const bool FullyQualified;
766+
762767
/// The output vector for VariableTypeInfos emitted during traversal.
763768
std::vector<VariableTypeInfo> &Results;
764769

@@ -791,10 +796,12 @@ class VariableTypeCollector : public SourceEntityWalker {
791796

792797
public:
793798
VariableTypeCollector(const SourceFile &SF, SourceRange Range,
799+
bool FullyQualified,
794800
std::vector<VariableTypeInfo> &Results,
795801
llvm::raw_ostream &OS)
796802
: SM(SF.getASTContext().SourceMgr), BufferId(*SF.getBufferID()),
797-
TotalRange(Range), Results(Results), OS(OS) {}
803+
TotalRange(Range), FullyQualified(FullyQualified), Results(Results),
804+
OS(OS) {}
798805

799806
bool walkToDeclPre(Decl *D, CharSourceRange DeclNameRange) override {
800807
if (DeclNameRange.isInvalid()) {
@@ -814,6 +821,7 @@ class VariableTypeCollector : public SourceEntityWalker {
814821
llvm::raw_svector_ostream OS(Buffer);
815822
PrintOptions Options;
816823
Options.SynthesizeSugarOnTypes = true;
824+
Options.FullyQualifiedTypes = FullyQualified;
817825
auto Ty = VD->getType();
818826
// Skip this declaration and its children if the type is an error type.
819827
if (Ty->is<ErrorType>()) {
@@ -854,9 +862,10 @@ VariableTypeInfo::VariableTypeInfo(uint32_t Offset, uint32_t Length,
854862
TypeOffset(TypeOffset) {}
855863

856864
void swift::collectVariableType(
857-
SourceFile &SF, SourceRange Range,
865+
SourceFile &SF, SourceRange Range, bool FullyQualified,
858866
std::vector<VariableTypeInfo> &VariableTypeInfos, llvm::raw_ostream &OS) {
859-
VariableTypeCollector Walker(SF, Range, VariableTypeInfos, OS);
867+
VariableTypeCollector Walker(SF, Range, FullyQualified, VariableTypeInfos,
868+
OS);
860869
Walker.walk(SF);
861870
}
862871

test/IDE/expr_type_qualified.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %target-swift-ide-test -print-expr-type -fully-qualified-types -source-filename %S/Inputs/ExprType.swift -swift-version 5 | %FileCheck %s -check-prefix=CHECK-SUGAR
2+
// RUN: %target-swift-ide-test -print-expr-type -fully-qualified-types -source-filename %S/Inputs/ExprType.swift -swift-version 5 -canonicalize-type | %FileCheck %s -check-prefix=CHECK-CANON
3+
4+
// CHECK-SUGAR: func foo() -> Int { return <expr type:"Swift.Int">1</expr> }
5+
// CHECK-SUGAR: func bar(f: Float) -> Float { return <expr type:"Swift.Float"><expr type:"(Swift.Float) -> Swift.Float">bar</expr>(f: <expr type:"Swift.Float">1</expr>)</expr> }
6+
// CHECK-SUGAR: func fooP(_ p: P) { <expr type:"()"><expr type:"(swift_ide_test.P) -> ()">fooP</expr>(<expr type:"swift_ide_test.P">p</expr>)</expr> }
7+
// CHECK-SUGAR: <expr type:"()"><expr type:"Swift.Int">_</expr> = <expr type:"Swift.Int"><expr type:"[swift_ide_test.C]">a</expr>.count</expr></expr>
8+
// CHECK-SUGAR: <expr type:"()"><expr type:"Swift.String">_</expr> = <expr type:"Swift.String"><expr type:"Swift.Int"><expr type:"(Swift.Int) -> Swift.Int"><expr type:"Swift.Int"><expr type:"Swift.String"><expr type:"[swift_ide_test.C]">a</expr>.description</expr>.count</expr>.<expr type:"(Swift.Int) -> (Swift.Int) -> Swift.Int">advanced</expr></expr>(by: <expr type:"Swift.Int">1</expr>)</expr>.description</expr></expr>
9+
// CHECK-SUGAR: <expr type:"()"><expr type:"Swift.Int?">_</expr> = <expr type:"Swift.Int?"><expr type:"Swift.Int"><expr type:"(Swift.Int) -> Swift.Int"><expr type:"Swift.Int"><expr type:"swift_ide_test.S"><expr type:"swift_ide_test.S?"><expr type:"[Swift.Int : swift_ide_test.S]">a</expr>[<expr type:"Swift.Int">2</expr>]</expr>?</expr>.val</expr>.<expr type:"(Swift.Int) -> (Swift.Int) -> Swift.Int">advanced</expr></expr>(by: <expr type:"Swift.Int">1</expr>)</expr>.byteSwapped</expr></expr>
10+
11+
12+
// CHECK-SUGAR: return <expr type:"swift_ide_test.MyInt"><expr type:"swift_ide_test.MyInt">a</expr> <expr type:"(Swift.Int, Swift.Int) -> Swift.Int">+</expr> <expr type:"swift_ide_test.MyInt">b</expr></expr>
13+
// CHECK-CANON: return <expr type:"Swift.Int"><expr type:"Swift.Int">a</expr> <expr type:"(Swift.Int, Swift.Int) -> Swift.Int">+</expr> <expr type:"Swift.Int">b</expr></expr>

test/SourceKit/VariableType/basic.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,16 @@ let `else` = 3
3333
// CHECK: (15:7, 15:8): (Int) -> Int (explicit type: 1)
3434
// CHECK: (19:7, 19:12): Int (explicit type: 0)
3535
// CHECK: (22:5, 22:11): Int (explicit type: 0)
36+
37+
// RUN: %sourcekitd-test -req=collect-var-type -req-opts=fully_qualified=true %s -- %s | %FileCheck %s --check-prefix CHECK-FULLY-QUALIFIED
38+
// CHECK-FULLY-QUALIFIED: (1:5, 1:6): Swift.Int (explicit type: 1)
39+
// CHECK-FULLY-QUALIFIED: (2:5, 2:6): Swift.String (explicit type: 0)
40+
// CHECK-FULLY-QUALIFIED: (4:5, 4:8): [Swift.String] (explicit type: 0)
41+
// CHECK-FULLY-QUALIFIED: (7:7, 7:8): Swift.String (explicit type: 1)
42+
// CHECK-FULLY-QUALIFIED: (8:7, 8:8): Swift.String (explicit type: 0)
43+
// CHECK-FULLY-QUALIFIED: (12:7, 12:8): Swift.Double (explicit type: 0)
44+
// CHECK-FULLY-QUALIFIED: (13:7, 13:8): [basic.A] (explicit type: 0)
45+
// CHECK-FULLY-QUALIFIED: (14:7, 14:8): [Swift.Int : Swift.Int] (explicit type: 1)
46+
// CHECK-FULLY-QUALIFIED: (15:7, 15:8): (Swift.Int) -> Swift.Int (explicit type: 1)
47+
// CHECK-FULLY-QUALIFIED: (19:7, 19:12): Swift.Int (explicit type: 0)
48+
// CHECK-FULLY-QUALIFIED: (22:5, 22:11): Swift.Int (explicit type: 0)

tools/SourceKit/docs/Protocol.md

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -751,14 +751,15 @@ type checking and the necessary compiler arguments to help resolve all dependenc
751751

752752
```
753753
{
754-
<key.request>: (UID) <source.request.expression.type>,
755-
<key.sourcefile>: (string) // Absolute path to the file.
756-
<key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
757-
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
758-
// these must include the path to that file.
759-
<key.expectedtypes>: [string*] // A list of interested protocol USRs.
760-
// When empty, we report all expressions in the file.
761-
// When non-empty, we report expressions whose types conform to any of the give protocols.
754+
<key.request>: (UID) <source.request.expression.type>,
755+
<key.sourcefile>: (string) // Absolute path to the file.
756+
<key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
757+
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
758+
// these must include the path to that file.
759+
<key.expectedtypes>: [string*] // A list of interested protocol USRs.
760+
// When empty, we report all expressions in the file.
761+
// When non-empty, we report expressions whose types conform to any of the give protocols.
762+
[opt] <key.fully_qualified>: (bool) // True when fully qualified type should be returned. Defaults to False.
762763
}
763764
```
764765

@@ -795,13 +796,14 @@ type checking and the necessary compiler arguments to help resolve all dependenc
795796

796797
```
797798
{
798-
<key.request>: (UID) <source.request.variable.type>,
799-
<key.sourcefile>: (string) // Absolute path to the file.
800-
<key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
801-
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
802-
// these must include the path to that file.
803-
[opt] <key.offset>: (int64) // Offset of the requested range. Defaults to zero.
804-
[opt] <key.length>: (int64) // Length of the requested range. Defaults to the entire file.
799+
<key.request>: (UID) <source.request.variable.type>,
800+
<key.sourcefile>: (string) // Absolute path to the file.
801+
<key.compilerargs>: [string*] // Array of zero or more strings for the compiler arguments,
802+
// e.g ["-sdk", "/path/to/sdk"]. If key.sourcefile is provided,
803+
// these must include the path to that file.
804+
[opt] <key.offset>: (int64) // Offset of the requested range. Defaults to zero.
805+
[opt] <key.length>: (int64) // Length of the requested range. Defaults to the entire file.
806+
[opt] <key.fully_qualified>: (bool) // True when fully qualified type should be returned. Defaults to False.
805807
}
806808
```
807809

tools/SourceKit/include/SourceKit/Core/LangSupport.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -911,8 +911,8 @@ class LangSupport {
911911

912912
virtual void collectExpressionTypes(
913913
StringRef FileName, ArrayRef<const char *> Args,
914-
ArrayRef<const char *> ExpectedProtocols, bool CanonicalType,
915-
SourceKitCancellationToken CancellationToken,
914+
ArrayRef<const char *> ExpectedProtocols, bool FullyQualified,
915+
bool CanonicalType, SourceKitCancellationToken CancellationToken,
916916
std::function<void(const RequestResult<ExpressionTypesInFile> &)>
917917
Receiver) = 0;
918918

@@ -921,7 +921,7 @@ class LangSupport {
921921
/// the entire document are collected.
922922
virtual void collectVariableTypes(
923923
StringRef FileName, ArrayRef<const char *> Args,
924-
Optional<unsigned> Offset, Optional<unsigned> Length,
924+
Optional<unsigned> Offset, Optional<unsigned> Length, bool FullyQualified,
925925
SourceKitCancellationToken CancellationToken,
926926
std::function<void(const RequestResult<VariableTypesInFile> &)>
927927
Receiver) = 0;

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -686,14 +686,14 @@ class SwiftLangSupport : public LangSupport {
686686

687687
void collectExpressionTypes(
688688
StringRef FileName, ArrayRef<const char *> Args,
689-
ArrayRef<const char *> ExpectedProtocols, bool CanonicalType,
690-
SourceKitCancellationToken CancellationToken,
689+
ArrayRef<const char *> ExpectedProtocols, bool FullyQualified,
690+
bool CanonicalType, SourceKitCancellationToken CancellationToken,
691691
std::function<void(const RequestResult<ExpressionTypesInFile> &)>
692692
Receiver) override;
693693

694694
void collectVariableTypes(
695695
StringRef FileName, ArrayRef<const char *> Args,
696-
Optional<unsigned> Offset, Optional<unsigned> Length,
696+
Optional<unsigned> Offset, Optional<unsigned> Length, bool FullyQualified,
697697
SourceKitCancellationToken CancellationToken,
698698
std::function<void(const RequestResult<VariableTypesInFile> &)> Receiver)
699699
override;

tools/SourceKit/lib/SwiftLang/SwiftSourceDocInfo.cpp

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2526,8 +2526,8 @@ void SwiftLangSupport::semanticRefactoring(
25262526

25272527
void SwiftLangSupport::collectExpressionTypes(
25282528
StringRef FileName, ArrayRef<const char *> Args,
2529-
ArrayRef<const char *> ExpectedProtocols, bool CanonicalType,
2530-
SourceKitCancellationToken CancellationToken,
2529+
ArrayRef<const char *> ExpectedProtocols, bool FullyQualified,
2530+
bool CanonicalType, SourceKitCancellationToken CancellationToken,
25312531
std::function<void(const RequestResult<ExpressionTypesInFile> &)>
25322532
Receiver) {
25332533
std::string Error;
@@ -2542,23 +2542,26 @@ void SwiftLangSupport::collectExpressionTypes(
25422542
class ExpressionTypeCollector: public SwiftASTConsumer {
25432543
std::function<void(const RequestResult<ExpressionTypesInFile> &)> Receiver;
25442544
std::vector<const char *> ExpectedProtocols;
2545+
bool FullyQualified;
25452546
bool CanonicalType;
25462547
public:
25472548
ExpressionTypeCollector(
2548-
std::function<void(const RequestResult<ExpressionTypesInFile> &)> Receiver,
2549-
ArrayRef<const char *> ExpectedProtocols,
2550-
bool CanonicalType):
2551-
Receiver(std::move(Receiver)),
2549+
std::function<void(const RequestResult<ExpressionTypesInFile> &)>
2550+
Receiver,
2551+
ArrayRef<const char *> ExpectedProtocols, bool FullyQualified,
2552+
bool CanonicalType)
2553+
: Receiver(std::move(Receiver)),
25522554
ExpectedProtocols(ExpectedProtocols.vec()),
2553-
CanonicalType(CanonicalType) {}
2555+
FullyQualified(FullyQualified), CanonicalType(CanonicalType) {}
25542556
void handlePrimaryAST(ASTUnitRef AstUnit) override {
25552557
auto *SF = AstUnit->getCompilerInstance().getPrimarySourceFile();
25562558
std::vector<ExpressionTypeInfo> Scratch;
25572559
llvm::SmallString<256> TypeBuffer;
25582560
llvm::raw_svector_ostream OS(TypeBuffer);
25592561
ExpressionTypesInFile Result;
2560-
for (auto Item: collectExpressionType(*SF, ExpectedProtocols, Scratch,
2561-
CanonicalType, OS)) {
2562+
for (auto Item :
2563+
collectExpressionType(*SF, ExpectedProtocols, Scratch,
2564+
FullyQualified, CanonicalType, OS)) {
25622565
Result.Results.push_back({Item.offset, Item.length, Item.typeOffset, {}});
25632566
for (auto P: Item.protocols) {
25642567
Result.Results.back().ProtocolOffsets.push_back(P.first);
@@ -2576,9 +2579,8 @@ void SwiftLangSupport::collectExpressionTypes(
25762579
Receiver(RequestResult<ExpressionTypesInFile>::fromError(Error));
25772580
}
25782581
};
2579-
auto Collector = std::make_shared<ExpressionTypeCollector>(Receiver,
2580-
ExpectedProtocols,
2581-
CanonicalType);
2582+
auto Collector = std::make_shared<ExpressionTypeCollector>(
2583+
Receiver, ExpectedProtocols, FullyQualified, CanonicalType);
25822584
/// FIXME: When request cancellation is implemented and Xcode adopts it,
25832585
/// don't use 'OncePerASTToken'.
25842586
static const char OncePerASTToken = 0;
@@ -2589,7 +2591,8 @@ void SwiftLangSupport::collectExpressionTypes(
25892591

25902592
void SwiftLangSupport::collectVariableTypes(
25912593
StringRef FileName, ArrayRef<const char *> Args, Optional<unsigned> Offset,
2592-
Optional<unsigned> Length, SourceKitCancellationToken CancellationToken,
2594+
Optional<unsigned> Length, bool FullyQualified,
2595+
SourceKitCancellationToken CancellationToken,
25932596
std::function<void(const RequestResult<VariableTypesInFile> &)> Receiver) {
25942597
std::string Error;
25952598
SwiftInvocationRef Invok =
@@ -2606,13 +2609,16 @@ void SwiftLangSupport::collectVariableTypes(
26062609
std::function<void(const RequestResult<VariableTypesInFile> &)> Receiver;
26072610
Optional<unsigned> Offset;
26082611
Optional<unsigned> Length;
2612+
bool FullyQualified;
26092613

26102614
public:
26112615
VariableTypeCollectorASTConsumer(
26122616
std::function<void(const RequestResult<VariableTypesInFile> &)>
26132617
Receiver,
2614-
Optional<unsigned> Offset, Optional<unsigned> Length)
2615-
: Receiver(std::move(Receiver)), Offset(Offset), Length(Length) {}
2618+
Optional<unsigned> Offset, Optional<unsigned> Length,
2619+
bool FullyQualified)
2620+
: Receiver(std::move(Receiver)), Offset(Offset), Length(Length),
2621+
FullyQualified(FullyQualified) {}
26162622

26172623
void handlePrimaryAST(ASTUnitRef AstUnit) override {
26182624
auto &CompInst = AstUnit->getCompilerInstance();
@@ -2636,7 +2642,7 @@ void SwiftLangSupport::collectVariableTypes(
26362642
llvm::raw_string_ostream OS(TypeBuffer);
26372643
VariableTypesInFile Result;
26382644

2639-
collectVariableType(*SF, Range, Infos, OS);
2645+
collectVariableType(*SF, Range, FullyQualified, Infos, OS);
26402646

26412647
for (auto Info : Infos) {
26422648
Result.Results.push_back({Info.Offset, Info.Length, Info.TypeOffset, Info.HasExplicitType});
@@ -2655,7 +2661,7 @@ void SwiftLangSupport::collectVariableTypes(
26552661
};
26562662

26572663
auto Collector = std::make_shared<VariableTypeCollectorASTConsumer>(
2658-
Receiver, Offset, Length);
2664+
Receiver, Offset, Length, FullyQualified);
26592665
/// FIXME: When request cancellation is implemented and Xcode adopts it,
26602666
/// don't use 'OncePerASTToken'.
26612667
static const char OncePerASTToken = 0;

0 commit comments

Comments
 (0)