Skip to content

Commit 2507e0e

Browse files
committed
[SourceKit] Support getting semantic tokens for macro expansion buffers
1 parent 4bc03f8 commit 2507e0e

File tree

3 files changed

+78
-9
lines changed

3 files changed

+78
-9
lines changed

lib/IDE/SourceEntityWalker.cpp

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -609,14 +609,19 @@ ASTWalker::PreWalkResult<Expr *> SemaAnnotator::walkToExprPre(Expr *E) {
609609
// We already visited the children.
610610
return doSkipChildren();
611611
} else if (auto ME = dyn_cast<MacroExpansionExpr>(E)) {
612-
// Add a reference to the macro
613-
auto macroRef = ME->getMacroRef();
614-
if (auto *macroDecl = dyn_cast_or_null<MacroDecl>(macroRef.getDecl())) {
615-
auto macroRefType = macroDecl->getDeclaredInterfaceType();
616-
if (!passReference(
617-
macroDecl, macroRefType, ME->getMacroNameLoc(),
618-
ReferenceMetaData(SemaReferenceKind::DeclRef, llvm::None)))
619-
return Action::Stop();
612+
// Add a reference to the macro if this is a true macro expansion *expression*.
613+
// If this is a `MacroExpansionExpr` that expands a declaration macro, the
614+
// substitute decl will be visited by ASTWalker and we would be passing its
615+
// reference if we didn't have this check.
616+
if (!ME->getSubstituteDecl()) {
617+
auto macroRef = ME->getMacroRef();
618+
if (auto *macroDecl = dyn_cast_or_null<MacroDecl>(macroRef.getDecl())) {
619+
auto macroRefType = macroDecl->getDeclaredInterfaceType();
620+
if (!passReference(
621+
macroDecl, macroRefType, ME->getMacroNameLoc(),
622+
ReferenceMetaData(SemaReferenceKind::DeclRef, llvm::None)))
623+
return Action::Stop();
624+
}
620625
}
621626
}
622627

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
@freestanding(declaration)
3+
macro anonymousTypes(_: () -> String) = #externalMacro(module: "MacroDefinition", type: "DefineAnonymousTypesMacro")
4+
5+
#anonymousTypes { "hello" }
6+
7+
// REQUIRES: swift_swift_parser, executable_test
8+
9+
// RUN: %empty-directory(%t)
10+
11+
//##-- Prepare the macro plugin.
12+
// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/../../Macros/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
13+
14+
// Check the output of the the `#anonymousTypes` macro
15+
// RUN: %sourcekitd-test -req=semantic-tokens @__swiftmacro_9MacroUser33_8C2BB8A10AE555140C0EDFDEB4A9572DLl14anonymousTypesfMf0_.swift -primary-file %s -- -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser %s | %FileCheck %s --check-prefix IN_BUFFER
16+
17+
// Check that we get some semantic tokens. Checking exact offsets is brittle.
18+
// IN_BUFFER: source.lang.swift.ref.struct
19+
// IN_BUFFER: key.kind: source.lang.swift.ref.class
20+
21+
// Check that we don't get semantic tokens inside the buffer when requesting semantic tokens for the outer file
22+
// RUN: %sourcekitd-test -req=semantic-tokens %s -- -swift-version 5 -load-plugin-library %t/%target-library-name(MacroDefinition) -module-name MacroUser %s | %FileCheck %s --check-prefix PRIMARY_FILE
23+
// Reference to String in line 2
24+
// PRIMARY_FILE: key.kind: source.lang.swift.ref.struct
25+
// Reference to macro in line 4
26+
// PRIMARY_FILE: key.kind: source.lang.swift.ref.macro
27+
// There should be no other references
28+
// PRIMARY_FILE-NOT: key.kind

tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -952,9 +952,39 @@ class SemanticAnnotator : public SourceEntityWalker {
952952
public:
953953

954954
std::vector<SwiftSemanticToken> SemaToks;
955+
bool IsWalkingMacroExpansionBuffer = false;
955956

956957
SemanticAnnotator(SourceManager &SM, unsigned BufferID)
957-
: SM(SM), BufferID(BufferID) {}
958+
: SM(SM), BufferID(BufferID) {
959+
if (auto GeneratedSourceInfo = SM.getGeneratedSourceInfo(BufferID)) {
960+
switch (GeneratedSourceInfo->kind) {
961+
case GeneratedSourceInfo::ExpressionMacroExpansion:
962+
case GeneratedSourceInfo::FreestandingDeclMacroExpansion:
963+
case GeneratedSourceInfo::AccessorMacroExpansion:
964+
case GeneratedSourceInfo::MemberAttributeMacroExpansion:
965+
case GeneratedSourceInfo::MemberMacroExpansion:
966+
case GeneratedSourceInfo::PeerMacroExpansion:
967+
case GeneratedSourceInfo::ConformanceMacroExpansion:
968+
case GeneratedSourceInfo::ExtensionMacroExpansion:
969+
IsWalkingMacroExpansionBuffer = true;
970+
break;
971+
case GeneratedSourceInfo::ReplacedFunctionBody:
972+
case GeneratedSourceInfo::PrettyPrinted:
973+
break;
974+
}
975+
}
976+
}
977+
978+
MacroWalking getMacroWalkingBehavior() const override {
979+
if (IsWalkingMacroExpansionBuffer) {
980+
// When we are walking a macro expansion buffer, we need to set the macro
981+
// walking behavior to walk the expansion, otherwise we skip over all the
982+
// declarations in the buffer.
983+
return MacroWalking::ArgumentsAndExpansion;
984+
} else {
985+
return SourceEntityWalker::getMacroWalkingBehavior();
986+
}
987+
}
958988

959989
bool visitDeclReference(ValueDecl *D, CharSourceRange Range,
960990
TypeDecl *CtorTyRef, ExtensionDecl *ExtTyRef, Type T,
@@ -996,6 +1026,12 @@ class SemanticAnnotator : public SourceEntityWalker {
9961026
if (!Range.isValid())
9971027
return;
9981028

1029+
// If we are walking into macro expansions, make sure we only report ranges
1030+
// from the requested buffer, not any buffers of child macro expansions.
1031+
if (IsWalkingMacroExpansionBuffer &&
1032+
SM.findBufferContainingLoc(Range.getStart()) != BufferID) {
1033+
return;
1034+
}
9991035
unsigned ByteOffset = SM.getLocOffsetInBuffer(Range.getStart(), BufferID);
10001036
unsigned Length = Range.getByteLength();
10011037
auto Kind = ContextFreeCodeCompletionResult::getCodeCompletionDeclKind(D);

0 commit comments

Comments
 (0)