Skip to content

Commit bb7760b

Browse files
committed
[Refactor] Allow expanding nested macros
This adds a new `primary_file` key, which defaults to `sourcefile`. For nested expansions, `primary_file` should be set to the containing file and `sourcefile` to the name of the macro expansion buffer.
1 parent f1ff695 commit bb7760b

File tree

19 files changed

+241
-144
lines changed

19 files changed

+241
-144
lines changed

include/swift/AST/Decl.h

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -892,8 +892,8 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl> {
892892

893893
/// Retrieve the discriminator for the given custom attribute that names
894894
/// an attached macro.
895-
unsigned getAttachedMacroDiscriminator(
896-
MacroRole role, const CustomAttr *attr) const;
895+
unsigned getAttachedMacroDiscriminator(DeclBaseName macroName, MacroRole role,
896+
const CustomAttr *attr) const;
897897

898898
/// Returns the innermost enclosing decl with an availability annotation.
899899
const Decl *getInnermostDeclWithAvailability() const;
@@ -8318,24 +8318,23 @@ class PostfixOperatorDecl : public OperatorDecl {
83188318
/// is used for parser recovery, e.g. when parsing a floating
83198319
/// attribute list.
83208320
class MissingDecl: public Decl {
8321-
MissingDecl(DeclContext *DC) : Decl(DeclKind::Missing, DC) {
8321+
/// The location that the decl would be if it wasn't missing.
8322+
SourceLoc Loc;
8323+
8324+
MissingDecl(DeclContext *DC, SourceLoc loc)
8325+
: Decl(DeclKind::Missing, DC), Loc(loc) {
83228326
setImplicit();
83238327
}
83248328

83258329
friend class Decl;
8326-
SourceLoc getLocFromSource() const {
8327-
return SourceLoc();
8328-
}
8330+
SourceLoc getLocFromSource() const { return Loc; }
83298331

83308332
public:
8331-
static MissingDecl *
8332-
create(ASTContext &ctx, DeclContext *DC) {
8333-
return new (ctx) MissingDecl(DC);
8333+
static MissingDecl *create(ASTContext &ctx, DeclContext *DC, SourceLoc loc) {
8334+
return new (ctx) MissingDecl(DC, loc);
83348335
}
83358336

8336-
SourceRange getSourceRange() const {
8337-
return SourceRange();
8338-
}
8337+
SourceRange getSourceRange() const { return SourceRange(Loc); }
83398338

83408339
static bool classof(const Decl *D) {
83418340
return D->getKind() == DeclKind::Missing;

include/swift/Refactoring/Refactoring.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ enum class RefactoringKind : int8_t {
3333
};
3434

3535
struct RangeConfig {
36-
unsigned BufferId;
36+
unsigned BufferID;
3737
unsigned Line;
3838
unsigned Column;
3939
unsigned Length;

lib/AST/ASTMangler.cpp

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3810,13 +3810,14 @@ void ASTMangler::appendMacroExpansionContext(
38103810

38113811
outerExpansionLoc = decl->getLoc();
38123812
outerExpansionDC = decl->getDeclContext();
3813-
discriminator = decl->getAttachedMacroDiscriminator(role, attr);
38143813

38153814
if (auto *macroDecl = decl->getResolvedMacro(attr))
38163815
baseName = macroDecl->getBaseName();
38173816
else
38183817
baseName = ctx.getIdentifier("__unknown_macro__");
38193818

3819+
discriminator = decl->getAttachedMacroDiscriminator(baseName, role, attr);
3820+
38203821
break;
38213822
}
38223823

@@ -3896,24 +3897,30 @@ std::string ASTMangler::mangleAttachedMacroExpansion(
38963897
beginMangling();
38973898

38983899
const Decl *attachedTo = decl;
3899-
if (role == MacroRole::MemberAttribute) {
3900-
appendContextOf(cast<ValueDecl>(decl));
3901-
attachedTo = decl->getDeclContext()->getAsDecl();
3902-
} else if (auto valueDecl = dyn_cast<ValueDecl>(decl)) {
3903-
appendAnyDecl(valueDecl);
3900+
if (auto valueDecl = dyn_cast<ValueDecl>(decl)) {
3901+
if (role != MacroRole::MemberAttribute) {
3902+
appendAnyDecl(valueDecl);
3903+
} else {
3904+
// Appending the member would result in a cycle since `VarDecl` appends
3905+
// its type, which would then loop back around to getting the attributes
3906+
// again. We'll instead add a discriminator for each member.
3907+
appendContextOf(valueDecl);
3908+
attachedTo = decl->getDeclContext()->getAsDecl();
3909+
}
39043910
} else {
39053911
appendContext(decl->getDeclContext(), "");
39063912
}
39073913

3908-
StringRef macroName;
3909-
if (auto *macroDecl = attachedTo->getResolvedMacro(attr))
3910-
macroName = macroDecl->getName().getBaseName().userFacingName();
3911-
else
3912-
macroName = "__unknown_macro__";
3914+
DeclBaseName macroName;
3915+
if (auto *macroDecl = attachedTo->getResolvedMacro(attr)) {
3916+
macroName = macroDecl->getName().getBaseName();
3917+
} else {
3918+
macroName = decl->getASTContext().getIdentifier("__unknown_macro__");
3919+
}
39133920

39143921
appendMacroExpansionOperator(
3915-
macroName, role,
3916-
decl->getAttachedMacroDiscriminator(role, attr));
3922+
macroName.userFacingName(), role,
3923+
decl->getAttachedMacroDiscriminator(macroName, role, attr));
39173924
return finalize();
39183925
}
39193926

lib/AST/Decl.cpp

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -441,39 +441,34 @@ MacroDecl *Decl::getResolvedMacro(CustomAttr *customAttr) const {
441441
return dyn_cast_or_null<MacroDecl>(declRef.getDecl());
442442
}
443443

444-
unsigned Decl::getAttachedMacroDiscriminator(
445-
MacroRole role, const CustomAttr *attr
446-
) const {
444+
unsigned Decl::getAttachedMacroDiscriminator(DeclBaseName macroName,
445+
MacroRole role,
446+
const CustomAttr *attr) const {
447447
assert(isAttachedMacro(role) && "Not an attached macro role");
448448

449-
// Member-attribute macros are written on the enclosing declaration,
450-
// but apply to the member itself. Adjust the owning declaration accordingly.
451-
const Decl *owningDecl = this;
452-
if (role == MacroRole::MemberAttribute) {
453-
owningDecl = getDeclContext()->getAsDecl();
454-
}
455-
456-
llvm::SmallDenseMap<Identifier, unsigned> nextDiscriminator;
457-
Optional<unsigned> foundDiscriminator;
449+
if (role != MacroRole::MemberAttribute) {
450+
llvm::SmallDenseMap<Identifier, unsigned> nextDiscriminator;
451+
Optional<unsigned> foundDiscriminator;
458452

459-
owningDecl->forEachAttachedMacro(
460-
role,
461-
[&](CustomAttr *foundAttr, MacroDecl *foundMacro) {
462-
unsigned discriminator =
463-
nextDiscriminator[foundMacro->getBaseIdentifier()]++;
464-
if (attr == foundAttr)
465-
foundDiscriminator = discriminator;
466-
});
453+
forEachAttachedMacro(
454+
role, [&](CustomAttr *foundAttr, MacroDecl *foundMacro) {
455+
unsigned discriminator =
456+
nextDiscriminator[foundMacro->getBaseIdentifier()]++;
457+
if (attr == foundAttr)
458+
foundDiscriminator = discriminator;
459+
});
467460

468-
if (foundDiscriminator)
469-
return *foundDiscriminator;
461+
if (foundDiscriminator)
462+
return *foundDiscriminator;
463+
}
470464

471465
// If that failed, conjure up a discriminator.
466+
// FIXME: Better discriminator for member attributes - add the member name?
472467
ASTContext &ctx = getASTContext();
473-
assert(ctx.Diags.hadAnyError());
468+
assert(role == MacroRole::MemberAttribute || ctx.Diags.hadAnyError());
474469
return ctx.getNextMacroDiscriminator(
475470
MacroDiscriminatorContext::getParentOf(getLoc(), getDeclContext()),
476-
DeclBaseName());
471+
macroName);
477472
}
478473

479474
const Decl *Decl::getInnermostDeclWithAvailability() const {

lib/AST/Module.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,9 @@ SourceFile *ModuleDecl::getSourceFileContainingLocation(SourceLoc loc) {
640640

641641
auto foundSourceFile = *found;
642642
auto foundRange = sourceMgr.getRangeForBuffer(*foundSourceFile->getBufferID());
643-
if (!foundRange.contains(adjustedLoc) && adjustedLoc != foundRange.getStart())
643+
// Positions inside an empty file or at EOF should still be considered within
644+
// this file.
645+
if (!foundRange.contains(adjustedLoc) && adjustedLoc != foundRange.getEnd())
644646
return nullptr;
645647

646648
// Update the last source file.

lib/IDE/SourceEntityWalker.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -684,11 +684,13 @@ bool SemaAnnotator::handleCustomAttributes(Decl *D) {
684684
}
685685
}
686686

687-
// FIXME: This should be getSemanticAttrs if we want to walk macro
688-
// expansions. We've just already typechecked and this list is mutable so...
689-
for (auto *customAttr : D->getAttrs().getAttributes<CustomAttr, true>()) {
690-
if (!shouldWalkMacroArgumentsAndExpansion().second &&
691-
D->getModuleContext()->isInGeneratedBuffer(customAttr->getLocation()))
687+
ModuleDecl *MD = D->getModuleContext();
688+
for (auto *customAttr :
689+
D->getSemanticAttrs().getAttributes<CustomAttr, true>()) {
690+
SourceFile *SF =
691+
MD->getSourceFileContainingLocation(customAttr->getLocation());
692+
ASTNode expansion = SF ? SF->getMacroExpansion() : nullptr;
693+
if (!shouldWalkMacroArgumentsAndExpansion().second && expansion)
692694
continue;
693695

694696
if (auto *Repr = customAttr->getTypeRepr()) {
@@ -700,10 +702,12 @@ bool SemaAnnotator::handleCustomAttributes(Decl *D) {
700702
if (auto macroDecl = D->getResolvedMacro(mutableAttr)) {
701703
Type macroRefType = macroDecl->getDeclaredInterfaceType();
702704
if (!passReference(
703-
macroDecl, macroRefType, DeclNameLoc(Repr->getStartLoc()),
704-
ReferenceMetaData(SemaReferenceKind::DeclRef, None,
705-
/*isImplicit=*/false,
706-
std::make_pair(customAttr, D))))
705+
macroDecl, macroRefType, DeclNameLoc(Repr->getStartLoc()),
706+
ReferenceMetaData(
707+
SemaReferenceKind::DeclRef, None,
708+
/*isImplicit=*/false,
709+
std::make_pair(customAttr,
710+
expansion ? expansion.get<Decl *>() : D))))
707711
return false;
708712
} else if (!Repr->walk(*this)) {
709713
return false;
@@ -865,9 +869,23 @@ bool SemaAnnotator::passCallArgNames(Expr *Fn, ArgumentList *ArgList) {
865869
}
866870

867871
bool SemaAnnotator::shouldIgnore(Decl *D) {
872+
if (!D->isImplicit())
873+
return false;
874+
868875
// TODO: There should really be a separate field controlling whether
869876
// constructors are visited or not
870-
return D->isImplicit() && !isa<ConstructorDecl>(D);
877+
if (isa<ConstructorDecl>(D))
878+
return false;
879+
880+
// Walk into missing decls to visit their attributes if they were generated
881+
// by a member attribute expansion. Note that we would have already skipped
882+
// this decl if we were ignoring expansions, so no need to check that.
883+
if (auto *missing = dyn_cast<MissingDecl>(D)) {
884+
if (D->isInGeneratedBuffer())
885+
return false;
886+
}
887+
888+
return true;
871889
}
872890

873891
bool SourceEntityWalker::walk(SourceFile &SrcFile) {

lib/Parse/ParseDecl.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7136,7 +7136,8 @@ void Parser::parseExpandedAttributeList(SmallVectorImpl<ASTNode> &items) {
71367136

71377137
// Create a `MissingDecl` as a placeholder for the declaration the
71387138
// macro will attach the attribute list to.
7139-
MissingDecl *missing = MissingDecl::create(Context, CurDeclContext);
7139+
MissingDecl *missing =
7140+
MissingDecl::create(Context, CurDeclContext, Tok.getLoc());
71407141
missing->getAttrs() = attributes;
71417142

71427143
items.push_back(ASTNode(missing));

lib/Refactoring/Refactoring.cpp

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -730,27 +730,12 @@ RenameRangeCollector::indexSymbolToRenameLoc(const index::IndexSymbol &symbol,
730730
isFunctionLike, isNonProtocolType};
731731
}
732732

733-
ArrayRef<SourceFile*>
734-
collectSourceFiles(ModuleDecl *MD, SmallVectorImpl<SourceFile *> &Scratch) {
735-
for (auto Unit : MD->getFiles()) {
736-
if (auto SF = dyn_cast<SourceFile>(Unit)) {
737-
Scratch.push_back(SF);
738-
}
739-
}
740-
return llvm::makeArrayRef(Scratch);
741-
}
742-
743-
/// Get the source file that contains the given range and belongs to the module.
733+
/// Get the source file that corresponds to the given buffer.
744734
SourceFile *getContainingFile(ModuleDecl *M, RangeConfig Range) {
745-
SmallVector<SourceFile*, 4> Files;
746-
for (auto File : collectSourceFiles(M, Files)) {
747-
if (File->getBufferID()) {
748-
if (File->getBufferID().value() == Range.BufferId) {
749-
return File;
750-
}
751-
}
752-
}
753-
return nullptr;
735+
auto &SM = M->getASTContext().SourceMgr;
736+
// TODO: We should add an ID -> SourceFile mapping.
737+
return M->getSourceFileContainingLocation(
738+
SM.getRangeForBuffer(Range.BufferID).getStart());
754739
}
755740

756741
class RefactoringAction {
@@ -8802,7 +8787,7 @@ getDescriptiveRefactoringKindName(RefactoringKind Kind) {
88028787
}
88038788

88048789
SourceLoc swift::ide::RangeConfig::getStart(SourceManager &SM) {
8805-
return SM.getLocForLineCol(BufferId, Line, Column);
8790+
return SM.getLocForLineCol(BufferID, Line, Column);
88068791
}
88078792

88088793
SourceLoc swift::ide::RangeConfig::getEnd(SourceManager &SM) {

test/SourceKit/Macros/macro_basic.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,25 @@ struct S4 { }
138138
// ATTACHED_EXPAND: source.edit.kind.active:
139139
// ATTACHED_EXPAND-NEXT: 23:3-23:3 (@__swiftmacro_9MacroUser1SV13myTypeWrapperfMA_.swift) "@accessViaStorage "
140140
// ATTACHED_EXPAND-NEXT: source.edit.kind.active:
141-
// ATTACHED_EXPAND-NEXT: 24:3-24:3 (@__swiftmacro_9MacroUser1SV13myTypeWrapperfMA_.swift) "@accessViaStorage "
141+
// ATTACHED_EXPAND-NEXT: 24:3-24:3 (@__swiftmacro_9MacroUser1SV13myTypeWrapperfMA0_.swift) "@accessViaStorage "
142142
// ATTACHED_EXPAND-NEXT: source.edit.kind.active:
143143
// ATTACHED_EXPAND-NEXT: 22:11-22:11 (@__swiftmacro_9MacroUser1SV13myTypeWrapperfMm_.swift) "
144144
// ATTACHED_EXPAND-NEXT: private var _storage = _Storage()
145145
// ATTACHED_EXPAND-NEXT: "
146146
// ATTACHED_EXPAND-NEXT: source.edit.kind.active:
147147
// ATTACHED_EXPAND-NEXT: 21:1-21:15 ""
148148

149+
//##-- Refactoring expanding the attribute expanded by @myTypeWrapper
150+
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=1:2 @__swiftmacro_9MacroUser1SV13myTypeWrapperfMA_.swift -primary-file %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=NESTED_ATTACHED_EXPAND %s
151+
// NESTED_ATTACHED_EXPAND: source.edit.kind.active:
152+
// NESTED_ATTACHED_EXPAND-NEXT: Macros/macro_basic.swift 23:13-23:13 (@__swiftmacro_9MacroUser1SV1xSivp16accessViaStoragefMa_.swift) "{
153+
// NESTED_ATTACHED_EXPAND-NEXT: get { _storage.x }
154+
// NESTED_ATTACHED_EXPAND-EMPTY:
155+
// NESTED_ATTACHED_EXPAND-NEXT: set { _storage.x = newValue }
156+
// NESTED_ATTACHED_EXPAND-NEXT: }"
157+
// NESTED_ATTACHED_EXPAND-NEXT: source.edit.kind.active:
158+
// NESTED_ATTACHED_EXPAND-NEXT: 1:1-1:18 ""
159+
149160
//##-- Refactoring expanding the first accessor macro
150161
// RUN: %sourcekitd-test -req=refactoring.expand.macro -pos=30:4 %s -- ${COMPILER_ARGS[@]} | %FileCheck -check-prefix=ACCESSOR1_EXPAND %s
151162
// ACCESSOR1_EXPAND: source.edit.kind.active:

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,10 @@ enum class SemanticRefactoringKind {
637637

638638
struct SemanticRefactoringInfo {
639639
SemanticRefactoringKind Kind;
640+
// The name of the source file to start the refactoring in. Empty if it is
641+
// the primary file (in which case the primary file from the AST is used).
642+
// This must match the buffer identifier stored in the source manager.
643+
StringRef SourceFile;
640644
unsigned Line;
641645
unsigned Column;
642646
unsigned Length;
@@ -1045,7 +1049,7 @@ class LangSupport {
10451049
SourceKitCancellationToken CancellationToken,
10461050
CategorizedRenameRangesReceiver Receiver) = 0;
10471051

1048-
virtual void semanticRefactoring(StringRef Filename,
1052+
virtual void semanticRefactoring(StringRef PrimaryFile,
10491053
SemanticRefactoringInfo Info,
10501054
ArrayRef<const char *> Args,
10511055
SourceKitCancellationToken CancellationToken,

0 commit comments

Comments
 (0)