[SourceKit/Refactoring] Macro expansion

Add refactoring "Expand Macro" that expands macro expressions.

rdar://102739026
This commit is contained in:
Rintaro Ishizaki
2022-12-06 14:45:25 -08:00
parent 0b29450a3d
commit 9f137074af
6 changed files with 116 additions and 4 deletions

View File

@@ -64,6 +64,8 @@ CURSOR_REFACTORING(AddAsyncAlternative, "Add Async Alternative", add.async-alter
CURSOR_REFACTORING(AddAsyncWrapper, "Add Async Wrapper", add.async-wrapper)
CURSOR_REFACTORING(ExpandMacro, "Expand Macro", expand.macro)
RANGE_REFACTORING(ExtractExpr, "Extract Expression", extract.expr)
RANGE_REFACTORING(ExtractFunction, "Extract Method", extract.function)

View File

@@ -607,10 +607,7 @@ ASTWalker::PreWalkResult<Expr *> SemaAnnotator::walkToExprPre(Expr *E) {
return Action::Stop();
}
if (auto rewritten = ME->getRewritten()) {
if (!rewritten->walk(*this))
return Action::Stop();
}
// Do not walk into ME->getRewritten() because it's not what the user wrote.
// Already walked the children.
return doSkipChildren();

View File

@@ -8421,6 +8421,62 @@ bool RefactoringActionAddAsyncWrapper::performChange() {
return false;
}
static MacroExpansionExpr *
findMacroExpansionTargetExpr(const ResolvedCursorInfo &Info) {
// Handle '#' position in '#macroName(...)'.
if (auto exprInfo = dyn_cast<ResolvedExprStartCursorInfo>(&Info)) {
if (auto target =
dyn_cast_or_null<MacroExpansionExpr>(exprInfo->getTrailingExpr()))
if (target->getRewritten())
return target;
return nullptr;
}
// Handle 'macroName' position in '#macroName(...)'.
if (auto refInfo = dyn_cast<ResolvedValueRefCursorInfo>(&Info)) {
if (refInfo->isRef() && isa_and_nonnull<MacroDecl>(refInfo->getValueD())) {
ContextFinder Finder(
*Info.getSourceFile(), Info.getLoc(), [&](ASTNode N) {
auto *expr =
dyn_cast_or_null<MacroExpansionExpr>(N.dyn_cast<Expr *>());
return expr &&
(expr->getMacroNameLoc().getBaseNameLoc() == Info.getLoc());
});
Finder.resolve();
if (!Finder.getContexts().empty()) {
auto *target =
dyn_cast<MacroExpansionExpr>(Finder.getContexts()[0].get<Expr *>());
if (target->getRewritten())
return target;
}
}
return nullptr;
}
// TODO: handle MacroExpansionDecl.
return nullptr;
}
bool RefactoringActionExpandMacro::isApplicable(const ResolvedCursorInfo &Info,
DiagnosticEngine &Diag) {
return findMacroExpansionTargetExpr(Info) != nullptr;
}
bool RefactoringActionExpandMacro::performChange() {
auto target = findMacroExpansionTargetExpr(CursorInfo);
if (!target)
return true;
auto exprRange =
Lexer::getCharSourceRangeFromSourceRange(SM, target->getSourceRange());
auto rewrittenRange = Lexer::getCharSourceRangeFromSourceRange(
SM, target->getRewritten()->getSourceRange());
auto rewrittenBuffer = SM.extractText(rewrittenRange);
EditConsumer.accept(SM, exprRange, rewrittenBuffer);
return false;
}
} // end of anonymous namespace
StringRef swift::ide::

View File

@@ -22,3 +22,6 @@ func test(x: Int) {
// CHECK: 11:8 | macro/Swift | myLine | s:14swift_ide_test6myLineSifm | Ref,RelCont | rel: 1
// CHECK: 12:20 | macro/Swift | myFilename | s:14swift_ide_test10myFilenamexfm | Ref,RelCont | rel: 1
// CHECK: 13:8 | macro/Swift | myStringify(_:) | s:14swift_ide_test11myStringifyyx_SStxcfm | Ref,RelCont | rel: 1
// CHECK: 13:20 | param/Swift | x | s:14swift_ide_test0C01xySi_tFACL_Sivp | Ref,Read,RelCont | rel: 1
// CHECK: 13:22 | static-method/infix-operator/Swift | +(_:_:) | s:Si1poiyS2i_SitFZ | Ref,Call,RelCall,RelCont | rel: 1
// CHECK: 13:24 | param/Swift | x | s:14swift_ide_test0C01xySi_tFACL_Sivp | Ref,Read,RelCont | rel: 1

View File

@@ -0,0 +1,53 @@
macro stringify<T>(_ value: T) -> (T, String) = MacroDefinition.StringifyMacro
func testStringify(a: Int, b: Int) {
_ = #stringify(a + b)
}
// FIXME: Swift parser is not enabled on Linux CI yet.
// REQUIRES: OS=macosx
// REQUIRES=shell
// RUN: %empty-directory(%t)
//##-- Prepare the macro plugin.
// RUN: %target-build-swift -I %swift-host-lib-dir -L %swift-host-lib-dir -emit-library -o %t/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/../../Macros/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath
// RUN: COMPILER_ARGS=( \
// RUN: -enable-experimental-feature Macros \
// RUN: -load-plugin-library %t/%target-library-name(MacroDefinition) \
// RUN: -I %swift-host-lib-dir \
// RUN: -module-name MacroUser \
// RUN: %s \
// RUN: )
//##-- cursor-info at '#' position.
// RUN: %sourcekitd-test -req=cursor -pos=4:7 -cursor-action %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=CURSOR_POUND %s
// CURSOR_POUND-LABEL: ACTIONS BEGIN
// CURSOR_POUND: source.refactoring.kind.expand.macro
// CURSOR_POUND-NEXT: Expand Macro
// CURSOR_POUND: ACTIONS END
//##-- cursor-info at 'stringify' position.
// RUN: %sourcekitd-test -req=cursor -pos=4:8 -cursor-action %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=CURSOR_MACRONAME %s
// CURSOR_MACRONAME: source.lang.swift.ref.macro (1:7-1:16)
// CURSOR_MACRONAME: (T) -> (T, String)
// CURSOR_MACRONAME: <Declaration>macro stringify&lt;T&gt;(_ value: <Type usr="s:9MacroUser1TL_xmfp">T</Type>) -&gt; (<Type usr="s:9MacroUser1TL_xmfp">T</Type>, <Type usr="s:SS">String</Type>) = MacroDefinition.StringifyMacro</Declaration>
// CURSOR_MACRONAME: <decl.macro><syntaxtype.keyword>macro</syntaxtype.keyword> <decl.name>stringify</decl.name>&lt;<decl.generic_type_param usr="s:9MacroUser1TL_xmfp"><decl.generic_type_param.name>T</decl.generic_type_param.name></decl.generic_type_param>&gt;(<decl.var.parameter><decl.var.parameter.argument_label>_</decl.var.parameter.argument_label> <decl.var.parameter.name>value</decl.var.parameter.name>: <decl.var.parameter.type><ref.generic_type_param usr="s:9MacroUser1TL_xmfp">T</ref.generic_type_param></decl.var.parameter.type></decl.var.parameter>) -&gt; <decl.function.returntype><tuple>(<tuple.element><tuple.element.type><ref.generic_type_param usr="s:9MacroUser1TL_xmfp">T</ref.generic_type_param></tuple.element.type></tuple.element>, <tuple.element><tuple.element.type><ref.struct usr="s:SS">String</ref.struct></tuple.element.type></tuple.element>)</tuple></decl.function.returntype> = MacroDefinition.StringifyMacro</decl.macro>
// CURSOR_MACRONAME-LABEL: ACTIONS BEGIN
// CURSOR_MACRONAME: source.refactoring.kind.rename.global
// CURSOR_MACRONAME-NEXT: Global Rename
// CURSOR_MACRONAME: source.refactoring.kind.expand.macro
// CURSOR_MACRONAME-NEXT: Expand Macro
// CURSOR_MACRONAME: ACTIONS END
//##-- Refactoring at both position.
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=4:7 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=EXPAND %s
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=4:8 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=EXPAND %s
// EXPAND: source.edit.kind.active:
// EXPAND-NEXT: 4:7-4:24 "(a + b, "a + b")"

View File

@@ -126,6 +126,7 @@ public:
UID_FOR(Destructor)
UID_FOR(Subscript)
UID_FOR(OpaqueType)
UID_FOR(Macro)
#undef UID_FOR
};