Skip to content

Commit c05c573

Browse files
committed
[Refactoring] Move ExpandMacro and InlineMacro to their own file
1 parent 10b9daf commit c05c573

File tree

3 files changed

+205
-186
lines changed

3 files changed

+205
-186
lines changed

lib/Refactoring/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_swift_host_library(swiftRefactoring STATIC
99
ConvertToDoCatch.cpp
1010
ConvertToSwitchStmt.cpp
1111
ConvertToTernaryExpr.cpp
12+
ExpandMacro.cpp
1213
ExpandSwitchCases.cpp
1314
ExpandTernaryExpr.cpp
1415
ExtractExpr.cpp

lib/Refactoring/ExpandMacro.cpp

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "ContextFinder.h"
14+
#include "RefactoringActions.h"
15+
#include "swift/AST/TypeCheckRequests.h"
16+
17+
using namespace swift::refactoring;
18+
19+
/// Retrieve the macro expansion buffer for the given macro expansion
20+
/// expression.
21+
static llvm::Optional<unsigned>
22+
getMacroExpansionBuffer(SourceManager &sourceMgr,
23+
MacroExpansionExpr *expansion) {
24+
return evaluateOrDefault(
25+
expansion->getDeclContext()->getASTContext().evaluator,
26+
ExpandMacroExpansionExprRequest{expansion}, {});
27+
}
28+
29+
/// Retrieve the macro expansion buffer for the given macro expansion
30+
/// declaration.
31+
static llvm::Optional<unsigned>
32+
getMacroExpansionBuffer(SourceManager &sourceMgr,
33+
MacroExpansionDecl *expansion) {
34+
return evaluateOrDefault(expansion->getASTContext().evaluator,
35+
ExpandMacroExpansionDeclRequest{expansion}, {});
36+
}
37+
38+
/// Retrieve the macro expansion buffers for the given attached macro reference.
39+
static llvm::SmallVector<unsigned, 2>
40+
getMacroExpansionBuffers(MacroDecl *macro, const CustomAttr *attr, Decl *decl) {
41+
auto roles = macro->getMacroRoles() & getAttachedMacroRoles();
42+
if (!roles)
43+
return {};
44+
45+
ASTContext &ctx = macro->getASTContext();
46+
llvm::SmallVector<unsigned, 2> allBufferIDs;
47+
if (roles.contains(MacroRole::Accessor)) {
48+
if (auto storage = dyn_cast<AbstractStorageDecl>(decl)) {
49+
auto bufferIDs =
50+
evaluateOrDefault(ctx.evaluator, ExpandAccessorMacros{storage}, {});
51+
allBufferIDs.append(bufferIDs.begin(), bufferIDs.end());
52+
}
53+
}
54+
55+
if (roles.contains(MacroRole::MemberAttribute)) {
56+
if (auto idc = dyn_cast<IterableDeclContext>(decl)) {
57+
for (auto memberDecl : idc->getAllMembers()) {
58+
auto bufferIDs = evaluateOrDefault(
59+
ctx.evaluator, ExpandMemberAttributeMacros{memberDecl}, {});
60+
allBufferIDs.append(bufferIDs.begin(), bufferIDs.end());
61+
}
62+
}
63+
}
64+
65+
if (roles.contains(MacroRole::Member)) {
66+
auto bufferIDs = evaluateOrDefault(
67+
ctx.evaluator, ExpandSynthesizedMemberMacroRequest{decl}, {});
68+
allBufferIDs.append(bufferIDs.begin(), bufferIDs.end());
69+
}
70+
71+
if (roles.contains(MacroRole::Peer)) {
72+
auto bufferIDs =
73+
evaluateOrDefault(ctx.evaluator, ExpandPeerMacroRequest{decl}, {});
74+
allBufferIDs.append(bufferIDs.begin(), bufferIDs.end());
75+
}
76+
77+
if (roles.contains(MacroRole::Conformance) ||
78+
roles.contains(MacroRole::Extension)) {
79+
if (auto nominal = dyn_cast<NominalTypeDecl>(decl)) {
80+
auto bufferIDs =
81+
evaluateOrDefault(ctx.evaluator, ExpandExtensionMacros{nominal}, {});
82+
allBufferIDs.append(bufferIDs.begin(), bufferIDs.end());
83+
}
84+
}
85+
86+
// Drop any buffers that come from other macros. We could eliminate this
87+
// step by adding more fine-grained requests above, which only expand for a
88+
// single custom attribute.
89+
SourceManager &sourceMgr = ctx.SourceMgr;
90+
auto removedAt = std::remove_if(
91+
allBufferIDs.begin(), allBufferIDs.end(), [&](unsigned bufferID) {
92+
auto generatedInfo = sourceMgr.getGeneratedSourceInfo(bufferID);
93+
if (!generatedInfo)
94+
return true;
95+
96+
return generatedInfo->attachedMacroCustomAttr != attr;
97+
});
98+
allBufferIDs.erase(removedAt, allBufferIDs.end());
99+
return allBufferIDs;
100+
}
101+
102+
/// Given a resolved cursor, determine whether it is for a macro expansion and
103+
/// return the list of macro expansion buffer IDs that are associated with the
104+
/// macro reference here.
105+
static llvm::SmallVector<unsigned, 2>
106+
getMacroExpansionBuffers(SourceManager &sourceMgr, ResolvedCursorInfoPtr Info) {
107+
auto *refInfo = dyn_cast<ResolvedValueRefCursorInfo>(Info);
108+
if (!refInfo || !refInfo->isRef())
109+
return {};
110+
111+
auto *macro = dyn_cast_or_null<MacroDecl>(refInfo->getValueD());
112+
if (!macro)
113+
return {};
114+
115+
// Attached macros
116+
if (auto customAttrRef = refInfo->getCustomAttrRef()) {
117+
auto macro = cast<MacroDecl>(refInfo->getValueD());
118+
return getMacroExpansionBuffers(macro, customAttrRef->first,
119+
customAttrRef->second);
120+
}
121+
122+
// FIXME: A resolved cursor should contain a slice up to its reference.
123+
// We shouldn't need to find it again.
124+
ContextFinder Finder(*Info->getSourceFile(), Info->getLoc(), [&](ASTNode N) {
125+
if (auto *expr =
126+
dyn_cast_or_null<MacroExpansionExpr>(N.dyn_cast<Expr *>())) {
127+
return expr->getStartLoc() == Info->getLoc() ||
128+
expr->getMacroNameLoc().getBaseNameLoc() == Info->getLoc();
129+
} else if (auto *decl =
130+
dyn_cast_or_null<MacroExpansionDecl>(N.dyn_cast<Decl *>())) {
131+
return decl->getStartLoc() == Info->getLoc() ||
132+
decl->getMacroNameLoc().getBaseNameLoc() == Info->getLoc();
133+
}
134+
135+
return false;
136+
});
137+
Finder.resolve();
138+
139+
if (!Finder.getContexts().empty()) {
140+
llvm::Optional<unsigned> bufferID;
141+
if (auto *target = dyn_cast_or_null<MacroExpansionExpr>(
142+
Finder.getContexts()[0].dyn_cast<Expr *>())) {
143+
bufferID = getMacroExpansionBuffer(sourceMgr, target);
144+
} else if (auto *target = dyn_cast_or_null<MacroExpansionDecl>(
145+
Finder.getContexts()[0].dyn_cast<Decl *>())) {
146+
bufferID = getMacroExpansionBuffer(sourceMgr, target);
147+
}
148+
149+
if (bufferID)
150+
return {*bufferID};
151+
}
152+
153+
return {};
154+
}
155+
156+
static bool expandMacro(SourceManager &SM, ResolvedCursorInfoPtr cursorInfo,
157+
SourceEditConsumer &editConsumer,
158+
bool adjustExpansion) {
159+
auto bufferIDs = getMacroExpansionBuffers(SM, cursorInfo);
160+
if (bufferIDs.empty())
161+
return true;
162+
163+
SourceFile *containingSF = cursorInfo->getSourceFile();
164+
if (!containingSF)
165+
return true;
166+
167+
// Send all of the rewritten buffer snippets.
168+
for (auto bufferID : bufferIDs) {
169+
editConsumer.acceptMacroExpansionBuffer(SM, bufferID, containingSF,
170+
adjustExpansion,
171+
/*includeBufferName=*/true);
172+
}
173+
174+
// For an attached macro, remove the custom attribute; it's been fully
175+
// subsumed by its expansions.
176+
if (auto attrRef =
177+
cast<ResolvedValueRefCursorInfo>(cursorInfo)->getCustomAttrRef()) {
178+
const CustomAttr *attachedMacroAttr = attrRef->first;
179+
SourceRange range = attachedMacroAttr->getRangeWithAt();
180+
auto charRange = Lexer::getCharSourceRangeFromSourceRange(SM, range);
181+
editConsumer.remove(SM, charRange);
182+
}
183+
184+
return false;
185+
}
186+
187+
bool RefactoringActionExpandMacro::isApplicable(ResolvedCursorInfoPtr Info,
188+
DiagnosticEngine &Diag) {
189+
// Never list in available refactorings. Only allow requesting directly.
190+
return false;
191+
}
192+
193+
bool RefactoringActionExpandMacro::performChange() {
194+
return expandMacro(SM, CursorInfo, EditConsumer, /*adjustExpansion=*/false);
195+
}
196+
197+
bool RefactoringActionInlineMacro::isApplicable(ResolvedCursorInfoPtr Info,
198+
DiagnosticEngine &Diag) {
199+
return !getMacroExpansionBuffers(Diag.SourceMgr, Info).empty();
200+
}
201+
202+
bool RefactoringActionInlineMacro::performChange() {
203+
return expandMacro(SM, CursorInfo, EditConsumer, /*adjustExpansion=*/true);
204+
}

0 commit comments

Comments
 (0)