From b2dab4d35f0639475ca9fcdbab3ea0b5e22bd388 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 30 May 2023 15:18:50 -0700 Subject: [PATCH 1/9] [Macros] Factor out SourceFile creation for macro expanded buffer Introduce 'createMacroSourceFile()' that creates macro expanded 'SourceFile' object. Use it from various macro expansion functions. (cherry picked from commit 78b22295a47a46866ee8a0b7d7b30aaa8f80d7df) --- lib/Sema/TypeCheckMacros.cpp | 354 ++++++++++++++++------------------- 1 file changed, 163 insertions(+), 191 deletions(-) diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 1861cb54d6df0..1db4a6f69091f 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -705,6 +705,159 @@ static std::string expandMacroDefinition( return expandedResult; } +static GeneratedSourceInfo::Kind getGeneratedSourceInfoKind(MacroRole role) { + switch (role) { + case MacroRole::Expression: + return GeneratedSourceInfo::ExpressionMacroExpansion; + case MacroRole::Declaration: + case MacroRole::CodeItem: + return GeneratedSourceInfo::FreestandingDeclMacroExpansion; + case MacroRole::Accessor: + return GeneratedSourceInfo::AccessorMacroExpansion; + case MacroRole::MemberAttribute: + return GeneratedSourceInfo::MemberAttributeMacroExpansion; + case MacroRole::Member: + return GeneratedSourceInfo::MemberMacroExpansion; + case MacroRole::Peer: + return GeneratedSourceInfo::PeerMacroExpansion; + case MacroRole::Conformance: + return GeneratedSourceInfo::ConformanceMacroExpansion; + } + llvm_unreachable("unhandled MacroRole"); +} + +// If this storage declaration is a variable with an explicit initializer, +// return the range from the `=` to the end of the explicit initializer. +static Optional +getExplicitInitializerRange(AbstractStorageDecl *storage) { + auto var = dyn_cast(storage); + if (!var) + return None; + + auto pattern = var->getParentPatternBinding(); + if (!pattern) + return None; + + unsigned index = pattern->getPatternEntryIndexForVarDecl(var); + SourceLoc equalLoc = pattern->getEqualLoc(index); + SourceRange initRange = pattern->getOriginalInitRange(index); + if (equalLoc.isInvalid() || initRange.End.isInvalid()) + return None; + + return SourceRange(equalLoc, initRange.End); +} + +static CharSourceRange getExpansionInsertionRange(MacroRole role, + ASTNode target, + SourceManager &sourceMgr) { + switch (role) { + case MacroRole::Accessor: { + auto storage = cast(target.get()); + auto bracesRange = storage->getBracesRange(); + + // Compute the location where the accessors will be added. + if (bracesRange.Start.isValid()) { + // We have braces already, so insert them inside the leading '{'. + return CharSourceRange( + Lexer::getLocForEndOfToken(sourceMgr, bracesRange.Start), 0); + } else if (auto initRange = getExplicitInitializerRange(storage)) { + // The accessor had an initializer, so the initializer (including + // the `=`) is replaced by the accessors. + return Lexer::getCharSourceRangeFromSourceRange(sourceMgr, *initRange); + } else { + // The accessors go at the end. + SourceLoc endLoc = storage->getEndLoc(); + if (auto var = dyn_cast(storage)) { + if (auto pattern = var->getParentPattern()) + endLoc = pattern->getEndLoc(); + } + + return CharSourceRange(Lexer::getLocForEndOfToken(sourceMgr, endLoc), 0); + } + } + case MacroRole::MemberAttribute: { + SourceLoc startLoc; + if (auto valueDecl = dyn_cast(target.get())) + startLoc = valueDecl->getAttributeInsertionLoc(/*forModifier=*/false); + else + startLoc = target.getStartLoc(); + + return CharSourceRange(startLoc, 0); + } + case MacroRole::Member: { + // Semantically, we insert members right before the closing brace. + SourceLoc rightBraceLoc; + if (auto nominal = dyn_cast(target.get())) { + rightBraceLoc = nominal->getBraces().End; + } else { + auto ext = cast(target.get()); + rightBraceLoc = ext->getBraces().End; + } + + return CharSourceRange(rightBraceLoc, 0); + } + case MacroRole::Peer: { + SourceLoc afterDeclLoc = + Lexer::getLocForEndOfToken(sourceMgr, target.getEndLoc()); + return CharSourceRange(afterDeclLoc, 0); + break; + } + + case MacroRole::Conformance: { + SourceLoc afterDeclLoc = + Lexer::getLocForEndOfToken(sourceMgr, target.getEndLoc()); + return CharSourceRange(afterDeclLoc, 0); + } + + case MacroRole::Expression: + case MacroRole::Declaration: + case MacroRole::CodeItem: + return Lexer::getCharSourceRangeFromSourceRange(sourceMgr, + target.getSourceRange()); + } + llvm_unreachable("unhandled MacroRole"); +} + +static SourceFile * +createMacroSourceFile(std::unique_ptr buffer, + MacroRole role, ASTNode target, DeclContext *dc, + CustomAttr *attr) { + ASTContext &ctx = dc->getASTContext(); + SourceManager &sourceMgr = ctx.SourceMgr; + + // Dump macro expansions to standard output, if requested. + if (ctx.LangOpts.DumpMacroExpansions) { + llvm::errs() << buffer->getBufferIdentifier() + << "\n------------------------------\n" + << buffer->getBuffer() + << "\n------------------------------\n"; + } + + CharSourceRange generatedOriginalSourceRange = + getExpansionInsertionRange(role, target, sourceMgr); + GeneratedSourceInfo::Kind generatedSourceKind = + getGeneratedSourceInfoKind(role); + + // Create a new source buffer with the contents of the expanded macro. + unsigned macroBufferID = sourceMgr.addNewSourceBuffer(std::move(buffer)); + auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID); + GeneratedSourceInfo sourceInfo{generatedSourceKind, + generatedOriginalSourceRange, + macroBufferRange, + target.getOpaqueValue(), + dc, + attr}; + sourceMgr.setGeneratedSourceInfo(macroBufferID, sourceInfo); + + // Create a source file to hold the macro buffer. This is automatically + // registered with the enclosing module. + auto macroSourceFile = new (ctx) SourceFile( + *dc->getParentModule(), SourceFileKind::MacroExpansion, macroBufferID, + /*parsingOpts=*/{}, /*isPrimary=*/false); + macroSourceFile->setImports(dc->getParentSourceFile()->getImports()); + return macroSourceFile; +} + Optional swift::expandMacroExpr(MacroExpansionExpr *mee) { DeclContext *dc = mee->getDeclContext(); @@ -810,36 +963,12 @@ swift::expandMacroExpr(MacroExpansionExpr *mee) { #endif } } + SourceFile *macroSourceFile = createMacroSourceFile( + std::move(evaluatedSource), MacroRole::Expression, mee, dc, + /*attr=*/nullptr); - // Dump macro expansions to standard output, if requested. - if (ctx.LangOpts.DumpMacroExpansions) { - llvm::errs() << evaluatedSource->getBufferIdentifier() << " as " - << expandedType.getString() - << "\n------------------------------\n" - << evaluatedSource->getBuffer() - << "\n------------------------------\n"; - } - - // Create a new source buffer with the contents of the expanded macro. - unsigned macroBufferID = - sourceMgr.addNewSourceBuffer(std::move(evaluatedSource)); + auto macroBufferID = *macroSourceFile->getBufferID(); auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID); - GeneratedSourceInfo sourceInfo{ - GeneratedSourceInfo::ExpressionMacroExpansion, - Lexer::getCharSourceRangeFromSourceRange( - sourceMgr, mee->getSourceRange()), - macroBufferRange, - ASTNode(mee).getOpaqueValue(), - dc - }; - sourceMgr.setGeneratedSourceInfo(macroBufferID, sourceInfo); - - // Create a source file to hold the macro buffer. This is automatically - // registered with the enclosing module. - auto macroSourceFile = new (ctx) SourceFile( - *dc->getParentModule(), SourceFileKind::MacroExpansion, macroBufferID, - /*parsingOpts=*/{}, /*isPrimary=*/false); - macroSourceFile->setImports(sourceFile->getImports()); // Retrieve the parsed expression from the list of top-level items. auto topLevelItems = macroSourceFile->getTopLevelItems(); @@ -890,7 +1019,6 @@ Optional swift::expandFreestandingMacro(MacroExpansionDecl *med) { auto *dc = med->getDeclContext(); ASTContext &ctx = dc->getASTContext(); - SourceManager &sourceMgr = ctx.SourceMgr; auto moduleDecl = dc->getParentModule(); auto sourceFile = moduleDecl->getSourceFileContainingLocation(med->getLoc()); @@ -1004,34 +1132,9 @@ swift::expandFreestandingMacro(MacroExpansionDecl *med) { } } - // Dump macro expansions to standard output, if requested. - if (ctx.LangOpts.DumpMacroExpansions) { - llvm::errs() << evaluatedSource->getBufferIdentifier() - << "\n------------------------------\n" - << evaluatedSource->getBuffer() - << "\n------------------------------\n"; - } - - // Create a new source buffer with the contents of the expanded macro. - unsigned macroBufferID = - sourceMgr.addNewSourceBuffer(std::move(evaluatedSource)); - auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID); - GeneratedSourceInfo sourceInfo{ - GeneratedSourceInfo::FreestandingDeclMacroExpansion, - Lexer::getCharSourceRangeFromSourceRange( - sourceMgr, med->getSourceRange()), - macroBufferRange, - ASTNode(med).getOpaqueValue(), - dc - }; - sourceMgr.setGeneratedSourceInfo(macroBufferID, sourceInfo); - - // Create a source file to hold the macro buffer. This is automatically - // registered with the enclosing module. - auto macroSourceFile = new (ctx) SourceFile( - *dc->getParentModule(), SourceFileKind::MacroExpansion, macroBufferID, - /*parsingOpts=*/{}, /*isPrimary=*/false); - macroSourceFile->setImports(sourceFile->getImports()); + SourceFile *macroSourceFile = createMacroSourceFile( + std::move(evaluatedSource), MacroRole::Declaration, med, dc, + /*attr=*/nullptr); validateMacroExpansion(macroSourceFile, macro, /*attachedTo*/nullptr, @@ -1045,28 +1148,7 @@ swift::expandFreestandingMacro(MacroExpansionDecl *med) { if (auto *decl = item.dyn_cast()) decl->setDeclContext(dc); } - return macroBufferID; -} - -// If this storage declaration is a variable with an explicit initializer, -// return the range from the `=` to the end of the explicit initializer. -static Optional getExplicitInitializerRange( - AbstractStorageDecl *storage) { - auto var = dyn_cast(storage); - if (!var) - return None; - - auto pattern = var->getParentPatternBinding(); - if (!pattern) - return None; - - unsigned index = pattern->getPatternEntryIndexForVarDecl(var); - SourceLoc equalLoc = pattern->getEqualLoc(index); - SourceRange initRange = pattern->getOriginalInitRange(index); - if (equalLoc.isInvalid() || initRange.End.isInvalid()) - return None; - - return SourceRange(equalLoc, initRange.End); + return *macroSourceFile->getBufferID(); } static SourceFile * @@ -1083,7 +1165,6 @@ evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, CustomAttr *attr, } ASTContext &ctx = dc->getASTContext(); - SourceManager &sourceMgr = ctx.SourceMgr; auto moduleDecl = dc->getParentModule(); @@ -1222,117 +1303,8 @@ evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, CustomAttr *attr, } } - // Dump macro expansions to standard output, if requested. - if (ctx.LangOpts.DumpMacroExpansions) { - llvm::errs() << evaluatedSource->getBufferIdentifier() - << "\n------------------------------\n" - << evaluatedSource->getBuffer() - << "\n------------------------------\n"; - } - - CharSourceRange generatedOriginalSourceRange; - GeneratedSourceInfo::Kind generatedSourceKind; - switch (role) { - case MacroRole::Accessor: { - generatedSourceKind = GeneratedSourceInfo::AccessorMacroExpansion; - - // Compute the location where the accessors will be added. - auto storage = cast(attachedTo); - auto bracesRange = storage->getBracesRange(); - if (bracesRange.Start.isValid()) { - // We have braces already, so insert them inside the leading '{'. - generatedOriginalSourceRange = CharSourceRange( - Lexer::getLocForEndOfToken(sourceMgr, bracesRange.Start), 0); - } else if (auto initRange = getExplicitInitializerRange(storage)) { - // The accessor had an initializer, so the initializer (including - // the `=`) is replaced by the accessors. - generatedOriginalSourceRange = - Lexer::getCharSourceRangeFromSourceRange(sourceMgr, *initRange); - } else { - // The accessors go at the end. - SourceLoc endLoc = storage->getEndLoc(); - if (auto var = dyn_cast(storage)) { - if (auto pattern = var->getParentPattern()) - endLoc = pattern->getEndLoc(); - } - - generatedOriginalSourceRange = CharSourceRange( - Lexer::getLocForEndOfToken(sourceMgr, endLoc), 0); - } - - break; - } - - case MacroRole::MemberAttribute: { - generatedSourceKind = GeneratedSourceInfo::MemberAttributeMacroExpansion; - SourceLoc startLoc; - if (auto valueDecl = dyn_cast(attachedTo)) - startLoc = valueDecl->getAttributeInsertionLoc(/*forModifier=*/false); - else - startLoc = attachedTo->getStartLoc(); - - generatedOriginalSourceRange = CharSourceRange(startLoc, 0); - break; - } - - case MacroRole::Member: { - generatedSourceKind = GeneratedSourceInfo::MemberMacroExpansion; - - // Semantically, we insert members right before the closing brace. - SourceLoc rightBraceLoc; - if (auto nominal = dyn_cast(attachedTo)) { - rightBraceLoc = nominal->getBraces().End; - } else { - auto ext = cast(attachedTo); - rightBraceLoc = ext->getBraces().End; - } - - generatedOriginalSourceRange = CharSourceRange(rightBraceLoc, 0); - break; - } - - case MacroRole::Peer: { - generatedSourceKind = GeneratedSourceInfo::PeerMacroExpansion; - SourceLoc afterDeclLoc = - Lexer::getLocForEndOfToken(sourceMgr, attachedTo->getEndLoc()); - generatedOriginalSourceRange = CharSourceRange(afterDeclLoc, 0); - break; - } - - case MacroRole::Conformance: { - generatedSourceKind = GeneratedSourceInfo::ConformanceMacroExpansion; - SourceLoc afterDeclLoc = - Lexer::getLocForEndOfToken(sourceMgr, attachedTo->getEndLoc()); - generatedOriginalSourceRange = CharSourceRange(afterDeclLoc, 0); - break; - } - - case MacroRole::Expression: - case MacroRole::Declaration: - case MacroRole::CodeItem: - llvm_unreachable("freestanding macro in attached macro evaluation"); - } - - // Create a new source buffer with the contents of the expanded macro. - unsigned macroBufferID = - sourceMgr.addNewSourceBuffer(std::move(evaluatedSource)); - auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID); - GeneratedSourceInfo sourceInfo{ - generatedSourceKind, - generatedOriginalSourceRange, - macroBufferRange, - ASTNode(attachedTo).getOpaqueValue(), - dc, - attr - }; - sourceMgr.setGeneratedSourceInfo(macroBufferID, sourceInfo); - - // Create a source file to hold the macro buffer. This is automatically - // registered with the enclosing module. - auto macroSourceFile = new (ctx) SourceFile( - *dc->getParentModule(), SourceFileKind::MacroExpansion, macroBufferID, - /*parsingOpts=*/{}, /*isPrimary=*/false); - macroSourceFile->setImports(declSourceFile->getImports()); + SourceFile *macroSourceFile = createMacroSourceFile( + std::move(evaluatedSource), role, attachedTo, dc, attr); validateMacroExpansion(macroSourceFile, macro, dyn_cast(attachedTo), role); From 3a24dcd669d0575f8fe2fcf07ddff9ba9ef8c8bd Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 30 May 2023 14:14:59 -0700 Subject: [PATCH 2/9] [Macros] Unify MacroExpansionDecl/MacroExpansionExpr expansion logic 'MacroExpansionDecl' and 'MacroExpansionExpr' have many common methods. Introduce a common base class 'FreestandingMacroExpansion' that holds 'MacroExpansionInfo'. Factor out common expansion logic to 'evaluateFreestandingMacro' function that resembles 'evaluateAttachedMacro'. (cherry picked from commit 86d405bcd01bcb8046fa9f2c85a8d709bfc43abf) --- include/swift/AST/ASTMangler.h | 4 +- include/swift/AST/Decl.h | 67 ++--- include/swift/AST/Expr.h | 54 ++-- .../swift/AST/FreestandingMacroExpansion.h | 113 ++++++++ include/swift/AST/MacroDiscriminatorContext.h | 6 +- include/swift/AST/PrettyStackTrace.h | 21 +- include/swift/AST/TypeCheckRequests.h | 12 +- lib/AST/ASTMangler.cpp | 29 +- lib/AST/CMakeLists.txt | 1 + lib/AST/Decl.cpp | 38 +-- lib/AST/Expr.cpp | 25 +- lib/AST/FreestandingMacroExpansion.cpp | 56 ++++ lib/AST/PrettyStackTrace.cpp | 16 +- lib/AST/TypeCheckRequests.cpp | 44 ++-- lib/Parse/ParseDecl.cpp | 2 +- lib/Parse/ParseExpr.cpp | 7 +- lib/Sema/CSApply.cpp | 2 +- lib/Sema/TypeCheckMacros.cpp | 249 ++++++------------ 18 files changed, 377 insertions(+), 369 deletions(-) create mode 100644 include/swift/AST/FreestandingMacroExpansion.h create mode 100644 lib/AST/FreestandingMacroExpansion.cpp diff --git a/include/swift/AST/ASTMangler.h b/include/swift/AST/ASTMangler.h index 141aa27e4e0eb..3aae2b5490690 100644 --- a/include/swift/AST/ASTMangler.h +++ b/include/swift/AST/ASTMangler.h @@ -16,6 +16,7 @@ #include "swift/Basic/Mangler.h" #include "swift/AST/Types.h" #include "swift/AST/Decl.h" +#include "swift/AST/FreestandingMacroExpansion.h" #include "swift/Basic/TaggedUnion.h" namespace clang { @@ -367,8 +368,7 @@ class ASTMangler : public Mangler { mangleRuntimeAttributeGeneratorEntity(const ValueDecl *decl, CustomAttr *attr, SymbolKind SKind = SymbolKind::Default); - std::string mangleMacroExpansion(const MacroExpansionExpr *expansion); - std::string mangleMacroExpansion(const MacroExpansionDecl *expansion); + std::string mangleMacroExpansion(const FreestandingMacroExpansion *expansion); std::string mangleAttachedMacroExpansion( const Decl *decl, CustomAttr *attr, MacroRole role); diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index bbea62516e69b..a9a1d30b6f20c 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -26,6 +26,7 @@ #include "swift/AST/DefaultArgumentKind.h" #include "swift/AST/DiagnosticConsumer.h" #include "swift/AST/DiagnosticEngine.h" +#include "swift/AST/FreestandingMacroExpansion.h" #include "swift/AST/GenericParamKey.h" #include "swift/AST/IfConfigClause.h" #include "swift/AST/LayoutConstraint.h" @@ -8618,69 +8619,28 @@ class MacroDecl : public GenericContext, public ValueDecl { using Decl::getASTContext; }; -/// Information about a macro expansion that is common between macro -/// expansion declarations and expressions. -/// -/// Instances of these types will be shared among paired macro expansion -/// declaration/expression nodes. -struct MacroExpansionInfo : ASTAllocated { - SourceLoc SigilLoc; - DeclNameRef MacroName; - DeclNameLoc MacroNameLoc; - SourceLoc LeftAngleLoc, RightAngleLoc; - ArrayRef GenericArgs; - ArgumentList *ArgList; - - /// The referenced macro. - ConcreteDeclRef macroRef; - - MacroExpansionInfo(SourceLoc sigilLoc, - DeclNameRef macroName, - DeclNameLoc macroNameLoc, - SourceLoc leftAngleLoc, SourceLoc rightAngleLoc, - ArrayRef genericArgs, - ArgumentList *argList) - : SigilLoc(sigilLoc), MacroName(macroName), MacroNameLoc(macroNameLoc), - LeftAngleLoc(leftAngleLoc), RightAngleLoc(rightAngleLoc), - GenericArgs(genericArgs), ArgList(argList) { } -}; - -class MacroExpansionDecl : public Decl { - MacroExpansionInfo *info; +class MacroExpansionDecl : public Decl, public FreestandingMacroExpansion { public: enum : unsigned { InvalidDiscriminator = 0xFFFF }; MacroExpansionDecl(DeclContext *dc, MacroExpansionInfo *info); - MacroExpansionDecl(DeclContext *dc, SourceLoc poundLoc, DeclNameRef macro, - DeclNameLoc macroLoc, - SourceLoc leftAngleLoc, - ArrayRef genericArgs, - SourceLoc rightAngleLoc, - ArgumentList *args); + static MacroExpansionDecl *create(DeclContext *dc, SourceLoc poundLoc, + DeclNameRef macro, DeclNameLoc macroLoc, + SourceLoc leftAngleLoc, + ArrayRef genericArgs, + SourceLoc rightAngleLoc, + ArgumentList *args); - ArrayRef getGenericArgs() const { - return info->GenericArgs; - } + DeclContext *getDeclContext() const { return Decl::getDeclContext(); } - SourceRange getGenericArgsRange() const { - return SourceRange(info->LeftAngleLoc, info->RightAngleLoc); + SourceRange getSourceRange() const { + return getExpansionInfo()->getSourceRange(); } - - SourceRange getSourceRange() const; - SourceLoc getLocFromSource() const { return info->SigilLoc; } - SourceLoc getPoundLoc() const { return info->SigilLoc; } - DeclNameLoc getMacroNameLoc() const { return info->MacroNameLoc; } - DeclNameRef getMacroName() const { return info->MacroName; } - ArgumentList *getArgs() const { return info->ArgList; } - void setArgs(ArgumentList *args) { info->ArgList = args; } + SourceLoc getLocFromSource() const { return getExpansionInfo()->SigilLoc; } using ExprOrStmtExpansionCallback = llvm::function_ref; void forEachExpandedExprOrStmt(ExprOrStmtExpansionCallback) const; - ConcreteDeclRef getMacroRef() const { return info->macroRef; } - void setMacroRef(ConcreteDeclRef ref) { info->macroRef = ref; } - - MacroExpansionInfo *getExpansionInfo() const { return info; } /// Returns a discriminator which determines this macro expansion's index /// in the sequence of macro expansions within the current function. @@ -8703,6 +8663,9 @@ class MacroExpansionDecl : public Decl { static bool classof(const Decl *D) { return D->getKind() == DeclKind::MacroExpansion; } + static bool classof(const FreestandingMacroExpansion *expansion) { + return expansion->getFreestandingMacroKind() == FreestandingMacroKind::Decl; + } }; /// Find references to the given generic parameter in the type signature of the diff --git a/include/swift/AST/Expr.h b/include/swift/AST/Expr.h index 3636517bf7e70..c9092bf925472 100644 --- a/include/swift/AST/Expr.h +++ b/include/swift/AST/Expr.h @@ -25,6 +25,7 @@ #include "swift/AST/Decl.h" #include "swift/AST/DeclContext.h" #include "swift/AST/DeclNameLoc.h" +#include "swift/AST/FreestandingMacroExpansion.h" #include "swift/AST/FunctionRefKind.h" #include "swift/AST/ProtocolConformanceRef.h" #include "swift/AST/TypeAlignments.h" @@ -6214,10 +6215,10 @@ class TypeJoinExpr final : public Expr, /// An invocation of a macro expansion, spelled with `#` for freestanding /// macros or `@` for attached macros. -class MacroExpansionExpr final : public Expr { +class MacroExpansionExpr final : public Expr, + public FreestandingMacroExpansion { private: DeclContext *DC; - MacroExpansionInfo *info; Expr *Rewritten; MacroRoles Roles; MacroExpansionDecl *SubstituteDecl; @@ -6226,47 +6227,31 @@ class MacroExpansionExpr final : public Expr { enum : unsigned { InvalidDiscriminator = 0xFFFF }; explicit MacroExpansionExpr(DeclContext *dc, MacroExpansionInfo *info, - MacroRoles roles, - bool isImplicit = false, + MacroRoles roles, bool isImplicit = false, Type ty = Type()) : Expr(ExprKind::MacroExpansion, isImplicit, ty), - DC(dc), info(info), Rewritten(nullptr), Roles(roles), - SubstituteDecl(nullptr) { + FreestandingMacroExpansion(FreestandingMacroKind::Expr, info), DC(dc), + Rewritten(nullptr), Roles(roles), SubstituteDecl(nullptr) { Bits.MacroExpansionExpr.Discriminator = InvalidDiscriminator; } - explicit MacroExpansionExpr(DeclContext *dc, - SourceLoc sigilLoc, DeclNameRef macroName, - DeclNameLoc macroNameLoc, - SourceLoc leftAngleLoc, - ArrayRef genericArgs, - SourceLoc rightAngleLoc, - ArgumentList *argList, - MacroRoles roles, - bool isImplicit = false, - Type ty = Type()); - - DeclNameRef getMacroName() const { return info->MacroName; } - DeclNameLoc getMacroNameLoc() const { return info->MacroNameLoc; } + static MacroExpansionExpr * + create(DeclContext *dc, SourceLoc sigilLoc, DeclNameRef macroName, + DeclNameLoc macroNameLoc, SourceLoc leftAngleLoc, + ArrayRef genericArgs, SourceLoc rightAngleLoc, + ArgumentList *argList, MacroRoles roles, bool isImplicit = false, + Type ty = Type()); Expr *getRewritten() const { return Rewritten; } void setRewritten(Expr *rewritten) { Rewritten = rewritten; } - ArrayRef getGenericArgs() const { return info->GenericArgs; } - - SourceRange getGenericArgsRange() const { - return SourceRange(info->LeftAngleLoc, info->RightAngleLoc); + ArgumentList *getArgs() const { + return FreestandingMacroExpansion::getArgs(); } - ArgumentList *getArgs() const { return info->ArgList; } - void setArgs(ArgumentList *newArgs) { info->ArgList = newArgs; } - MacroRoles getMacroRoles() const { return Roles; } - SourceLoc getLoc() const { return info->SigilLoc; } - - ConcreteDeclRef getMacroRef() const { return info->macroRef; } - void setMacroRef(ConcreteDeclRef ref) { info->macroRef = ref; } + SourceLoc getLoc() const { return getPoundLoc(); } DeclContext *getDeclContext() const { return DC; } void setDeclContext(DeclContext *dc) { DC = dc; } @@ -6289,9 +6274,9 @@ class MacroExpansionExpr final : public Expr { Bits.MacroExpansionExpr.Discriminator = discriminator; } - MacroExpansionInfo *getExpansionInfo() const { return info; } - - SourceRange getSourceRange() const; + SourceRange getSourceRange() const { + return getExpansionInfo()->getSourceRange(); + } MacroExpansionDecl *createSubstituteDecl(); MacroExpansionDecl *getSubstituteDecl() const; @@ -6299,6 +6284,9 @@ class MacroExpansionExpr final : public Expr { static bool classof(const Expr *E) { return E->getKind() == ExprKind::MacroExpansion; } + static bool classof(const FreestandingMacroExpansion *expansion) { + return expansion->getFreestandingMacroKind() == FreestandingMacroKind::Expr; + } }; inline bool Expr::isInfixOperator() const { diff --git a/include/swift/AST/FreestandingMacroExpansion.h b/include/swift/AST/FreestandingMacroExpansion.h new file mode 100644 index 0000000000000..5907d37193e58 --- /dev/null +++ b/include/swift/AST/FreestandingMacroExpansion.h @@ -0,0 +1,113 @@ +//===--- FreestandingMacroExpansion.h ------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_AST_FREESTANDING_MACRO_EXPANSION_H +#define SWIFT_AST_FREESTANDING_MACRO_EXPANSION_H + +#include "swift/AST/ASTAllocated.h" +#include "swift/AST/ASTNode.h" +#include "swift/AST/ConcreteDeclRef.h" +#include "swift/AST/DeclNameLoc.h" +#include "swift/AST/Identifier.h" +#include "swift/Basic/SourceLoc.h" + +namespace swift { +class MacroExpansionDecl; +class MacroExpansionExpr; +class Expr; +class Decl; +class ArgumentList; + +/// Information about a macro expansion that is common between macro +/// expansion declarations and expressions. +/// +/// Instances of these types will be shared among paired macro expansion +/// declaration/expression nodes. +struct MacroExpansionInfo : ASTAllocated { + SourceLoc SigilLoc; + DeclNameRef MacroName; + DeclNameLoc MacroNameLoc; + SourceLoc LeftAngleLoc, RightAngleLoc; + llvm::ArrayRef GenericArgs; + ArgumentList *ArgList; + + /// The referenced macro. + ConcreteDeclRef macroRef; + + MacroExpansionInfo(SourceLoc sigilLoc, DeclNameRef macroName, + DeclNameLoc macroNameLoc, SourceLoc leftAngleLoc, + SourceLoc rightAngleLoc, ArrayRef genericArgs, + ArgumentList *argList) + : SigilLoc(sigilLoc), MacroName(macroName), MacroNameLoc(macroNameLoc), + LeftAngleLoc(leftAngleLoc), RightAngleLoc(rightAngleLoc), + GenericArgs(genericArgs), ArgList(argList) {} + + SourceLoc getLoc() const { return SigilLoc; } + SourceRange getGenericArgsRange() const { + return {LeftAngleLoc, RightAngleLoc}; + } + SourceRange getSourceRange() const; +}; + +enum class FreestandingMacroKind { + Expr, // MacroExpansionExpr. + Decl, // MacroExpansionDecl. +}; + +/// A base class of either 'MacroExpansionExpr' or 'MacroExpansionDecl'. +class FreestandingMacroExpansion { + llvm::PointerIntPair + infoAndKind; + +protected: + FreestandingMacroExpansion(FreestandingMacroKind kind, + MacroExpansionInfo *info) + : infoAndKind(info, kind) {} + +public: + MacroExpansionInfo *getExpansionInfo() const { + return infoAndKind.getPointer(); + } + FreestandingMacroKind getFreestandingMacroKind() const { + return infoAndKind.getInt(); + } + + ASTNode getASTNode(); + + SourceLoc getPoundLoc() const { return getExpansionInfo()->SigilLoc; } + + DeclNameLoc getMacroNameLoc() const { + return getExpansionInfo()->MacroNameLoc; + } + DeclNameRef getMacroName() const { return getExpansionInfo()->MacroName; } + + ArrayRef getGenericArgs() const { + return getExpansionInfo()->GenericArgs; + } + SourceRange getGenericArgsRange() const { + return getExpansionInfo()->getGenericArgsRange(); + } + + ArgumentList *getArgs() const { return getExpansionInfo()->ArgList; } + void setArgs(ArgumentList *args) { getExpansionInfo()->ArgList = args; } + + ConcreteDeclRef getMacroRef() const { return getExpansionInfo()->macroRef; } + void setMacroRef(ConcreteDeclRef ref) { getExpansionInfo()->macroRef = ref; } + + DeclContext *getDeclContext() const; + SourceRange getSourceRange() const; + unsigned getDiscriminator() const; +}; + +} // namespace swift + +#endif // SWIFT_AST_FREESTANDING_MACRO_EXPANSION_H diff --git a/include/swift/AST/MacroDiscriminatorContext.h b/include/swift/AST/MacroDiscriminatorContext.h index ac770a59b7c2d..0e8f80130cdc0 100644 --- a/include/swift/AST/MacroDiscriminatorContext.h +++ b/include/swift/AST/MacroDiscriminatorContext.h @@ -22,12 +22,10 @@ namespace swift { /// Describes the context of a macro expansion for the purpose of /// computing macro expansion discriminators. struct MacroDiscriminatorContext - : public llvm::PointerUnion { + : public llvm::PointerUnion { using PointerUnion::PointerUnion; - static MacroDiscriminatorContext getParentOf(MacroExpansionExpr *expansion); - static MacroDiscriminatorContext getParentOf(MacroExpansionDecl *expansion); + static MacroDiscriminatorContext getParentOf(FreestandingMacroExpansion *expansion); static MacroDiscriminatorContext getParentOf( SourceLoc loc, DeclContext *origDC ); diff --git a/include/swift/AST/PrettyStackTrace.h b/include/swift/AST/PrettyStackTrace.h index 0baaa28354cca..e60dddbf92f40 100644 --- a/include/swift/AST/PrettyStackTrace.h +++ b/include/swift/AST/PrettyStackTrace.h @@ -18,11 +18,12 @@ #ifndef SWIFT_PRETTYSTACKTRACE_H #define SWIFT_PRETTYSTACKTRACE_H -#include "llvm/Support/PrettyStackTrace.h" -#include "swift/Basic/SourceLoc.h" #include "swift/AST/AnyFunctionRef.h" +#include "swift/AST/FreestandingMacroExpansion.h" #include "swift/AST/Identifier.h" #include "swift/AST/Type.h" +#include "swift/Basic/SourceLoc.h" +#include "llvm/Support/PrettyStackTrace.h" namespace clang { class Type; @@ -93,7 +94,21 @@ class PrettyStackTraceAnyFunctionRef : public llvm::PrettyStackTraceEntry { virtual void print(llvm::raw_ostream &OS) const override; }; -void printExprDescription(llvm::raw_ostream &out, Expr *E, +/// PrettyStackTraceFreestandingMacroExpansion - Observe that we are +/// processing a specific freestanding macro expansion. +class PrettyStackTraceFreestandingMacroExpansion + : public llvm::PrettyStackTraceEntry { + const FreestandingMacroExpansion *Expansion; + const char *Action; + +public: + PrettyStackTraceFreestandingMacroExpansion( + const char *action, const FreestandingMacroExpansion *expansion) + : Expansion(expansion), Action(action) {} + virtual void print(llvm::raw_ostream &OS) const override; +}; + +void printExprDescription(llvm::raw_ostream &out, const Expr *E, const ASTContext &Context, bool addNewline = true); /// PrettyStackTraceExpr - Observe that we are processing a specific diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 8a7591b213959..1e1e9a515c36f 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -3223,19 +3223,15 @@ class CheckRedeclarationRequest class UnresolvedMacroReference { private: - llvm::PointerUnion + llvm::PointerUnion pointer; public: - UnresolvedMacroReference(MacroExpansionDecl *decl) : pointer(decl) {} - UnresolvedMacroReference(MacroExpansionExpr *expr) : pointer(expr) {} + UnresolvedMacroReference(FreestandingMacroExpansion *exp) : pointer(exp) {} UnresolvedMacroReference(CustomAttr *attr) : pointer(attr) {} - MacroExpansionDecl *getDecl() const { - return pointer.dyn_cast(); - } - MacroExpansionExpr *getExpr() const { - return pointer.dyn_cast(); + FreestandingMacroExpansion *getFreestanding() const { + return pointer.dyn_cast(); } CustomAttr *getAttr() const { return pointer.dyn_cast(); diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 92d879304551d..6b4de6b2e8976 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -4033,26 +4033,23 @@ static StringRef getPrivateDiscriminatorIfNecessary( return discriminator.str(); } -std::string ASTMangler::mangleMacroExpansion( - const MacroExpansionExpr *expansion) { - beginMangling(); - appendMacroExpansionContext(expansion->getLoc(), expansion->getDeclContext()); - auto privateDiscriminator = getPrivateDiscriminatorIfNecessary(expansion); - if (!privateDiscriminator.empty()) { - appendIdentifier(privateDiscriminator); - appendOperator("Ll"); +static StringRef getPrivateDiscriminatorIfNecessary( + const FreestandingMacroExpansion *expansion) { + switch (expansion->getFreestandingMacroKind()) { + case FreestandingMacroKind::Expr: + return getPrivateDiscriminatorIfNecessary( + cast(expansion)); + case FreestandingMacroKind::Decl: + return getPrivateDiscriminatorIfNecessary( + cast(cast(expansion))); } - appendMacroExpansionOperator( - expansion->getMacroName().getBaseName().userFacingName(), - MacroRole::Expression, - expansion->getDiscriminator()); - return finalize(); } -std::string ASTMangler::mangleMacroExpansion( - const MacroExpansionDecl *expansion) { +std::string +ASTMangler::mangleMacroExpansion(const FreestandingMacroExpansion *expansion) { beginMangling(); - appendMacroExpansionContext(expansion->getLoc(), expansion->getDeclContext()); + appendMacroExpansionContext(expansion->getPoundLoc(), + expansion->getDeclContext()); auto privateDiscriminator = getPrivateDiscriminatorIfNecessary(expansion); if (!privateDiscriminator.empty()) { appendIdentifier(privateDiscriminator); diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index cfb7e1ec73fb1..b2af2b5a56ea3 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -50,6 +50,7 @@ add_swift_host_library(swiftAST STATIC ExtInfo.cpp FineGrainedDependencies.cpp FineGrainedDependencyFormat.cpp + FreestandingMacroExpansion.cpp FrontendSourceFileDepGraphFactory.cpp GenericEnvironment.cpp GenericParamList.cpp diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 0265e94d86357..b55d805295cc2 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -10640,37 +10640,27 @@ MacroDefinition MacroDefinition::forExpanded( ctx.AllocateCopy(replacements)}; } -MacroExpansionDecl::MacroExpansionDecl( - DeclContext *dc, MacroExpansionInfo *info -) : Decl(DeclKind::MacroExpansion, dc), info(info) { +MacroExpansionDecl::MacroExpansionDecl(DeclContext *dc, + MacroExpansionInfo *info) + : Decl(DeclKind::MacroExpansion, dc), + FreestandingMacroExpansion(FreestandingMacroKind::Decl, info) { Bits.MacroExpansionDecl.Discriminator = InvalidDiscriminator; } -MacroExpansionDecl::MacroExpansionDecl( +MacroExpansionDecl * +MacroExpansionDecl::create( DeclContext *dc, SourceLoc poundLoc, DeclNameRef macro, DeclNameLoc macroLoc, SourceLoc leftAngleLoc, ArrayRef genericArgs, SourceLoc rightAngleLoc, ArgumentList *args -) : Decl(DeclKind::MacroExpansion, dc) { +) { ASTContext &ctx = dc->getASTContext(); - info = new (ctx) MacroExpansionInfo{ + MacroExpansionInfo *info = new (ctx) MacroExpansionInfo{ poundLoc, macro, macroLoc, leftAngleLoc, rightAngleLoc, genericArgs, args ? args : ArgumentList::createImplicit(ctx, {}) }; - Bits.MacroExpansionDecl.Discriminator = InvalidDiscriminator; -} - -SourceRange MacroExpansionDecl::getSourceRange() const { - SourceLoc endLoc; - if (auto argsEndList = info->ArgList->getEndLoc()) - endLoc = argsEndList; - else if (info->RightAngleLoc.isValid()) - endLoc = info->RightAngleLoc; - else - endLoc = info->MacroNameLoc.getEndLoc(); - - return SourceRange(info->SigilLoc, endLoc); + return new (ctx) MacroExpansionDecl(dc, info); } unsigned MacroExpansionDecl::getDiscriminator() const { @@ -10814,13 +10804,7 @@ MacroDiscriminatorContext MacroDiscriminatorContext::getParentOf( } MacroDiscriminatorContext -MacroDiscriminatorContext::getParentOf(MacroExpansionExpr *expansion) { - return getParentOf( - expansion->getLoc(), expansion->getDeclContext()); -} - -MacroDiscriminatorContext -MacroDiscriminatorContext::getParentOf(MacroExpansionDecl *expansion) { +MacroDiscriminatorContext::getParentOf(FreestandingMacroExpansion *expansion) { return getParentOf( - expansion->getLoc(), expansion->getDeclContext()); + expansion->getPoundLoc(), expansion->getDeclContext()); } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 8c83ed6f1030d..4ecfffea89eaf 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -2680,34 +2680,20 @@ TypeJoinExpr::forBranchesOfSingleValueStmtExpr(ASTContext &ctx, Type joinType, return createImpl(ctx, joinType.getPointer(), /*elements*/ {}, arena, SVE); } -MacroExpansionExpr::MacroExpansionExpr( +MacroExpansionExpr *MacroExpansionExpr::create( DeclContext *dc, SourceLoc sigilLoc, DeclNameRef macroName, DeclNameLoc macroNameLoc, SourceLoc leftAngleLoc, ArrayRef genericArgs, SourceLoc rightAngleLoc, ArgumentList *argList, MacroRoles roles, bool isImplicit, Type ty -) : Expr(ExprKind::MacroExpansion, isImplicit, ty), DC(dc), - Rewritten(nullptr), Roles(roles), SubstituteDecl(nullptr) { +) { ASTContext &ctx = dc->getASTContext(); - info = new (ctx) MacroExpansionInfo{ + MacroExpansionInfo *info = new (ctx) MacroExpansionInfo{ sigilLoc, macroName, macroNameLoc, leftAngleLoc, rightAngleLoc, genericArgs, argList ? argList : ArgumentList::createImplicit(ctx, {}) }; - - Bits.MacroExpansionExpr.Discriminator = InvalidDiscriminator; -} - -SourceRange MacroExpansionExpr::getSourceRange() const { - SourceLoc endLoc; - if (info->ArgList && !info->ArgList->isImplicit()) - endLoc = info->ArgList->getEndLoc(); - else if (info->RightAngleLoc.isValid()) - endLoc = info->RightAngleLoc; - else - endLoc = info->MacroNameLoc.getEndLoc(); - - return SourceRange(info->SigilLoc, endLoc); + return new (ctx) MacroExpansionExpr(dc, info, roles, isImplicit, ty); } unsigned MacroExpansionExpr::getDiscriminator() const { @@ -2731,7 +2717,8 @@ MacroExpansionDecl *MacroExpansionExpr::createSubstituteDecl() { auto dc = DC; if (auto *tlcd = dyn_cast_or_null(dc->getAsDecl())) dc = tlcd->getDeclContext(); - SubstituteDecl = new (DC->getASTContext()) MacroExpansionDecl(dc, info); + SubstituteDecl = + new (DC->getASTContext()) MacroExpansionDecl(dc, getExpansionInfo()); return SubstituteDecl; } diff --git a/lib/AST/FreestandingMacroExpansion.cpp b/lib/AST/FreestandingMacroExpansion.cpp new file mode 100644 index 0000000000000..ad368a5177410 --- /dev/null +++ b/lib/AST/FreestandingMacroExpansion.cpp @@ -0,0 +1,56 @@ +//===--- FreestandingMacroExpansion.cpp -----------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/AST/FreestandingMacroExpansion.h" +#include "swift/AST/Decl.h" +#include "swift/AST/Expr.h" + +using namespace swift; + +SourceRange MacroExpansionInfo::getSourceRange() const { + SourceLoc endLoc; + if (ArgList && !ArgList->isImplicit()) + endLoc = ArgList->getEndLoc(); + else if (RightAngleLoc.isValid()) + endLoc = RightAngleLoc; + else + endLoc = MacroNameLoc.getEndLoc(); + + return SourceRange(SigilLoc, endLoc); +} + +#define FORWARD_VARIANT(NAME) \ + switch (getFreestandingMacroKind()) { \ + case FreestandingMacroKind::Expr: \ + return cast(this)->NAME(); \ + case FreestandingMacroKind::Decl: \ + return cast(this)->NAME(); \ + } + +DeclContext *FreestandingMacroExpansion::getDeclContext() const { + FORWARD_VARIANT(getDeclContext); +} +SourceRange FreestandingMacroExpansion::getSourceRange() const { + FORWARD_VARIANT(getSourceRange); +} +unsigned FreestandingMacroExpansion::getDiscriminator() const { + FORWARD_VARIANT(getDiscriminator); +} + +ASTNode FreestandingMacroExpansion::getASTNode() { + switch (getFreestandingMacroKind()) { + case FreestandingMacroKind::Expr: + return cast(this); + case FreestandingMacroKind::Decl: + return cast(this); + } +} diff --git a/lib/AST/PrettyStackTrace.cpp b/lib/AST/PrettyStackTrace.cpp index 6d24777a11c87..747faf50f5170 100644 --- a/lib/AST/PrettyStackTrace.cpp +++ b/lib/AST/PrettyStackTrace.cpp @@ -133,6 +133,20 @@ void PrettyStackTraceAnyFunctionRef::print(llvm::raw_ostream &out) const { } } +void PrettyStackTraceFreestandingMacroExpansion::print( + llvm::raw_ostream &out) const { + out << "While " << Action << ' '; + auto &Context = Expansion->getDeclContext()->getASTContext(); + switch (Expansion->getFreestandingMacroKind()) { + case FreestandingMacroKind::Expr: + printExprDescription(out, cast(Expansion), Context); + break; + case FreestandingMacroKind::Decl: + printDeclDescription(out, cast(Expansion), Context); + break; + } +} + void PrettyStackTraceExpr::print(llvm::raw_ostream &out) const { out << "While " << Action << ' '; if (!TheExpr) { @@ -142,7 +156,7 @@ void PrettyStackTraceExpr::print(llvm::raw_ostream &out) const { printExprDescription(out, TheExpr, Context); } -void swift::printExprDescription(llvm::raw_ostream &out, Expr *E, +void swift::printExprDescription(llvm::raw_ostream &out, const Expr *E, const ASTContext &Context, bool addNewline) { out << "expression at "; E->getSourceRange().print(out, Context.SourceMgr); diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index 426eb501b5efb..0b7666c79bddf 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -1681,10 +1681,8 @@ void swift::simple_display( //----------------------------------------------------------------------------// DeclNameRef UnresolvedMacroReference::getMacroName() const { - if (auto *med = pointer.dyn_cast()) - return med->getMacroName(); - if (auto *mee = pointer.dyn_cast()) - return mee->getMacroName(); + if (auto *expansion = pointer.dyn_cast()) + return expansion->getMacroName(); if (auto *attr = pointer.dyn_cast()) { auto *identTypeRepr = dyn_cast_or_null(attr->getTypeRepr()); if (!identTypeRepr) @@ -1695,20 +1693,16 @@ DeclNameRef UnresolvedMacroReference::getMacroName() const { } SourceLoc UnresolvedMacroReference::getSigilLoc() const { - if (auto *med = pointer.dyn_cast()) - return med->getPoundLoc(); - if (auto *mee = pointer.dyn_cast()) - return mee->getLoc(); + if (auto *expansion = pointer.dyn_cast()) + return expansion->getPoundLoc(); if (auto *attr = pointer.dyn_cast()) return attr->getRangeWithAt().Start; llvm_unreachable("Unhandled case"); } DeclNameLoc UnresolvedMacroReference::getMacroNameLoc() const { - if (auto *med = pointer.dyn_cast()) - return med->getMacroNameLoc(); - if (auto *mee = pointer.dyn_cast()) - return mee->getMacroNameLoc(); + if (auto *expansion = pointer.dyn_cast()) + return expansion->getMacroNameLoc(); if (auto *attr = pointer.dyn_cast()) { auto *identTypeRepr = dyn_cast_or_null(attr->getTypeRepr()); if (!identTypeRepr) @@ -1719,10 +1713,8 @@ DeclNameLoc UnresolvedMacroReference::getMacroNameLoc() const { } SourceRange UnresolvedMacroReference::getGenericArgsRange() const { - if (auto *med = pointer.dyn_cast()) - return med->getGenericArgsRange(); - if (auto *mee = pointer.dyn_cast()) - return mee->getGenericArgsRange(); + if (auto *expansion = pointer.dyn_cast()) + return expansion->getGenericArgsRange(); if (auto *attr = pointer.dyn_cast()) { auto *typeRepr = attr->getTypeRepr(); @@ -1737,10 +1729,8 @@ SourceRange UnresolvedMacroReference::getGenericArgsRange() const { } ArrayRef UnresolvedMacroReference::getGenericArgs() const { - if (auto *med = pointer.dyn_cast()) - return med->getGenericArgs(); - if (auto *mee = pointer.dyn_cast()) - return mee->getGenericArgs(); + if (auto *expansion = pointer.dyn_cast()) + return expansion->getGenericArgs(); if (auto *attr = pointer.dyn_cast()) { auto *typeRepr = attr->getTypeRepr(); @@ -1755,17 +1745,15 @@ ArrayRef UnresolvedMacroReference::getGenericArgs() const { } ArgumentList *UnresolvedMacroReference::getArgs() const { - if (auto *med = pointer.dyn_cast()) - return med->getArgs(); - if (auto *mee = pointer.dyn_cast()) - return mee->getArgs(); + if (auto *expansion = pointer.dyn_cast()) + return expansion->getArgs(); if (auto *attr = pointer.dyn_cast()) return attr->getArgs(); llvm_unreachable("Unhandled case"); } MacroRoles UnresolvedMacroReference::getMacroRoles() const { - if (pointer.is() || pointer.is()) + if (pointer.is()) return getFreestandingMacroRoles(); if (pointer.is()) @@ -1776,10 +1764,8 @@ MacroRoles UnresolvedMacroReference::getMacroRoles() const { void swift::simple_display(llvm::raw_ostream &out, const UnresolvedMacroReference &ref) { - if (ref.getDecl()) - out << "macro-expansion-decl"; - else if (ref.getExpr()) - out << "macro-expansion-expr"; + if (ref.getFreestanding()) + out << "freestanding-macro-expansion"; else if (ref.getAttr()) out << "custom-attr"; } diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index f634767af4011..1120a28d22387 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -9940,7 +9940,7 @@ Parser::parseDeclMacroExpansion(ParseDeclOptions flags, if (!macroNameRef) return status; - auto *med = new (Context) MacroExpansionDecl( + auto *med = MacroExpansionDecl::create( CurDeclContext, poundLoc, macroNameRef, macroNameLoc, leftAngleLoc, Context.AllocateCopy(genericArgs), rightAngleLoc, argList); med->getAttrs() = attributes; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 1ce2c3d2c6d49..ab5d8f4ed1606 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -3472,12 +3472,11 @@ ParserResult Parser::parseExprMacroExpansion(bool isExprBasic) { return makeParserResult( status, - new (Context) MacroExpansionExpr( + MacroExpansionExpr::create( CurDeclContext, poundLoc, macroNameRef, macroNameLoc, leftAngleLoc, Context.AllocateCopy(genericArgs), rightAngleLoc, argList, - CurDeclContext->isTypeContext() - ? MacroRole::Declaration - : getFreestandingMacroRoles())); + CurDeclContext->isTypeContext() ? MacroRole::Declaration + : getFreestandingMacroRoles())); } /// parseExprCollection - Parse a collection literal expression. diff --git a/lib/Sema/CSApply.cpp b/lib/Sema/CSApply.cpp index f64ee2a0a82cb..6b246afdc5071 100644 --- a/lib/Sema/CSApply.cpp +++ b/lib/Sema/CSApply.cpp @@ -2937,7 +2937,7 @@ namespace { auto macro = cast(overload.choice.getDecl()); ConcreteDeclRef macroRef = resolveConcreteDeclRef(macro, locator); - auto expansion = new (ctx) MacroExpansionExpr( + auto *expansion = MacroExpansionExpr::create( dc, expr->getStartLoc(), DeclNameRef(macro->getName()), DeclNameLoc(expr->getLoc()), SourceLoc(), {}, SourceLoc(), nullptr, MacroRole::Expression, /*isImplicit=*/true, expandedType); diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 1db4a6f69091f..9cc35ba4264f7 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -24,6 +24,7 @@ #include "swift/AST/CASTBridging.h" #include "swift/AST/DiagnosticsFrontend.h" #include "swift/AST/Expr.h" +#include "swift/AST/FreestandingMacroExpansion.h" #include "swift/AST/MacroDefinition.h" #include "swift/AST/NameLookupRequests.h" #include "swift/AST/PluginLoader.h" @@ -858,24 +859,29 @@ createMacroSourceFile(std::unique_ptr buffer, return macroSourceFile; } -Optional -swift::expandMacroExpr(MacroExpansionExpr *mee) { - DeclContext *dc = mee->getDeclContext(); +/// Evaluate the given freestanding macro expansion. +static SourceFile * +evaluateFreestandingMacro(FreestandingMacroExpansion *expansion) { + auto *dc = expansion->getDeclContext(); ASTContext &ctx = dc->getASTContext(); - SourceManager &sourceMgr = ctx.SourceMgr; - ConcreteDeclRef macroRef = mee->getMacroRef(); - Type expandedType = mee->getType(); + SourceLoc loc = expansion->getPoundLoc(); auto moduleDecl = dc->getParentModule(); - auto sourceFile = moduleDecl->getSourceFileContainingLocation(mee->getLoc()); + auto sourceFile = moduleDecl->getSourceFileContainingLocation(loc); if (!sourceFile) - return None; + return nullptr; - MacroDecl *macro = cast(macroRef.getDecl()); + MacroDecl *macro = cast(expansion->getMacroRef().getDecl()); + auto macroRoles = macro->getMacroRoles(); + assert(macroRoles.contains(MacroRole::Expression) || + macroRoles.contains(MacroRole::Declaration) || + macroRoles.contains(MacroRole::CodeItem)); - if (isFromExpansionOfMacro(sourceFile, macro, MacroRole::Expression)) { - ctx.Diags.diagnose(mee->getLoc(), diag::macro_recursive, macro->getName()); - return None; + if (isFromExpansionOfMacro(sourceFile, macro, MacroRole::Expression) || + isFromExpansionOfMacro(sourceFile, macro, MacroRole::Declaration) || + isFromExpansionOfMacro(sourceFile, macro, MacroRole::CodeItem)) { + ctx.Diags.diagnose(loc, diag::macro_recursive, macro->getName()); + return nullptr; } // Evaluate the macro. @@ -885,7 +891,7 @@ swift::expandMacroExpr(MacroExpansionExpr *mee) { LazyValue discriminator([&]() -> std::string { #if SWIFT_SWIFT_PARSER Mangle::ASTMangler mangler; - return mangler.mangleMacroExpansion(mee); + return mangler.mangleMacroExpansion(expansion); #else return ""; #endif @@ -896,21 +902,20 @@ swift::expandMacroExpr(MacroExpansionExpr *mee) { case MacroDefinition::Kind::Undefined: case MacroDefinition::Kind::Invalid: // Already diagnosed as an error elsewhere. - return None; + return nullptr; case MacroDefinition::Kind::Builtin: { switch (macroDef.getBuiltinKind()) { case BuiltinMacroKind::ExternalMacro: - ctx.Diags.diagnose( - mee->getLoc(), diag::external_macro_outside_macro_definition); - return None; + ctx.Diags.diagnose(loc, diag::external_macro_outside_macro_definition); + return nullptr; } } case MacroDefinition::Kind::Expanded: { // Expand the definition with the given arguments. - auto result = expandMacroDefinition( - macroDef.getExpanded(), macro, mee->getArgs()); + auto result = expandMacroDefinition(macroDef.getExpanded(), macro, + expansion->getArgs()); evaluatedSource = llvm::MemoryBuffer::getMemBufferCopy( result, adjustMacroExpansionBufferName(*discriminator)); break; @@ -919,28 +924,33 @@ swift::expandMacroExpr(MacroExpansionExpr *mee) { case MacroDefinition::Kind::External: { // Retrieve the external definition of the macro. auto external = macroDef.getExternalMacro(); - ExternalMacroDefinitionRequest request{ - &ctx, external.moduleName, external.macroTypeName - }; + ExternalMacroDefinitionRequest request{&ctx, external.moduleName, + external.macroTypeName}; auto externalDef = evaluateOrDefault(ctx.evaluator, request, None); if (!externalDef) { - ctx.Diags.diagnose( - mee->getLoc(), diag::external_macro_not_found, - external.moduleName.str(), - external.macroTypeName.str(), - macro->getName() - ); + ctx.Diags.diagnose(loc, diag::external_macro_not_found, + external.moduleName.str(), + external.macroTypeName.str(), macro->getName()); macro->diagnose(diag::decl_declared_here, macro->getName()); - return None; + return nullptr; + } + + // Code item macros require `CodeItemMacros` feature flag. + if (macroRoles.contains(MacroRole::CodeItem) && + !ctx.LangOpts.hasFeature(Feature::CodeItemMacros)) { + ctx.Diags.diagnose(loc, diag::macro_experimental, "code item", + "CodeItemMacros"); + return nullptr; } #if SWIFT_SWIFT_PARSER - PrettyStackTraceExpr debugStack(ctx, "expanding macro", mee); + PrettyStackTraceFreestandingMacroExpansion debugStack( + "expanding freestanding macro", expansion); // Builtin macros are handled via ASTGen. auto *astGenSourceFile = sourceFile->getExportedSourceFile(); if (!astGenSourceFile) - return None; + return nullptr; const char *evaluatedSourceAddress; ptrdiff_t evaluatedSourceLength; @@ -948,24 +958,38 @@ swift::expandMacroExpr(MacroExpansionExpr *mee) { &ctx.Diags, externalDef->opaqueHandle, static_cast(externalDef->kind), discriminator->data(), discriminator->size(), astGenSourceFile, - mee->getStartLoc().getOpaquePointerValue(), &evaluatedSourceAddress, - &evaluatedSourceLength); + expansion->getSourceRange().Start.getOpaquePointerValue(), + &evaluatedSourceAddress, &evaluatedSourceLength); if (!evaluatedSourceAddress) - return None; + return nullptr; evaluatedSource = llvm::MemoryBuffer::getMemBufferCopy( {evaluatedSourceAddress, (size_t)evaluatedSourceLength}, adjustMacroExpansionBufferName(*discriminator)); free((void *)evaluatedSourceAddress); break; #else - ctx.Diags.diagnose(mee->getLoc(), diag::macro_unsupported); - return None; + ctx.Diags.diagnose(loc, diag::macro_unsupported); + return nullptr; #endif } } - SourceFile *macroSourceFile = createMacroSourceFile( - std::move(evaluatedSource), MacroRole::Expression, mee, dc, - /*attr=*/nullptr); + + return createMacroSourceFile(std::move(evaluatedSource), + isa(expansion) + ? MacroRole::Declaration + : MacroRole::Expression, + expansion->getASTNode(), dc, + /*attr=*/nullptr); +} + +Optional swift::expandMacroExpr(MacroExpansionExpr *mee) { + SourceFile *macroSourceFile = evaluateFreestandingMacro(mee); + if (!macroSourceFile) + return None; + + DeclContext *dc = mee->getDeclContext(); + ASTContext &ctx = dc->getASTContext(); + SourceManager &sourceMgr = ctx.SourceMgr; auto macroBufferID = *macroSourceFile->getBufferID(); auto macroBufferRange = sourceMgr.getRangeForBuffer(macroBufferID); @@ -989,6 +1013,8 @@ swift::expandMacroExpr(MacroExpansionExpr *mee) { return macroBufferID; } + auto expandedType = mee->getType(); + // Type-check the expanded expression. // FIXME: Would like to pass through type checking options like "discarded" // that are captured by TypeCheckExprOptions. @@ -1017,124 +1043,12 @@ swift::expandMacroExpr(MacroExpansionExpr *mee) { /// Expands the given macro expansion declaration. Optional swift::expandFreestandingMacro(MacroExpansionDecl *med) { - auto *dc = med->getDeclContext(); - ASTContext &ctx = dc->getASTContext(); - - auto moduleDecl = dc->getParentModule(); - auto sourceFile = moduleDecl->getSourceFileContainingLocation(med->getLoc()); - if (!sourceFile) + SourceFile *macroSourceFile = evaluateFreestandingMacro(med); + if (!macroSourceFile) return None; MacroDecl *macro = cast(med->getMacroRef().getDecl()); - auto macroRoles = macro->getMacroRoles(); - assert(macroRoles.contains(MacroRole::Declaration) || - macroRoles.contains(MacroRole::CodeItem)); - - if (isFromExpansionOfMacro(sourceFile, macro, MacroRole::Expression) || - isFromExpansionOfMacro(sourceFile, macro, MacroRole::Declaration) || - isFromExpansionOfMacro(sourceFile, macro, MacroRole::CodeItem)) { - med->diagnose(diag::macro_recursive, macro->getName()); - return None; - } - - // Evaluate the macro. - std::unique_ptr evaluatedSource; - - /// The discriminator used for the macro. - LazyValue discriminator([&]() -> std::string { -#if SWIFT_SWIFT_PARSER - Mangle::ASTMangler mangler; - return mangler.mangleMacroExpansion(med); -#else - return ""; -#endif - }); - - auto macroDef = macro->getDefinition(); - switch (macroDef.kind) { - case MacroDefinition::Kind::Undefined: - case MacroDefinition::Kind::Invalid: - // Already diagnosed as an error elsewhere. - return None; - - case MacroDefinition::Kind::Builtin: { - switch (macroDef.getBuiltinKind()) { - case BuiltinMacroKind::ExternalMacro: - // FIXME: Error here. - return None; - } - } - - case MacroDefinition::Kind::Expanded: { - // Expand the definition with the given arguments. - auto result = expandMacroDefinition( - macroDef.getExpanded(), macro, med->getArgs()); - evaluatedSource = llvm::MemoryBuffer::getMemBufferCopy( - result, adjustMacroExpansionBufferName(*discriminator)); - break; - } - - case MacroDefinition::Kind::External: { - // Retrieve the external definition of the macro. - auto external = macroDef.getExternalMacro(); - ExternalMacroDefinitionRequest request{ - &ctx, external.moduleName, external.macroTypeName - }; - auto externalDef = evaluateOrDefault(ctx.evaluator, request, None); - if (!externalDef) { - med->diagnose(diag::external_macro_not_found, - external.moduleName.str(), - external.macroTypeName.str(), - macro->getName() - ); - macro->diagnose(diag::decl_declared_here, macro->getName()); - return None; - } - - // Currently only expression macros are enabled by default. Declaration - // macros need the `FreestandingMacros` feature flag, and code item macros - // need both `FreestandingMacros` and `CodeItemMacros`. - if (!macroRoles.contains(MacroRole::Expression)) { - if (!macroRoles.contains(MacroRole::Declaration) && - !ctx.LangOpts.hasFeature(Feature::CodeItemMacros)) { - med->diagnose(diag::macro_experimental, "code item", "CodeItemMacros"); - return None; - } - } - -#if SWIFT_SWIFT_PARSER - PrettyStackTraceDecl debugStack("expanding declaration macro", med); - - // Builtin macros are handled via ASTGen. - auto *astGenSourceFile = sourceFile->getExportedSourceFile(); - if (!astGenSourceFile) - return None; - - const char *evaluatedSourceAddress; - ptrdiff_t evaluatedSourceLength; - swift_ASTGen_expandFreestandingMacro( - &ctx.Diags, externalDef->opaqueHandle, - static_cast(externalDef->kind), discriminator->data(), - discriminator->size(), astGenSourceFile, - med->getStartLoc().getOpaquePointerValue(), &evaluatedSourceAddress, - &evaluatedSourceLength); - if (!evaluatedSourceAddress) - return None; - evaluatedSource = llvm::MemoryBuffer::getMemBufferCopy( - {evaluatedSourceAddress, (size_t)evaluatedSourceLength}, - adjustMacroExpansionBufferName(*discriminator)); - free((void *)evaluatedSourceAddress); - break; -#else - med->diagnose(diag::macro_unsupported); - return None; -#endif - } - } - - SourceFile *macroSourceFile = createMacroSourceFile( - std::move(evaluatedSource), MacroRole::Declaration, med, dc, - /*attr=*/nullptr); + DeclContext *dc = med->getDeclContext(); validateMacroExpansion(macroSourceFile, macro, /*attachedTo*/nullptr, @@ -1479,11 +1393,8 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, DeclContext *dc) const { // Macro expressions and declarations have their own stored macro // reference. Use it if it's there. - if (auto *expr = macroRef.getExpr()) { - if (auto ref = expr->getMacroRef()) - return ref; - } else if (auto decl = macroRef.getDecl()) { - if (auto ref = decl->getMacroRef()) + if (auto *expansion = macroRef.getFreestanding()) { + if (auto ref = expansion->getMacroRef()) return ref; } @@ -1502,14 +1413,16 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, // If we already have a MacroExpansionExpr, use that. Otherwise, // create one. MacroExpansionExpr *macroExpansion; - if (auto *expr = macroRef.getExpr()) { - macroExpansion = expr; - } else if (auto *decl = macroRef.getDecl()) { - macroExpansion = new (ctx) MacroExpansionExpr( - dc, decl->getExpansionInfo(), roles); + if (auto *expansion = macroRef.getFreestanding()) { + if (auto *expr = dyn_cast(expansion)) { + macroExpansion = expr; + } else { + macroExpansion = new (ctx) MacroExpansionExpr( + dc, expansion->getExpansionInfo(), roles); + } } else { SourceRange genericArgsRange = macroRef.getGenericArgsRange(); - macroExpansion = new (ctx) MacroExpansionExpr( + macroExpansion = MacroExpansionExpr::create( dc, macroRef.getSigilLoc(), macroRef.getMacroName(), macroRef.getMacroNameLoc(), genericArgsRange.Start, macroRef.getGenericArgs(), genericArgsRange.End, @@ -1528,10 +1441,8 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, // reference. If we got a reference, store it there, too. // FIXME: This duplication of state is really unfortunate. if (auto ref = macroExpansion->getMacroRef()) { - if (auto *expr = macroRef.getExpr()) { - expr->setMacroRef(ref); - } else if (auto decl = macroRef.getDecl()) { - decl->setMacroRef(ref); + if (auto *expansion = macroRef.getFreestanding()) { + expansion->setMacroRef(ref); } } From 713059f16f322867dab559eccd9732b4d4460f9f Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 24 May 2023 14:29:05 -0700 Subject: [PATCH 3/9] [SourceKit] Add request to expand macros syntactically Expand macros in the specified source file syntactically (without any module imports, nor typechecking). Request would look like: ``` { key.compilerargs: [...] key.sourcefile: key.sourcetext: (optional) key.expansions: [...] } ``` `key.compilerargs` are used for getting plugins search paths. If `key.sourcetext` is not specified, it's loaded from the file system. Each `` is ``` { key.offset: key.modulename: key.typename: key.macro_roles: [...] } ``` Clients have to provide the module and type names because that's semantic. Response is a `CategorizedEdits` just like (semantic) "ExpandMacro" refactoring. Each edit object has `key.buffer_name` that can be used for recursive expansion. If the client founds nested macro expansion in the expanded source, it can send another request with the same compiler arguments using the buffer name and the source to get the nested expansions. (cherry picked from commit 43908fad02e4bfe33c6ce61422e820bf82dca6de) --- include/swift/AST/Decl.h | 3 + include/swift/IDE/Utils.h | 3 + .../swift/IDETool/SyntacticMacroExpansion.h | 105 ++++ include/swift/Sema/IDETypeChecking.h | 8 + lib/AST/Decl.cpp | 5 + lib/IDE/Utils.cpp | 91 ++++ lib/IDETool/CMakeLists.txt | 1 + lib/IDETool/SyntacticMacroExpansion.cpp | 467 ++++++++++++++++++ lib/Refactoring/Refactoring.cpp | 95 +--- lib/Sema/TypeCheckMacros.cpp | 66 ++- .../Macros/syntactic_expansion.swift | 66 +++ .../Macros/syntactic_expansion.swift.expected | 131 +++++ .../include/SourceKit/Core/LangSupport.h | 59 +++ tools/SourceKit/lib/SwiftLang/CMakeLists.txt | 1 + .../lib/SwiftLang/SwiftLangSupport.cpp | 4 + .../lib/SwiftLang/SwiftLangSupport.h | 7 + .../SwiftSyntacticMacroExpansion.cpp | 94 ++++ .../tools/sourcekitd-test/TestOptions.cpp | 4 +- .../tools/sourcekitd-test/TestOptions.h | 1 + .../tools/sourcekitd-test/sourcekitd-test.cpp | 47 ++ .../tools/sourcekitd/lib/Service/Requests.cpp | 132 +++++ utils/gyb_sourcekit_support/UIDs.py | 16 + 22 files changed, 1294 insertions(+), 112 deletions(-) create mode 100644 include/swift/IDETool/SyntacticMacroExpansion.h create mode 100644 lib/IDETool/SyntacticMacroExpansion.cpp create mode 100644 test/SourceKit/Macros/syntactic_expansion.swift create mode 100644 test/SourceKit/Macros/syntactic_expansion.swift.expected create mode 100644 tools/SourceKit/lib/SwiftLang/SwiftSyntacticMacroExpansion.cpp diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index a9a1d30b6f20c..e74db0ebb99ac 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -8597,6 +8597,9 @@ class MacroDecl : public GenericContext, public ValueDecl { /// Retrieve the definition of this macro. MacroDefinition getDefinition() const; + /// Set the definition of this macro + void setDefinition(MacroDefinition definition); + /// Retrieve the parameter list of this macro. ParameterList *getParameterList() const { return parameterList; } diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index 77b361d2d7be4..97dc26fa34f9b 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -578,6 +578,9 @@ class SourceEditConsumer { void insertAfter(SourceManager &SM, SourceLoc Loc, StringRef Text, ArrayRef SubRegions = {}); void accept(SourceManager &SM, Replacement Replacement) { accept(SM, RegionType::ActiveCode, {Replacement}); } void remove(SourceManager &SM, CharSourceRange Range); + void acceptMacroExpansionBuffer(SourceManager &SM, unsigned bufferID, + SourceFile *containingSF, + bool adjustExpansion); }; /// This helper stream inserts text into a SourceLoc by calling functions in diff --git a/include/swift/IDETool/SyntacticMacroExpansion.h b/include/swift/IDETool/SyntacticMacroExpansion.h new file mode 100644 index 0000000000000..73b3c6fe3abaa --- /dev/null +++ b/include/swift/IDETool/SyntacticMacroExpansion.h @@ -0,0 +1,105 @@ +//===--- SyntacticMacroExpansion.h ----------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_IDE_SYNTACTICMACROEXPANSION_H +#define SWIFT_IDE_SYNTACTICMACROEXPANSION_H + +#include "swift/AST/Decl.h" +#include "swift/AST/MacroDefinition.h" +#include "swift/AST/PluginRegistry.h" +#include "swift/Basic/Fingerprint.h" +#include "swift/Frontend/Frontend.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace swift { + +class ASTContext; +class SourceFile; + +namespace ide { +class SourceEditConsumer; + +/// Simple object to specify a syntactic macro expansion. +struct MacroExpansionSpecifier { + unsigned offset; + swift::MacroRoles macroRoles; + swift::MacroDefinition macroDefinition; +}; + +/// Instance of a syntactic macro expansion context. This is created for each +/// list of compiler arguments (i.e. 'argHash'), and reused as long as the +/// compiler arguments are not changed. +class SyntacticMacroExpansionInstance { + const Fingerprint argHash; + CompilerInvocation invocation; + + SourceManager SourceMgr; + DiagnosticEngine Diags{SourceMgr}; + std::unique_ptr Ctx; + ModuleDecl *TheModule = nullptr; + llvm::DenseMap MacroDecls; + + std::mutex mtx; + + /// Create 'SourceFile' using the buffer. + swift::SourceFile *getSourceFile(llvm::MemoryBuffer *inputBuf); + + /// Synthesize 'MacroDecl' AST object to use the expansion. + swift::MacroDecl * + getSynthesizedMacroDecl(swift::Identifier name, + const MacroExpansionSpecifier &expansion); + + /// Expand single 'expansion' in SF. + bool getExpansion(swift::SourceFile *SF, + const MacroExpansionSpecifier &expansion, + SourceEditConsumer &consumer); + +public: + SyntacticMacroExpansionInstance(Fingerprint argHash) : argHash(argHash) {} + + /// Setup the instance with \p args . + bool setup(StringRef SwiftExecutablePath, ArrayRef args, + std::shared_ptr plugins, std::string &error); + + const Fingerprint &getArgHash() const { return argHash; } + ASTContext &getASTContext() { return *Ctx; } + + /// Expand all macros in \p inputBuf and send the edit results to \p consumer. + /// Expansions are specified by \p expansions . + bool getExpansions(llvm::MemoryBuffer *inputBuf, + ArrayRef expansions, + SourceEditConsumer &consumer); +}; + +/// Manager object to vend 'SyntacticMacroExpansionInstance'. +class SyntacticMacroExpansion { + StringRef SwiftExecutablePath; + std::shared_ptr Plugins; + + /// Cached instance. + std::shared_ptr currentInstance; + +public: + SyntacticMacroExpansion(StringRef SwiftExecutablePath, + std::shared_ptr Plugins) + : SwiftExecutablePath(SwiftExecutablePath), Plugins(Plugins) {} + + /// Get instance configured with the specified compiler arguments. + /// If 'currentInstance' matches with the arguments, just return it. + std::shared_ptr + getInstance(ArrayRef args, std::string &error); +}; + +} // namespace ide +} // namespace swift + +#endif // SWIFT_IDE_SYNTACTICMACROEXPANSION_H diff --git a/include/swift/Sema/IDETypeChecking.h b/include/swift/Sema/IDETypeChecking.h index 2d4da1a016ae5..33825e593cf15 100644 --- a/include/swift/Sema/IDETypeChecking.h +++ b/include/swift/Sema/IDETypeChecking.h @@ -37,6 +37,7 @@ namespace swift { enum class DeclRefKind; class Expr; class ExtensionDecl; + class FreestandingMacroExpansion; class FunctionType; class LabeledConditionalStmt; class LookupResult; @@ -355,6 +356,13 @@ namespace swift { SmallVector, 1> getShorthandShadows(LabeledConditionalStmt *CondStmt, DeclContext *DC = nullptr); + + SourceFile *evaluateFreestandingMacro(FreestandingMacroExpansion *expansion, + StringRef discriminator); + + SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, + CustomAttr *attr, bool passParentContext, + MacroRole role, StringRef discriminator); } #endif diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index b55d805295cc2..565fd3400f17e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -10624,6 +10624,11 @@ MacroDefinition MacroDecl::getDefinition() const { MacroDefinition::forUndefined()); } +void MacroDecl::setDefinition(MacroDefinition definition) { + getASTContext().evaluator.cacheOutput(MacroDefinitionRequest{this}, + std::move(definition)); +} + Optional MacroDecl::getBuiltinKind() const { auto def = getDefinition(); if (def.kind != MacroDefinition::Kind::Builtin) diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 776f6a9e54450..45dd6f5340c22 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -622,6 +622,97 @@ remove(SourceManager &SM, CharSourceRange Range) { accept(SM, Range, ""); } +/// Given the expanded code for a particular macro, perform whitespace +/// adjustments to make the refactoring more suitable for inline insertion. +static StringRef +adjustMacroExpansionWhitespace(GeneratedSourceInfo::Kind kind, + StringRef expandedCode, + llvm::SmallString<64> &scratch) { + scratch.clear(); + + switch (kind) { + case GeneratedSourceInfo::MemberAttributeMacroExpansion: + // Attributes are added to the beginning, add a space to separate from + // any existing. + scratch += expandedCode; + scratch += " "; + return scratch; + + case GeneratedSourceInfo::MemberMacroExpansion: + case GeneratedSourceInfo::PeerMacroExpansion: + case GeneratedSourceInfo::ConformanceMacroExpansion: + // All added to the end. Note that conformances are always expanded as + // extensions, hence treating them the same as peer. + scratch += "\n\n"; + scratch += expandedCode; + scratch += "\n"; + return scratch; + + case GeneratedSourceInfo::ExpressionMacroExpansion: + case GeneratedSourceInfo::FreestandingDeclMacroExpansion: + case GeneratedSourceInfo::AccessorMacroExpansion: + case GeneratedSourceInfo::ReplacedFunctionBody: + case GeneratedSourceInfo::PrettyPrinted: + return expandedCode; + } +} + +void swift::ide::SourceEditConsumer::acceptMacroExpansionBuffer( + SourceManager &SM, unsigned bufferID, SourceFile *containingSF, + bool adjustExpansion) { + auto generatedInfo = SM.getGeneratedSourceInfo(bufferID); + if (!generatedInfo || generatedInfo->originalSourceRange.isInvalid()) + return; + + auto rewrittenBuffer = SM.extractText(generatedInfo->generatedSourceRange); + + // If there's no change, drop the edit entirely. + if (generatedInfo->originalSourceRange.getStart() == + generatedInfo->originalSourceRange.getEnd() && + rewrittenBuffer.empty()) + return; + + SmallString<64> scratchBuffer; + if (adjustExpansion) { + rewrittenBuffer = adjustMacroExpansionWhitespace( + generatedInfo->kind, rewrittenBuffer, scratchBuffer); + } + + // `containingFile` is the file of the actual expansion site, where as + // `originalFile` is the possibly enclosing buffer. Concretely: + // ``` + // // m.swift + // @AddMemberAttributes + // struct Foo { + // // --- expanded from @AddMemberAttributes eg. @_someBufferName --- + // @AddedAttribute + // // --- + // let someMember: Int + // } + // ``` + // + // When expanding `AddedAttribute`, the expansion actually applies to the + // original source (`m.swift`) rather than the buffer of the expansion + // site (`@_someBufferName`). Thus, we need to include the path to the + // original source as well. Note that this path could itself be another + // expansion. + auto originalSourceRange = generatedInfo->originalSourceRange; + SourceFile *originalFile = + containingSF->getParentModule()->getSourceFileContainingLocation( + originalSourceRange.getStart()); + StringRef originalPath; + if (originalFile->getBufferID().hasValue() && + containingSF->getBufferID() != originalFile->getBufferID()) { + originalPath = SM.getIdentifierForBuffer(*originalFile->getBufferID()); + } + + accept(SM, {originalPath, + originalSourceRange, + SM.getIdentifierForBuffer(bufferID), + rewrittenBuffer, + {}}); +} + struct swift::ide::SourceEditJsonConsumer::Implementation { llvm::raw_ostream &OS; std::vector AllEdits; diff --git a/lib/IDETool/CMakeLists.txt b/lib/IDETool/CMakeLists.txt index c7555e0cb3d51..34994928c1459 100644 --- a/lib/IDETool/CMakeLists.txt +++ b/lib/IDETool/CMakeLists.txt @@ -4,6 +4,7 @@ add_swift_host_library(swiftIDETool STATIC CompilerInvocation.cpp IDEInspectionInstance.cpp DependencyChecking.cpp + SyntacticMacroExpansion.cpp ) target_link_libraries(swiftIDETool PRIVATE diff --git a/lib/IDETool/SyntacticMacroExpansion.cpp b/lib/IDETool/SyntacticMacroExpansion.cpp new file mode 100644 index 0000000000000..03dcf191685b8 --- /dev/null +++ b/lib/IDETool/SyntacticMacroExpansion.cpp @@ -0,0 +1,467 @@ +//===--- SyntacticMacroExpansion.cpp --------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "swift/IDETool/SyntacticMacroExpansion.h" +#include "swift/AST/ASTWalker.h" +#include "swift/AST/MacroDefinition.h" +#include "swift/AST/PluginLoader.h" +#include "swift/AST/TypeRepr.h" +#include "swift/Driver/FrontendUtil.h" +#include "swift/Frontend/Frontend.h" +#include "swift/IDE/Utils.h" +#include "swift/Sema/IDETypeChecking.h" + +using namespace swift; +using namespace ide; + +std::shared_ptr +SyntacticMacroExpansion::getInstance(ArrayRef args, + std::string &error) { + // Compute the signature of the invocation. + StableHasher argHasher = StableHasher::defaultHasher(); + for (auto arg : args) + argHasher.combine(StringRef(arg)); + Fingerprint argHash(std::move(argHasher)); + + // Check if the current instance is usable. + if (auto currentInstance = this->currentInstance) { + if (currentInstance->getArgHash() == argHash) { + return currentInstance; + } + } + + // Create and configure a new instance. + auto instance = std::make_shared(argHash); + + bool failed = instance->setup(SwiftExecutablePath, args, Plugins, error); + if (failed) + return nullptr; + + currentInstance = instance; + return instance; +} + +bool SyntacticMacroExpansionInstance::setup( + StringRef SwiftExecutablePath, ArrayRef args, + std::shared_ptr plugins, std::string &error) { + SmallString<256> driverPath(SwiftExecutablePath); + llvm::sys::path::remove_filename(driverPath); + llvm::sys::path::append(driverPath, "swiftc"); + + // Setup CompilerInstance to configure the plugin search path correctly. + bool hadError = driver::getSingleFrontendInvocationFromDriverArguments( + driverPath, args, Diags, + [&](ArrayRef frontendArgs) { + return invocation.parseArgs( + frontendArgs, Diags, /*ConfigurationFileBuffers=*/nullptr, + /*workingDirectory=*/{}, SwiftExecutablePath); + }, + /*ForceNoOutput=*/true); + if (hadError) { + error = "failed to setup compiler invocation"; + return true; + } + + // Setup filesystem. + auto FS = invocation.getSearchPathOptions().makeOverlayFileSystem( + SourceMgr.getFileSystem()); + if (!FS) { + llvm::consumeError(FS.takeError()); + error = "failed to setup overlay filesystem"; + return true; + } + SourceMgr.setFileSystem(FS.get()); + + // Setup ASTContext. + Ctx.reset(ASTContext::get( + invocation.getLangOptions(), invocation.getTypeCheckerOptions(), + invocation.getSILOptions(), invocation.getSearchPathOptions(), + invocation.getClangImporterOptions(), invocation.getSymbolGraphOptions(), + SourceMgr, Diags)); + registerParseRequestFunctions(Ctx->evaluator); + registerTypeCheckerRequestFunctions(Ctx->evaluator); + + std::unique_ptr pluginLoader = + std::make_unique(*Ctx, /*DepTracker=*/nullptr); + pluginLoader->setRegistry(plugins.get()); + Ctx->setPluginLoader(std::move(pluginLoader)); + + // Create a module where SourceFiles reside. + Identifier ID = Ctx->getIdentifier(invocation.getModuleName()); + TheModule = ModuleDecl::create(ID, *Ctx); + + return false; +} + +SourceFile * +SyntacticMacroExpansionInstance::getSourceFile(llvm::MemoryBuffer *inputBuf) { + + // If there is a SourceFile with the same name and the content, use it. + // Note that this finds the generated source file that was created in the + // previous expansion requests. + if (auto bufID = + SourceMgr.getIDForBufferIdentifier(inputBuf->getBufferIdentifier())) { + if (inputBuf->getBuffer() == SourceMgr.getEntireTextForBuffer(*bufID)) { + SourceLoc bufLoc = SourceMgr.getLocForBufferStart(*bufID); + if (SourceFile *existing = + TheModule->getSourceFileContainingLocation(bufLoc)) { + return existing; + } + } + } + + // Otherwise, create a new SourceFile. + SourceFile *SF = new (getASTContext()) SourceFile( + *TheModule, SourceFileKind::Main, SourceMgr.addMemBufferCopy(inputBuf)); + SF->setImports({}); + TheModule->addFile(*SF); + + return SF; +} + +MacroDecl *SyntacticMacroExpansionInstance::getSynthesizedMacroDecl( + Identifier name, const MacroExpansionSpecifier &expansion) { + auto &ctx = getASTContext(); + + // Reuse cached MacroDecl of the same name if it's already created. + MacroDecl *macro; + auto found = MacroDecls.find(name); + if (found != MacroDecls.end()) { + macro = found->second; + } else { + macro = new (ctx) MacroDecl( + /*macroLoc=*/{}, DeclName(name), /*nameLoc=*/{}, + /*genericParams=*/nullptr, /*parameterList=*/nullptr, + /*arrowLoc=*/{}, /*resultType=*/nullptr, + /*definition=*/nullptr, /*parent=*/TheModule); + macro->setImplicit(); + MacroDecls.insert({name, macro}); + } + + // Add missing role attributes to MacroDecl. + MacroRoles roles = expansion.macroRoles; + for (auto attr : macro->getAttrs().getAttributes()) { + roles -= attr->getMacroRole(); + } + for (MacroRole role : getAllMacroRoles()) { + if (!roles.contains(role)) + continue; + + MacroSyntax syntax = getFreestandingMacroRoles().contains(role) + ? MacroSyntax::Freestanding + : MacroSyntax::Attached; + + auto *attr = MacroRoleAttr::create(ctx, /*atLoc=*/{}, /*range=*/{}, syntax, + /*lParenLoc=*/{}, role, /*names=*/{}, + /*rParenLoc=*/{}, /*implicit=*/true); + macro->getAttrs().add(attr); + } + + // Set the macro definition. + macro->setDefinition(expansion.macroDefinition); + + return macro; +} + +/// Create a unique name of the expansion. The result is *appended* to \p out. +static void addExpansionDiscriminator(SmallString<32> &out, + const SourceFile *SF, SourceLoc loc, + MacroDecl *macro, + Optional role = None) { + SourceManager &SM = SF->getASTContext().SourceMgr; + auto lineColumn = SM.getLineAndColumnInBuffer(loc); + + StableHasher hasher = StableHasher::defaultHasher(); + + // Macro name. + hasher.combine(macro->getName().getBaseIdentifier().str()); + hasher.combine(uint8_t{0}); + + // Module name. + hasher.combine(SF->getParentModule()->getName().str()); + hasher.combine(uint8_t{0}); + + // File base name. + // Do not use the full path because we want this hash stable. + hasher.combine(llvm::sys::path::filename(SF->getFilename())); + hasher.combine(uint8_t{0}); + + // Line/column + hasher.combine(lineColumn.first); + hasher.combine(lineColumn.second); + + // Macro role. + if (role) { + hasher.combine(*role); + } + + Fingerprint hash(std::move(hasher)); + out.append(hash.getRawValue()); +} + +/// Perform expansion of the specified freestanding macro using the 'MacroDecl'. +static std::vector +expandFreestandingMacro(MacroDecl *macro, + FreestandingMacroExpansion *expansion) { + std::vector bufferIDs; + + SmallString<32> discriminator; + discriminator.append("macro_"); + addExpansionDiscriminator(discriminator, + expansion->getDeclContext()->getParentSourceFile(), + expansion->getPoundLoc(), macro); + + expansion->setMacroRef(macro); + + SourceFile *expandedSource = + swift::evaluateFreestandingMacro(expansion, discriminator); + if (expandedSource) + bufferIDs.push_back(*expandedSource->getBufferID()); + + return bufferIDs; +} + +/// Perform expansion of the specified decl and the attribute using the +/// 'MacroDecl'. If the macro has multiple roles, evaluate it for all macro +/// roles. +static std::vector +expandAttachedMacro(MacroDecl *macro, CustomAttr *attr, Decl *attachedDecl) { + + std::vector bufferIDs; + auto evaluate = [&](Decl *target, bool passParent, MacroRole role) { + + SmallString<32> discriminator; + discriminator.append("macro_"); + addExpansionDiscriminator(discriminator, + target->getDeclContext()->getParentSourceFile(), + target->getLoc(), macro, role); + + SourceFile *expandedSource = swift::evaluateAttachedMacro( + macro, target, attr, passParent, role, discriminator); + if (expandedSource) + bufferIDs.push_back(*expandedSource->getBufferID()); + }; + + MacroRoles roles = macro->getMacroRoles(); + if (roles.contains(MacroRole::Accessor)) { + if (isa(attachedDecl)) + evaluate(attachedDecl, /*passParent=*/false, MacroRole::Accessor); + } + if (roles.contains(MacroRole::MemberAttribute)) { + if (auto *idc = dyn_cast(attachedDecl)) { + for (auto *member : idc->getParsedMembers()) { + // 'VarDecl' in 'IterableDeclContext' are part of 'PatternBindingDecl'. + if (isa(member)) + continue; + evaluate(member, /*passParent=*/true, MacroRole::MemberAttribute); + } + } + } + if (roles.contains(MacroRole::Member)) { + evaluate(attachedDecl, /*passParent=*/false, MacroRole::Member); + } + if (roles.contains(MacroRole::Peer)) { + evaluate(attachedDecl, /*passParent=*/false, MacroRole::Peer); + } + if (roles.contains(MacroRole::Conformance)) { + evaluate(attachedDecl, /*passParent=*/false, MacroRole::Conformance); + } + return bufferIDs; +} + +/// Get the name of the custom attribute. This is used to create a dummy +/// MacroDecl. +static Identifier getCustomAttrName(ASTContext &ctx, const CustomAttr *attr) { + TypeRepr *tyR = attr->getTypeRepr(); + if (auto ref = dyn_cast(tyR)) { + return ref->getNameRef().getBaseIdentifier(); + } + + // If the attribute is not an identifier type, create an identifier with its + // textual representation. + SmallString<32> name; + llvm::raw_svector_ostream OS(name); + tyR->print(OS); + return ctx.getIdentifier(name); +} + +namespace { + +/// Find macro expansion i.e. '#foo' or '@foo' at the specified source location. +/// If a freestanding expansion (i.e. #foo) is found, the result 'ExpansionNode' +/// only has the node. If an attribute is found, the attribute and the attached +/// decl object is returned. +struct ExpansionNode { + CustomAttr *attribute; + ASTNode node; +}; +class MacroExpansionFinder : public ASTWalker { + SourceManager &SM; + SourceLoc LocToResolve; + llvm::Optional Result; + + bool rangeContainsLocToResolve(SourceRange Range) const { + return SM.rangeContainsTokenLoc(Range, LocToResolve); + } + +public: + MacroExpansionFinder(SourceManager &SM, SourceLoc LocToResolve) + : SM(SM), LocToResolve(LocToResolve) {} + + llvm::Optional getResult() const { return Result; } + + MacroWalking getMacroWalkingBehavior() const override { + return MacroWalking::None; + } + + PreWalkAction walkToDeclPre(Decl *D) override { + // Visit all 'VarDecl' because 'getSourceRangeIncludingAttrs()' doesn't + // include attribute its ranges. + if (!isa(D) && + !rangeContainsLocToResolve(D->getSourceRangeIncludingAttrs())) { + return Action::SkipChildren(); + } + + // Check the attributes. + for (DeclAttribute *attr : D->getAttrs()) { + if (auto customAttr = dyn_cast(attr)) { + SourceRange nameRange(customAttr->getRangeWithAt().Start, + customAttr->getTypeExpr()->getEndLoc()); + if (rangeContainsLocToResolve(nameRange)) { + Result = ExpansionNode{customAttr, ASTNode(D)}; + return Action::Stop(); + } + } + } + + // Check 'MacroExpansionDecl'. + if (auto med = dyn_cast(D)) { + SourceRange nameRange(med->getExpansionInfo()->SigilLoc, + med->getMacroNameLoc().getEndLoc()); + if (rangeContainsLocToResolve(nameRange)) { + Result = ExpansionNode{nullptr, ASTNode(med)}; + return Action::Stop(); + } + } + + return Action::Continue(); + } + + PreWalkResult walkToExprPre(Expr *E) override { + if (!rangeContainsLocToResolve(E->getSourceRange())) { + return Action::SkipChildren(E); + } + + // Check 'MacroExpansionExpr'. + if (auto mee = dyn_cast(E)) { + SourceRange nameRange(mee->getExpansionInfo()->SigilLoc, + mee->getMacroNameLoc().getEndLoc()); + if (rangeContainsLocToResolve(nameRange)) { + Result = ExpansionNode{nullptr, ASTNode(mee)}; + return Action::Stop(); + } + } + + return Action::Continue(E); + } + + PreWalkResult walkToStmtPre(Stmt *S) override { + if (!rangeContainsLocToResolve(S->getSourceRange())) { + return Action::SkipChildren(S); + } + return Action::Continue(S); + } + PreWalkResult + walkToArgumentListPre(ArgumentList *AL) override { + if (!rangeContainsLocToResolve(AL->getSourceRange())) { + return Action::SkipChildren(AL); + } + return Action::Continue(AL); + } + PreWalkAction walkToParameterListPre(ParameterList *PL) override { + if (!rangeContainsLocToResolve(PL->getSourceRange())) { + return Action::SkipChildren(); + } + return Action::Continue(); + } + PreWalkAction walkToTypeReprPre(TypeRepr *T) override { + // TypeRepr cannot have macro expansions in it. + return Action::SkipChildren(); + } +}; +} // namespace + +bool SyntacticMacroExpansionInstance::getExpansion( + SourceFile *SF, const MacroExpansionSpecifier &expansion, + SourceEditConsumer &consumer) { + + // Find the expansion at 'expantion.offset'. + MacroExpansionFinder expansionFinder( + SourceMgr, + SourceMgr.getLocForOffset(*SF->getBufferID(), expansion.offset)); + SF->walk(expansionFinder); + auto expansionNode = expansionFinder.getResult(); + if (!expansionNode) + return true; + + // Expand the macro. + std::vector bufferIDs; + if (auto *attr = expansionNode->attribute) { + // Attached macros. + MacroDecl *macro = getSynthesizedMacroDecl( + getCustomAttrName(getASTContext(), attr), expansion); + auto *attachedTo = expansionNode->node.get(); + bufferIDs = expandAttachedMacro(macro, attr, attachedTo); + + // For an attached macro, remove the custom attribute; it's been fully + // subsumed by its expansions. + SourceRange range = attr->getRangeWithAt(); + auto charRange = Lexer::getCharSourceRangeFromSourceRange(SourceMgr, range); + consumer.remove(SourceMgr, charRange); + } else { + // Freestanding macros. + FreestandingMacroExpansion *freestanding; + auto node = expansionNode->node; + if (node.is()) { + freestanding = cast(node.get()); + } else { + freestanding = cast(node.get()); + } + + MacroDecl *macro = getSynthesizedMacroDecl( + freestanding->getMacroName().getBaseIdentifier(), expansion); + bufferIDs = expandFreestandingMacro(macro, freestanding); + } + + // Send all edits to the consumer. + for (unsigned bufferID : bufferIDs) { + consumer.acceptMacroExpansionBuffer(SourceMgr, bufferID, SF, + /*adjust=*/false); + } + + return false; +} + +bool SyntacticMacroExpansionInstance::getExpansions( + llvm::MemoryBuffer *inputBuf, ArrayRef expansions, + SourceEditConsumer &consumer) { + std::scoped_lock lock(mtx); + + // Create a source file. + SourceFile *SF = getSourceFile(inputBuf); + + bool hasError = false; + for (const auto &expansion : expansions) { + hasError |= getExpansion(SF, expansion, consumer); + } + return hasError; +} diff --git a/lib/Refactoring/Refactoring.cpp b/lib/Refactoring/Refactoring.cpp index 515b96a0e50e7..1082ac6666cf8 100644 --- a/lib/Refactoring/Refactoring.cpp +++ b/lib/Refactoring/Refactoring.cpp @@ -8754,40 +8754,6 @@ getMacroExpansionBuffers(SourceManager &sourceMgr, ResolvedCursorInfoPtr Info) { return {}; } -/// Given the expanded code for a particular macro, perform whitespace -/// adjustments to make the refactoring more suitable for inline insertion. -static StringRef adjustMacroExpansionWhitespace( - GeneratedSourceInfo::Kind kind, StringRef expandedCode, - llvm::SmallString<64> &scratch) { - scratch.clear(); - - switch (kind) { - case GeneratedSourceInfo::MemberAttributeMacroExpansion: - // Attributes are added to the beginning, add a space to separate from - // any existing. - scratch += expandedCode; - scratch += " "; - return scratch; - - case GeneratedSourceInfo::MemberMacroExpansion: - case GeneratedSourceInfo::PeerMacroExpansion: - case GeneratedSourceInfo::ConformanceMacroExpansion: - // All added to the end. Note that conformances are always expanded as - // extensions, hence treating them the same as peer. - scratch += "\n\n"; - scratch += expandedCode; - scratch += "\n"; - return scratch; - - case GeneratedSourceInfo::ExpressionMacroExpansion: - case GeneratedSourceInfo::FreestandingDeclMacroExpansion: - case GeneratedSourceInfo::AccessorMacroExpansion: - case GeneratedSourceInfo::ReplacedFunctionBody: - case GeneratedSourceInfo::PrettyPrinted: - return expandedCode; - } -} - static bool expandMacro(SourceManager &SM, ResolvedCursorInfoPtr cursorInfo, SourceEditConsumer &editConsumer, bool adjustExpansion) { auto bufferIDs = getMacroExpansionBuffers(SM, cursorInfo); @@ -8799,68 +8765,19 @@ static bool expandMacro(SourceManager &SM, ResolvedCursorInfoPtr cursorInfo, return true; // Send all of the rewritten buffer snippets. - CustomAttr *attachedMacroAttr = nullptr; - SmallString<64> scratchBuffer; for (auto bufferID: bufferIDs) { - auto generatedInfo = SM.getGeneratedSourceInfo(bufferID); - if (!generatedInfo || generatedInfo->originalSourceRange.isInvalid()) - continue; - - auto rewrittenBuffer = SM.extractText(generatedInfo->generatedSourceRange); - - // If there's no change, drop the edit entirely. - if (generatedInfo->originalSourceRange.getStart() == - generatedInfo->originalSourceRange.getEnd() && - rewrittenBuffer.empty()) - continue; - - if (adjustExpansion) { - rewrittenBuffer = adjustMacroExpansionWhitespace(generatedInfo->kind, rewrittenBuffer, scratchBuffer); - } - - // `containingFile` is the file of the actual expansion site, where as - // `originalFile` is the possibly enclosing buffer. Concretely: - // ``` - // // m.swift - // @AddMemberAttributes - // struct Foo { - // // --- expanded from @AddMemberAttributes eg. @_someBufferName --- - // @AddedAttribute - // // --- - // let someMember: Int - // } - // ``` - // - // When expanding `AddedAttribute`, the expansion actually applies to the - // original source (`m.swift`) rather than the buffer of the expansion - // site (`@_someBufferName`). Thus, we need to include the path to the - // original source as well. Note that this path could itself be another - // expansion. - auto originalSourceRange = generatedInfo->originalSourceRange; - SourceFile *originalFile = - containingSF->getParentModule()->getSourceFileContainingLocation(originalSourceRange.getStart()); - StringRef originalPath; - if (originalFile->getBufferID().hasValue() && - containingSF->getBufferID() != originalFile->getBufferID()) { - originalPath = SM.getIdentifierForBuffer(*originalFile->getBufferID()); - } - - editConsumer.accept(SM, {originalPath, - originalSourceRange, - SM.getIdentifierForBuffer(bufferID), - rewrittenBuffer, - {}}); - - if (generatedInfo->attachedMacroCustomAttr && !attachedMacroAttr) - attachedMacroAttr = generatedInfo->attachedMacroCustomAttr; + editConsumer.acceptMacroExpansionBuffer(SM, bufferID, containingSF, + adjustExpansion); } // For an attached macro, remove the custom attribute; it's been fully // subsumed by its expansions. - if (attachedMacroAttr) { + if (auto attrRef = + cast(cursorInfo)->getCustomAttrRef()) { + const CustomAttr *attachedMacroAttr = attrRef->first; SourceRange range = attachedMacroAttr->getRangeWithAt(); auto charRange = Lexer::getCharSourceRangeFromSourceRange(SM, range); - editConsumer.accept(SM, charRange, StringRef()); + editConsumer.remove(SM, charRange); } return false; diff --git a/lib/Sema/TypeCheckMacros.cpp b/lib/Sema/TypeCheckMacros.cpp index 9cc35ba4264f7..b607f918842c4 100644 --- a/lib/Sema/TypeCheckMacros.cpp +++ b/lib/Sema/TypeCheckMacros.cpp @@ -39,6 +39,7 @@ #include "swift/Demangling/Demangler.h" #include "swift/Demangling/ManglingMacros.h" #include "swift/Parse/Lexer.h" +#include "swift/Sema/IDETypeChecking.h" #include "swift/Subsystems.h" #include "llvm/Config/config.h" @@ -861,7 +862,8 @@ createMacroSourceFile(std::unique_ptr buffer, /// Evaluate the given freestanding macro expansion. static SourceFile * -evaluateFreestandingMacro(FreestandingMacroExpansion *expansion) { +evaluateFreestandingMacro(FreestandingMacroExpansion *expansion, + StringRef discriminatorStr = "") { auto *dc = expansion->getDeclContext(); ASTContext &ctx = dc->getASTContext(); SourceLoc loc = expansion->getPoundLoc(); @@ -889,6 +891,8 @@ evaluateFreestandingMacro(FreestandingMacroExpansion *expansion) { /// The discriminator used for the macro. LazyValue discriminator([&]() -> std::string { + if (!discriminatorStr.empty()) + return discriminatorStr.str(); #if SWIFT_SWIFT_PARSER Mangle::ASTMangler mangler; return mangler.mangleMacroExpansion(expansion); @@ -983,7 +987,7 @@ evaluateFreestandingMacro(FreestandingMacroExpansion *expansion) { } Optional swift::expandMacroExpr(MacroExpansionExpr *mee) { - SourceFile *macroSourceFile = evaluateFreestandingMacro(mee); + SourceFile *macroSourceFile = ::evaluateFreestandingMacro(mee); if (!macroSourceFile) return None; @@ -1043,7 +1047,7 @@ Optional swift::expandMacroExpr(MacroExpansionExpr *mee) { /// Expands the given macro expansion declaration. Optional swift::expandFreestandingMacro(MacroExpansionDecl *med) { - SourceFile *macroSourceFile = evaluateFreestandingMacro(med); + SourceFile *macroSourceFile = ::evaluateFreestandingMacro(med); if (!macroSourceFile) return None; @@ -1065,9 +1069,10 @@ swift::expandFreestandingMacro(MacroExpansionDecl *med) { return *macroSourceFile->getBufferID(); } -static SourceFile * -evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, CustomAttr *attr, - bool passParentContext, MacroRole role) { +static SourceFile *evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, + CustomAttr *attr, + bool passParentContext, MacroRole role, + StringRef discriminatorStr = "") { DeclContext *dc; if (role == MacroRole::Peer) { dc = attachedTo->getDeclContext(); @@ -1117,6 +1122,8 @@ evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, CustomAttr *attr, /// The discriminator used for the macro. LazyValue discriminator([&]() -> std::string { + if (!discriminatorStr.empty()) + return discriminatorStr.str(); #if SWIFT_SWIFT_PARSER Mangle::ASTMangler mangler; return mangler.mangleAttachedMacroExpansion(attachedTo, attr, role); @@ -1229,9 +1236,9 @@ Optional swift::expandAccessors( AbstractStorageDecl *storage, CustomAttr *attr, MacroDecl *macro ) { // Evaluate the macro. - auto macroSourceFile = evaluateAttachedMacro(macro, storage, attr, - /*passParentContext*/false, - MacroRole::Accessor); + auto macroSourceFile = + ::evaluateAttachedMacro(macro, storage, attr, + /*passParentContext=*/false, MacroRole::Accessor); if (!macroSourceFile) return None; @@ -1280,9 +1287,9 @@ ArrayRef ExpandAccessorMacros::evaluate( Optional swift::expandAttributes(CustomAttr *attr, MacroDecl *macro, Decl *member) { // Evaluate the macro. - auto macroSourceFile = evaluateAttachedMacro(macro, member, attr, - /*passParentContext*/true, - MacroRole::MemberAttribute); + auto macroSourceFile = ::evaluateAttachedMacro(macro, member, attr, + /*passParentContext=*/true, + MacroRole::MemberAttribute); if (!macroSourceFile) return None; @@ -1305,9 +1312,9 @@ swift::expandAttributes(CustomAttr *attr, MacroDecl *macro, Decl *member) { Optional swift::expandMembers(CustomAttr *attr, MacroDecl *macro, Decl *decl) { // Evaluate the macro. - auto macroSourceFile = evaluateAttachedMacro(macro, decl, attr, - /*passParentContext*/false, - MacroRole::Member); + auto macroSourceFile = + ::evaluateAttachedMacro(macro, decl, attr, + /*passParentContext=*/false, MacroRole::Member); if (!macroSourceFile) return None; @@ -1332,9 +1339,9 @@ swift::expandMembers(CustomAttr *attr, MacroDecl *macro, Decl *decl) { Optional swift::expandPeers(CustomAttr *attr, MacroDecl *macro, Decl *decl) { - auto macroSourceFile = evaluateAttachedMacro(macro, decl, attr, - /*passParentContext*/false, - MacroRole::Peer); + auto macroSourceFile = + ::evaluateAttachedMacro(macro, decl, attr, + /*passParentContext=*/false, MacroRole::Peer); if (!macroSourceFile) return None; @@ -1358,10 +1365,9 @@ ExpandConformanceMacros::evaluate(Evaluator &evaluator, Optional swift::expandConformances(CustomAttr *attr, MacroDecl *macro, NominalTypeDecl *nominal) { - auto macroSourceFile = - evaluateAttachedMacro(macro, nominal, attr, - /*passParentContext*/false, - MacroRole::Conformance); + auto macroSourceFile = ::evaluateAttachedMacro(macro, nominal, attr, + /*passParentContext=*/false, + MacroRole::Conformance); if (!macroSourceFile) return None; @@ -1448,3 +1454,19 @@ ConcreteDeclRef ResolveMacroRequest::evaluate(Evaluator &evaluator, return macroExpansion->getMacroRef(); } + +// MARK: for IDE. + +SourceFile *swift::evaluateAttachedMacro(MacroDecl *macro, Decl *attachedTo, + CustomAttr *attr, + bool passParentContext, MacroRole role, + StringRef discriminator) { + return ::evaluateAttachedMacro(macro, attachedTo, attr, passParentContext, + role, discriminator); +} + +SourceFile * +swift::evaluateFreestandingMacro(FreestandingMacroExpansion *expansion, + StringRef discriminator) { + return ::evaluateFreestandingMacro(expansion, discriminator); +} diff --git a/test/SourceKit/Macros/syntactic_expansion.swift b/test/SourceKit/Macros/syntactic_expansion.swift new file mode 100644 index 0000000000000..db5aa6bbd6305 --- /dev/null +++ b/test/SourceKit/Macros/syntactic_expansion.swift @@ -0,0 +1,66 @@ +//--- test.swift +@DelegatedConformance +@wrapAllProperties +struct Generic { + + @myPropertyWrapper + @otherAttr + var value: Int + + func member() {} + var otherVal: Int = 1 + + #bitwidthNumberedStructs("blah") +} + +//--- DelegatedConformance.json +{ + key.macro_roles: [source.lang.swift.macrorole.conformance, source.lang.swift.macrorole.member], + key.modulename: "MacroDefinition", + key.typename: "DelegatedConformanceMacro", +} + +//--- myPropertyWrapper.json +{ + key.macro_roles: [source.lang.swift.macrorole.accessor, source.lang.swift.macrorole.peer], + key.modulename: "MacroDefinition", + key.typename: "PropertyWrapperMacro", +} + +//--- wrapAllProperties.json +{ + key.macro_roles: [source.lang.swift.macrorole.memberattribute], + key.modulename: "MacroDefinition", + key.typename: "WrapAllProperties", +} + +//--- bitwidthNumberedStructs.json +{ + key.macro_roles: [source.lang.swift.macrorole.declaration], + key.modulename: "MacroDefinition", + key.typename: "DefineBitwidthNumberedStructsMacro", +} + +//--- dummy.script +// REQUIRES: swift_swift_parser + +// RUN: %empty-directory(%t) +// RUN: mkdir -p %t/plugins +// RUN: split-file %s %t + +//##-- Prepare the macro plugin. +// RUN: %host-build-swift -swift-version 5 -emit-library -o %t/plugins/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/../../Macros/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath + +// RUN: %sourcekitd-test -req=syntactic-expandmacro \ +// RUN: -req-opts=1:1:%t/DelegatedConformance.json \ +// RUN: -req-opts=5:3:%t/myPropertyWrapper.json \ +// RUN: -req-opts=2:1:%t/wrapAllProperties.json \ +// RUN: -req-opts=12:3:%t/bitwidthNumberedStructs.json \ +// RUN: %t/test.swift \ +// RUN: -- \ +// RUN: %t/test.swift \ +// RUN: -plugin-path %t/plugins -Xfrontend -dump-macro-expansions \ +// RUN: -module-name TestModule \ +// RUN: | tee %t.response + +// RUN: diff -u %s.expected %t.response diff --git a/test/SourceKit/Macros/syntactic_expansion.swift.expected b/test/SourceKit/Macros/syntactic_expansion.swift.expected new file mode 100644 index 0000000000000..727a9910f3a1a --- /dev/null +++ b/test/SourceKit/Macros/syntactic_expansion.swift.expected @@ -0,0 +1,131 @@ +{ + key.categorizededits: [ + { + key.edits: [ + { + key.line: 1, + key.column: 1, + key.endline: 1, + key.endcolumn: 22, + key.text: "" + } + ], + key.category: source.edit.kind.active + }, + { + key.edits: [ + { + key.line: 13, + key.column: 1, + key.endline: 13, + key.endcolumn: 1, + key.text: "static func requirement() where Element : P {\n Element.requirement()\n}", + key.buffer_name: "macro_185a888f5c6c1a9445a25edf7028dc75.swift" + } + ], + key.category: source.edit.kind.active + }, + { + key.edits: [ + { + key.line: 13, + key.column: 2, + key.endline: 13, + key.endcolumn: 2, + key.text: "extension Generic : P where Element: P {}", + key.buffer_name: "macro_c5de351c406a933f1a952846b34e0639.swift" + } + ], + key.category: source.edit.kind.active + }, + { + key.edits: [ + { + key.line: 5, + key.column: 3, + key.endline: 5, + key.endcolumn: 21, + key.text: "" + } + ], + key.category: source.edit.kind.active + }, + { + key.edits: [ + { + key.line: 7, + key.column: 17, + key.endline: 7, + key.endcolumn: 17, + key.text: "{\n get {\n _value.wrappedValue\n }\n\n set {\n _value.wrappedValue = newValue\n }\n}", + key.buffer_name: "macro_695ff4226d699e531ba7bb4cc103005a.swift" + } + ], + key.category: source.edit.kind.active + }, + { + key.edits: [ + { + key.line: 7, + key.column: 12, + key.endline: 7, + key.endcolumn: 12, + key.text: "var _value: MyWrapperThingy", + key.buffer_name: "macro_629ec828bcb8e81543f19a16c7f1ac1d.swift" + } + ], + key.category: source.edit.kind.active + }, + { + key.edits: [ + { + key.line: 2, + key.column: 1, + key.endline: 2, + key.endcolumn: 19, + key.text: "" + } + ], + key.category: source.edit.kind.active + }, + { + key.edits: [ + { + key.line: 7, + key.column: 3, + key.endline: 7, + key.endcolumn: 3, + key.text: "@Wrapper", + key.buffer_name: "macro_cf98ea58703480a8a577ab40e66fb8e1.swift" + } + ], + key.category: source.edit.kind.active + }, + { + key.edits: [ + { + key.line: 10, + key.column: 3, + key.endline: 10, + key.endcolumn: 3, + key.text: "@Wrapper", + key.buffer_name: "macro_3ac1e34ba8396a85fb44db3e6f52cc26.swift" + } + ], + key.category: source.edit.kind.active + }, + { + key.edits: [ + { + key.line: 12, + key.column: 3, + key.endline: 12, + key.endcolumn: 35, + key.text: "struct blah8 {\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu_() {\n }\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu0_() {\n }\n}\nstruct blah16 {\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu1_() {\n }\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu2_() {\n }\n}\nstruct blah32 {\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu3_() {\n }\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu4_() {\n }\n}\nstruct blah64 {\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu5_() {\n }\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu6_() {\n }\n}", + key.buffer_name: "macro_373e16cc0bde29e604b8bfcf27292b37.swift" + } + ], + key.category: source.edit.kind.active + } + ] +} diff --git a/tools/SourceKit/include/SourceKit/Core/LangSupport.h b/tools/SourceKit/include/SourceKit/Core/LangSupport.h index 5dccd87dd59a0..4f1d28b53ab3e 100644 --- a/tools/SourceKit/include/SourceKit/Core/LangSupport.h +++ b/tools/SourceKit/include/SourceKit/Core/LangSupport.h @@ -220,6 +220,60 @@ struct RawCharSourceRange { unsigned Length; }; +enum class MacroRole : uint8_t { + // This should align with 'swift::MacroRole'. + Expression = 0x01, + Declaration = 0x02, + Accessor = 0x04, + MemberAttribute = 0x08, + Member = 0x10, + Peer = 0x20, + Conformance = 0x40, + CodeItem = 0x80, +}; +using MacroRoles = swift::OptionSet; + +struct MacroExpansionInfo { + // See swift::ExternalMacroReference. + struct ExternalMacroReference { + std::string moduleName; + std::string typeName; + + ExternalMacroReference(StringRef moduleName, StringRef typeName) + : moduleName(moduleName), typeName(typeName){}; + }; + // See swift::ExpandedMacroDefinition. + struct ExpandedMacroDefinition { + struct Replacement { + RawCharSourceRange range; + unsigned parameterIndex; + Replacement(RawCharSourceRange range, unsigned parameterIndex) + : range(range), parameterIndex(parameterIndex) {} + }; + std::string expansionText; + std::vector replacements; + + ExpandedMacroDefinition(StringRef expansionText) + : expansionText(expansionText), replacements(){}; + }; + + // Offset of the macro expansion syntax (i.e. attribute or #) + unsigned offset; + + // Macro roles. + MacroRoles roles; + + // Tagged union of macro definition. + std::variant macroDefinition; + + MacroExpansionInfo(unsigned offset, MacroRoles roles, + ExternalMacroReference macroRef) + : offset(offset), roles(roles), macroDefinition(macroRef) {} + MacroExpansionInfo(unsigned offset, MacroRoles roles, + ExpandedMacroDefinition definition) + : offset(offset), roles(roles), macroDefinition(definition) {} +}; + /// Stores information about a given buffer, including its name and, if /// generated, its source text and original location. struct BufferInfo { @@ -1128,6 +1182,11 @@ class LangSupport { ConformingMethodListConsumer &Consumer, Optional vfsOptions) = 0; + virtual void expandMacroSyntactically(llvm::MemoryBuffer *inputBuf, + ArrayRef args, + ArrayRef expansions, + CategorizedEditsReceiver receiver) = 0; + virtual void performCompile(StringRef Name, ArrayRef Args, Optional vfsOptions, diff --git a/tools/SourceKit/lib/SwiftLang/CMakeLists.txt b/tools/SourceKit/lib/SwiftLang/CMakeLists.txt index 38725d140d215..31f596e5a0019 100644 --- a/tools/SourceKit/lib/SwiftLang/CMakeLists.txt +++ b/tools/SourceKit/lib/SwiftLang/CMakeLists.txt @@ -11,6 +11,7 @@ add_sourcekit_library(SourceKitSwiftLang SwiftLangSupport.cpp SwiftMangling.cpp SwiftSourceDocInfo.cpp + SwiftSyntacticMacroExpansion.cpp SwiftTypeContextInfo.cpp LLVM_LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} bitreader diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp index a77254e38d6ce..6f8b019d2db92 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.cpp @@ -29,6 +29,7 @@ #include "swift/IDE/SyntaxModel.h" #include "swift/IDE/Utils.h" #include "swift/IDETool/IDEInspectionInstance.h" +#include "swift/IDETool/SyntacticMacroExpansion.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" @@ -303,6 +304,9 @@ SwiftLangSupport::SwiftLangSupport(SourceKit::Context &SKCtx) // By default, just use the in-memory cache. CCCache->inMemory = std::make_unique(); + SyntacticMacroExpansions = + std::make_shared(SwiftExecutablePath, Plugins); + // Provide a default file system provider. setFileSystemProvider("in-memory-vfs", std::make_unique()); } diff --git a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h index 5fd15b589bd20..ad4a8a7fe5769 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h +++ b/tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h @@ -55,6 +55,7 @@ namespace ide { class IDEInspectionInstance; class OnDiskCodeCompletionCache; class SourceEditConsumer; + class SyntacticMacroExpansion; enum class CodeCompletionDeclKind : uint8_t; enum class SyntaxNodeKind : uint8_t; enum class SyntaxStructureKind : uint8_t; @@ -366,6 +367,7 @@ class SwiftLangSupport : public LangSupport { llvm::StringMap> FileSystemProviders; std::shared_ptr IDEInspectionInst; std::shared_ptr CompileManager; + std::shared_ptr SyntacticMacroExpansions; public: explicit SwiftLangSupport(SourceKit::Context &SKCtx); @@ -756,6 +758,11 @@ class SwiftLangSupport : public LangSupport { ConformingMethodListConsumer &Consumer, Optional vfsOptions) override; + void expandMacroSyntactically(llvm::MemoryBuffer *inputBuf, + ArrayRef args, + ArrayRef expansions, + CategorizedEditsReceiver receiver) override; + void performCompile(StringRef Name, ArrayRef Args, Optional vfsOptions, diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSyntacticMacroExpansion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSyntacticMacroExpansion.cpp new file mode 100644 index 0000000000000..b17c258415d4f --- /dev/null +++ b/tools/SourceKit/lib/SwiftLang/SwiftSyntacticMacroExpansion.cpp @@ -0,0 +1,94 @@ +//===--- SwiftSyntaxMacro.cpp ---------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2023 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +#include "SwiftLangSupport.h" +#include "swift/AST/MacroDefinition.h" +#include "swift/Frontend/Frontend.h" +#include "swift/Frontend/PrintingDiagnosticConsumer.h" +#include "swift/IDE/TypeContextInfo.h" +#include "swift/IDETool/SyntacticMacroExpansion.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Comment.h" +#include "clang/AST/Decl.h" + +using namespace SourceKit; +using namespace swift; +using namespace ide; + +void SwiftLangSupport::expandMacroSyntactically( + llvm::MemoryBuffer *inputBuf, ArrayRef args, + ArrayRef reqExpansions, + CategorizedEditsReceiver receiver) { + + std::string error; + auto instance = SyntacticMacroExpansions->getInstance(args, error); + if (!instance) { + return receiver( + RequestResult>::fromError(error)); + } + auto &ctx = instance->getASTContext(); + + // Convert 'SourceKit::MacroExpansionInfo' to 'ide::MacroExpansionSpecifier'. + SmallVector expansions; + for (auto &req : reqExpansions) { + unsigned offset = req.offset; + + swift::MacroRoles macroRoles; + if (req.roles.contains(SourceKit::MacroRole::Expression)) + macroRoles |= swift::MacroRole::Expression; + if (req.roles.contains(SourceKit::MacroRole::Declaration)) + macroRoles |= swift::MacroRole::Declaration; + if (req.roles.contains(SourceKit::MacroRole::CodeItem)) + macroRoles |= swift::MacroRole::CodeItem; + if (req.roles.contains(SourceKit::MacroRole::Accessor)) + macroRoles |= swift::MacroRole::Accessor; + if (req.roles.contains(SourceKit::MacroRole::MemberAttribute)) + macroRoles |= swift::MacroRole::MemberAttribute; + if (req.roles.contains(SourceKit::MacroRole::Member)) + macroRoles |= swift::MacroRole::Member; + if (req.roles.contains(SourceKit::MacroRole::Peer)) + macroRoles |= swift::MacroRole::Peer; + if (req.roles.contains(SourceKit::MacroRole::Conformance)) + macroRoles |= swift::MacroRole::Conformance; + + MacroDefinition definition = [&] { + if (auto *expanded = + std::get_if( + &req.macroDefinition)) { + SmallVector replacements; + for (auto &reqReplacement : expanded->replacements) { + replacements.push_back( + {/*startOffset=*/reqReplacement.range.Offset, + /*endOffset=*/reqReplacement.range.Offset + + reqReplacement.range.Length, + /*parameterIndex=*/reqReplacement.parameterIndex}); + } + return MacroDefinition::forExpanded(ctx, expanded->expansionText, + replacements); + } else if (auto *externalRef = + std::get_if( + &req.macroDefinition)) { + return MacroDefinition::forExternal( + ctx.getIdentifier(externalRef->moduleName), + ctx.getIdentifier(externalRef->typeName)); + } else { + return MacroDefinition::forUndefined(); + } + }(); + + expansions.push_back({offset, macroRoles, definition}); + } + + RequestRefactoringEditConsumer consumer(receiver); + (void)instance->getExpansions(inputBuf, expansions, consumer); + // consumer automatically send the results on destruction. +} diff --git a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp index e92982d18ea0a..d138fb3932604 100644 --- a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp @@ -153,9 +153,10 @@ bool TestOptions::parseArgs(llvm::ArrayRef Args) { .Case("diags", SourceKitRequest::Diagnostics) .Case("compile", SourceKitRequest::Compile) .Case("compile.close", SourceKitRequest::CompileClose) + .Case("syntactic-expandmacro", SourceKitRequest::SyntacticMacroExpansion) #define SEMANTIC_REFACTORING(KIND, NAME, ID) .Case("refactoring." #ID, SourceKitRequest::KIND) #include "swift/Refactoring/RefactoringKinds.def" - .Default(SourceKitRequest::None); + .Default(SourceKitRequest::None); if (Request == SourceKitRequest::None) { llvm::errs() << "error: invalid request '" << InputArg->getValue() @@ -203,6 +204,7 @@ bool TestOptions::parseArgs(llvm::ArrayRef Args) { << "- collect-type\n" << "- global-config\n" << "- dependency-updated\n" + << "- syntactic-expandmacro\n" #define SEMANTIC_REFACTORING(KIND, NAME, ID) << "- refactoring." #ID "\n" #include "swift/Refactoring/RefactoringKinds.def" "\n"; diff --git a/tools/SourceKit/tools/sourcekitd-test/TestOptions.h b/tools/SourceKit/tools/sourcekitd-test/TestOptions.h index d8b9868dc28c9..ace443a58fa86 100644 --- a/tools/SourceKit/tools/sourcekitd-test/TestOptions.h +++ b/tools/SourceKit/tools/sourcekitd-test/TestOptions.h @@ -70,6 +70,7 @@ enum class SourceKitRequest { Diagnostics, Compile, CompileClose, + SyntacticMacroExpansion, #define SEMANTIC_REFACTORING(KIND, NAME, ID) KIND, #include "swift/Refactoring/RefactoringKinds.def" }; diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index 2db2dc7206c92..1d9601bbef08e 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -416,6 +416,46 @@ static bool readPopularAPIList(StringRef filename, return false; } +/// Read '-req-opts' for syntactic macro expansion request and apply it to 'req' +/// object. +/// The format of the argument is '-req-opts={line}:{column}:{path}' +/// where {path} is a path to a JSON file that has macro roles and definition. +/// {line} and {column} is resolved to 'offset' using \p inputBuf . +static bool setSyntacticMacroExpansions(sourcekitd_object_t req, + TestOptions &Opts, + llvm::MemoryBuffer *inputBuf) { + SmallVector expansions; + for (std::string &opt : Opts.RequestOptions) { + SmallVector args; + StringRef(opt).split(args, ":"); + unsigned line, column; + + if (args.size() != 3 || args[0].getAsInteger(10, line) || + args[1].getAsInteger(10, column)) { + llvm::errs() << "-req-opts should be {line}:{column}:{json-path}"; + return true; + } + unsigned offset = resolveFromLineCol(line, column, inputBuf); + + auto Buffer = getBufferForFilename(args[2], Opts.VFSFiles)->getBuffer(); + char *Err = nullptr; + auto expansion = sourcekitd_request_create_from_yaml(Buffer.data(), &Err); + if (!expansion) { + assert(Err); + llvm::errs() << Err; + free(Err); + return true; + } + sourcekitd_request_dictionary_set_int64(expansion, KeyOffset, + int64_t(offset)); + expansions.push_back(expansion); + } + sourcekitd_request_dictionary_set_value( + req, KeyExpansions, + sourcekitd_request_array_create(expansions.data(), expansions.size())); + return false; +} + namespace { class PrintingTimer { std::string desc; @@ -1107,6 +1147,12 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) { sourcekitd_request_dictionary_set_string(Req, KeyName, SemaName.c_str()); sourcekitd_request_dictionary_set_uid(Req, KeyRequest, RequestCompileClose); break; + + case SourceKitRequest::SyntacticMacroExpansion: + sourcekitd_request_dictionary_set_uid(Req, KeyRequest, + RequestExpandMacroSyntactically); + setSyntacticMacroExpansions(Req, Opts, SourceBuf.get()); + break; } if (!Opts.SourceFile.empty()) { @@ -1366,6 +1412,7 @@ static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts, case SourceKitRequest::ConformingMethodList: case SourceKitRequest::DependencyUpdated: case SourceKitRequest::Diagnostics: + case SourceKitRequest::SyntacticMacroExpansion: printRawResponse(Resp); break; case SourceKitRequest::Compile: diff --git a/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp b/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp index 94686abdf8567..d8cec964fb669 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp +++ b/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp @@ -1824,6 +1824,136 @@ handleRequestDiagnostics(const RequestDict &Req, }); } +/// Expand macros in the specified source file syntactically. +/// +/// Request would look like: +/// { +/// key.compilerargs: [] +/// key.sourcefile: +/// key.sourcetext: (optional) +/// key.expansions: [...] +/// } +/// 'compilerargs' is used for plugin search paths. +/// 'expansion specifier' is +/// { +/// key.offset: +/// key.modulename: +/// key.typename: +/// key.macro_roles: [...] +/// } +/// +/// Sends the results as a 'CategorizedEdits'. Each edit object has +/// 'key.buffer_name' that can be used for recursive expansion. If the +/// client founds nested macro expansion in the expanded source, it can send +/// another request using the buffer name and the source text in the subsequent +/// request. +static void handleRequestExpandMacroSyntactically( + const RequestDict &Req, SourceKitCancellationToken CancellationToken, + ResponseReceiver Rec) { + + Optional vfsOptions = getVFSOptions(Req); + std::unique_ptr inputBuf = + getInputBufForRequestOrEmitError(Req, vfsOptions, Rec); + if (!inputBuf) + return; + + SmallVector args; + if (getCompilerArgumentsForRequestOrEmitError(Req, args, Rec)) + return; + + // key.expansions: [ + // { key.offset: 42, + // key.macro_roles: [source.lang.swift.macrorole.conformance, + // source.lang.swift.macrorole.member], + // key.modulename: "MyMacroImpl", + // key.typename: "StringifyMacro"}, + // { key.offset: 132, + // key.sourceText: "foo(bar, baz)", + // key.macro_roles: [source.lang.swift.macrorole.conformance, + // source.lang.swift.macrorole.member], + // key.expandedmacro_replacements: [ + // {key.offset: 4, key.length: 3, key.argindex: 0}, + // {key.offset: 9, key.length: 3, key.argindex: 1}]} + // ] + std::vector expansions; + bool failed = Req.dictionaryArrayApply(KeyExpansions, [&](RequestDict dict) { + // offset. + int64_t offset; + dict.getInt64(KeyOffset, offset, false); + + // macro roles. + SmallVector macroRoleUIDs; + if (dict.getUIDArray(KeyMacroRoles, macroRoleUIDs, false)) { + Rec(createErrorRequestInvalid( + "missing 'key.macro_roles' for expansion specifier")); + return true; + } + MacroRoles macroRoles; + for (auto uid : macroRoleUIDs) { + if (uid == KindMacroRoleExpression) + macroRoles |= MacroRole::Expression; + if (uid == KindMacroRoleDeclaration) + macroRoles |= MacroRole::Declaration; + if (uid == KindMacroRoleCodeItem) + macroRoles |= MacroRole::CodeItem; + if (uid == KindMacroRoleAccessor) + macroRoles |= MacroRole::Accessor; + if (uid == KindMacroRoleMemberAttribute) + macroRoles |= MacroRole::MemberAttribute; + if (uid == KindMacroRoleMember) + macroRoles |= MacroRole::Member; + if (uid == KindMacroRolePeer) + macroRoles |= MacroRole::Peer; + if (uid == KindMacroRoleConformance) + macroRoles |= MacroRole::Conformance; + } + + // definition. + if (auto moduleName = dict.getString(KeyModuleName)) { + auto typeName = dict.getString(KeyTypeName); + if (!typeName) { + Rec(createErrorRequestInvalid( + "missing 'key.typename' for external macro definition")); + return true; + } + MacroExpansionInfo::ExternalMacroReference definition(moduleName->str(), + typeName->str()); + expansions.emplace_back(offset, macroRoles, definition); + } else if (auto expandedText = dict.getString(KeySourceText)) { + MacroExpansionInfo::ExpandedMacroDefinition definition(*expandedText); + bool failed = dict.dictionaryArrayApply( + KeyExpandedMacroReplacements, [&](RequestDict dict) { + int64_t offset, length, paramIndex; + bool failed = false; + failed |= dict.getInt64(KeyOffset, offset, false); + failed |= dict.getInt64(KeyLength, length, false); + failed |= dict.getInt64(KeyArgIndex, paramIndex, false); + if (failed) { + Rec(createErrorRequestInvalid( + "macro replacement should have key.offset, key.length, and " + "key.argindex")); + return true; + } + definition.replacements.emplace_back( + RawCharSourceRange{unsigned(offset), unsigned(length)}, + paramIndex); + return false; + }); + if (failed) + return true; + expansions.emplace_back(offset, macroRoles, definition); + } + return false; + }); + if (failed) + return; + + LangSupport &Lang = getGlobalContext().getSwiftLangSupport(); + Lang.expandMacroSyntactically( + inputBuf.get(), args, expansions, + [&](const auto &Result) { Rec(createCategorizedEditsResponse(Result)); }); +} + void handleRequestImpl(sourcekitd_object_t ReqObj, SourceKitCancellationToken CancellationToken, ResponseReceiver Rec) { @@ -1927,6 +2057,8 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, HANDLE_REQUEST(RequestRelatedIdents, handleRequestRelatedIdents) HANDLE_REQUEST(RequestActiveRegions, handleRequestActiveRegions) HANDLE_REQUEST(RequestDiagnostics, handleRequestDiagnostics) + HANDLE_REQUEST(RequestExpandMacroSyntactically, + handleRequestExpandMacroSyntactically) { SmallString<64> ErrBuf; diff --git a/utils/gyb_sourcekit_support/UIDs.py b/utils/gyb_sourcekit_support/UIDs.py index 4bd5a9f40a534..197e5c651eef5 100644 --- a/utils/gyb_sourcekit_support/UIDs.py +++ b/utils/gyb_sourcekit_support/UIDs.py @@ -209,6 +209,9 @@ def __init__(self, internal_name, external_name): KEY('IsSynthesized', 'key.is_synthesized'), KEY('BufferName', 'key.buffer_name'), KEY('BarriersEnabled', 'key.barriers_enabled'), + KEY('Expansions', 'key.expansions'), + KEY('MacroRoles', 'key.macro_roles'), + KEY('ExpandedMacroReplacements', 'key.expandedmacro_replacements'), ] @@ -273,7 +276,12 @@ def __init__(self, internal_name, external_name): REQUEST('Diagnostics', 'source.request.diagnostics'), REQUEST('Compile', 'source.request.compile'), REQUEST('CompileClose', 'source.request.compile.close'), +<<<<<<< HEAD REQUEST('EnableRequestBarriers', 'source.request.enable_request_barriers'), +======= + REQUEST('ExpandMacroSyntactically', + 'source.request.expand.macro.syntactically'), +>>>>>>> 309c87b56fa ([SourceKit] Add request to expand macros syntactically) ] @@ -491,4 +499,12 @@ def __init__(self, internal_name, external_name): KIND('StatInstructionCount', 'source.statistic.instruction-count'), KIND('Swift', 'source.lang.swift'), KIND('ObjC', 'source.lang.objc'), + KIND('MacroRoleExpression', 'source.lang.swift.macrorole.expression'), + KIND('MacroRoleDeclaration', 'source.lang.swift.macrorole.declaration'), + KIND('MacroRoleCodeItem', 'source.lang.swift.macrorole.codeitem'), + KIND('MacroRoleAccessor', 'source.lang.swift.macrorole.accessor'), + KIND('MacroRoleMemberAttribute', 'source.lang.swift.macrorole.memberattribute'), + KIND('MacroRoleMember', 'source.lang.swift.macrorole.member'), + KIND('MacroRolePeer', 'source.lang.swift.macrorole.peer'), + KIND('MacroRoleConformance', 'source.lang.swift.macrorole.conformance'), ] From 048435d12b5e811a9eed57a85d6238698d20b254 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Mon, 5 Jun 2023 15:46:26 -0700 Subject: [PATCH 4/9] UID rename (cherry picked from commit 0c931e063ad2acab6178ea8fbd6c5c525be51166) --- .../SourceKit/Macros/syntactic_expansion.swift | 8 ++++---- utils/gyb_sourcekit_support/UIDs.py | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/test/SourceKit/Macros/syntactic_expansion.swift b/test/SourceKit/Macros/syntactic_expansion.swift index db5aa6bbd6305..cae9c3c447a1d 100644 --- a/test/SourceKit/Macros/syntactic_expansion.swift +++ b/test/SourceKit/Macros/syntactic_expansion.swift @@ -15,28 +15,28 @@ struct Generic { //--- DelegatedConformance.json { - key.macro_roles: [source.lang.swift.macrorole.conformance, source.lang.swift.macrorole.member], + key.macro_roles: [source.lang.swift.macro_role.conformance, source.lang.swift.macro_role.member], key.modulename: "MacroDefinition", key.typename: "DelegatedConformanceMacro", } //--- myPropertyWrapper.json { - key.macro_roles: [source.lang.swift.macrorole.accessor, source.lang.swift.macrorole.peer], + key.macro_roles: [source.lang.swift.macro_role.accessor, source.lang.swift.macro_role.peer], key.modulename: "MacroDefinition", key.typename: "PropertyWrapperMacro", } //--- wrapAllProperties.json { - key.macro_roles: [source.lang.swift.macrorole.memberattribute], + key.macro_roles: [source.lang.swift.macro_role.member_attribute], key.modulename: "MacroDefinition", key.typename: "WrapAllProperties", } //--- bitwidthNumberedStructs.json { - key.macro_roles: [source.lang.swift.macrorole.declaration], + key.macro_roles: [source.lang.swift.macro_role.declaration], key.modulename: "MacroDefinition", key.typename: "DefineBitwidthNumberedStructsMacro", } diff --git a/utils/gyb_sourcekit_support/UIDs.py b/utils/gyb_sourcekit_support/UIDs.py index 197e5c651eef5..6100167361bec 100644 --- a/utils/gyb_sourcekit_support/UIDs.py +++ b/utils/gyb_sourcekit_support/UIDs.py @@ -211,7 +211,7 @@ def __init__(self, internal_name, external_name): KEY('BarriersEnabled', 'key.barriers_enabled'), KEY('Expansions', 'key.expansions'), KEY('MacroRoles', 'key.macro_roles'), - KEY('ExpandedMacroReplacements', 'key.expandedmacro_replacements'), + KEY('ExpandedMacroReplacements', 'key.expanded_macro_replacements'), ] @@ -499,12 +499,12 @@ def __init__(self, internal_name, external_name): KIND('StatInstructionCount', 'source.statistic.instruction-count'), KIND('Swift', 'source.lang.swift'), KIND('ObjC', 'source.lang.objc'), - KIND('MacroRoleExpression', 'source.lang.swift.macrorole.expression'), - KIND('MacroRoleDeclaration', 'source.lang.swift.macrorole.declaration'), - KIND('MacroRoleCodeItem', 'source.lang.swift.macrorole.codeitem'), - KIND('MacroRoleAccessor', 'source.lang.swift.macrorole.accessor'), - KIND('MacroRoleMemberAttribute', 'source.lang.swift.macrorole.memberattribute'), - KIND('MacroRoleMember', 'source.lang.swift.macrorole.member'), - KIND('MacroRolePeer', 'source.lang.swift.macrorole.peer'), - KIND('MacroRoleConformance', 'source.lang.swift.macrorole.conformance'), + KIND('MacroRoleExpression', 'source.lang.swift.macro_role.expression'), + KIND('MacroRoleDeclaration', 'source.lang.swift.macro_role.declaration'), + KIND('MacroRoleCodeItem', 'source.lang.swift.macro_role.codeitem'), + KIND('MacroRoleAccessor', 'source.lang.swift.macro_role.accessor'), + KIND('MacroRoleMemberAttribute', 'source.lang.swift.macro_role.member_attribute'), + KIND('MacroRoleMember', 'source.lang.swift.macro_role.member'), + KIND('MacroRolePeer', 'source.lang.swift.macro_role.peer'), + KIND('MacroRoleConformance', 'source.lang.swift.macro_role.conformance'), ] From 89345418c1091b245747ed3ff8a89cb71ace9f02 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Mon, 5 Jun 2023 15:50:53 -0700 Subject: [PATCH 5/9] camelCase (cherry picked from commit 645624129219769fd70301c83b88c14cf18418ad) --- lib/IDETool/SyntacticMacroExpansion.cpp | 18 +++++++-------- .../tools/sourcekitd/lib/Service/Requests.cpp | 22 +++++++++---------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/IDETool/SyntacticMacroExpansion.cpp b/lib/IDETool/SyntacticMacroExpansion.cpp index 03dcf191685b8..ad72187424a6c 100644 --- a/lib/IDETool/SyntacticMacroExpansion.cpp +++ b/lib/IDETool/SyntacticMacroExpansion.cpp @@ -306,18 +306,18 @@ struct ExpansionNode { }; class MacroExpansionFinder : public ASTWalker { SourceManager &SM; - SourceLoc LocToResolve; - llvm::Optional Result; + SourceLoc locToResolve; + llvm::Optional result; bool rangeContainsLocToResolve(SourceRange Range) const { - return SM.rangeContainsTokenLoc(Range, LocToResolve); + return SM.rangeContainsTokenLoc(Range, locToResolve); } public: - MacroExpansionFinder(SourceManager &SM, SourceLoc LocToResolve) - : SM(SM), LocToResolve(LocToResolve) {} + MacroExpansionFinder(SourceManager &SM, SourceLoc locToResolve) + : SM(SM), locToResolve(locToResolve) {} - llvm::Optional getResult() const { return Result; } + llvm::Optional getResult() const { return result; } MacroWalking getMacroWalkingBehavior() const override { return MacroWalking::None; @@ -337,7 +337,7 @@ class MacroExpansionFinder : public ASTWalker { SourceRange nameRange(customAttr->getRangeWithAt().Start, customAttr->getTypeExpr()->getEndLoc()); if (rangeContainsLocToResolve(nameRange)) { - Result = ExpansionNode{customAttr, ASTNode(D)}; + result = ExpansionNode{customAttr, ASTNode(D)}; return Action::Stop(); } } @@ -348,7 +348,7 @@ class MacroExpansionFinder : public ASTWalker { SourceRange nameRange(med->getExpansionInfo()->SigilLoc, med->getMacroNameLoc().getEndLoc()); if (rangeContainsLocToResolve(nameRange)) { - Result = ExpansionNode{nullptr, ASTNode(med)}; + result = ExpansionNode{nullptr, ASTNode(med)}; return Action::Stop(); } } @@ -366,7 +366,7 @@ class MacroExpansionFinder : public ASTWalker { SourceRange nameRange(mee->getExpansionInfo()->SigilLoc, mee->getMacroNameLoc().getEndLoc()); if (rangeContainsLocToResolve(nameRange)) { - Result = ExpansionNode{nullptr, ASTNode(mee)}; + result = ExpansionNode{nullptr, ASTNode(mee)}; return Action::Stop(); } } diff --git a/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp b/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp index d8cec964fb669..aa4a2ec8c234e 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp +++ b/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp @@ -1844,21 +1844,21 @@ handleRequestDiagnostics(const RequestDict &Req, /// /// Sends the results as a 'CategorizedEdits'. Each edit object has /// 'key.buffer_name' that can be used for recursive expansion. If the -/// client founds nested macro expansion in the expanded source, it can send +/// client finds nested macro expansion in the expanded source, it can send /// another request using the buffer name and the source text in the subsequent /// request. static void handleRequestExpandMacroSyntactically( - const RequestDict &Req, SourceKitCancellationToken CancellationToken, - ResponseReceiver Rec) { + const RequestDict &req, SourceKitCancellationToken cancellationToken, + ResponseReceiver rec) { - Optional vfsOptions = getVFSOptions(Req); + Optional vfsOptions = getVFSOptions(req); std::unique_ptr inputBuf = - getInputBufForRequestOrEmitError(Req, vfsOptions, Rec); + getInputBufForRequestOrEmitError(req, vfsOptions, rec); if (!inputBuf) return; SmallVector args; - if (getCompilerArgumentsForRequestOrEmitError(Req, args, Rec)) + if (getCompilerArgumentsForRequestOrEmitError(req, args, rec)) return; // key.expansions: [ @@ -1876,7 +1876,7 @@ static void handleRequestExpandMacroSyntactically( // {key.offset: 9, key.length: 3, key.argindex: 1}]} // ] std::vector expansions; - bool failed = Req.dictionaryArrayApply(KeyExpansions, [&](RequestDict dict) { + bool failed = req.dictionaryArrayApply(KeyExpansions, [&](RequestDict dict) { // offset. int64_t offset; dict.getInt64(KeyOffset, offset, false); @@ -1884,7 +1884,7 @@ static void handleRequestExpandMacroSyntactically( // macro roles. SmallVector macroRoleUIDs; if (dict.getUIDArray(KeyMacroRoles, macroRoleUIDs, false)) { - Rec(createErrorRequestInvalid( + rec(createErrorRequestInvalid( "missing 'key.macro_roles' for expansion specifier")); return true; } @@ -1912,7 +1912,7 @@ static void handleRequestExpandMacroSyntactically( if (auto moduleName = dict.getString(KeyModuleName)) { auto typeName = dict.getString(KeyTypeName); if (!typeName) { - Rec(createErrorRequestInvalid( + rec(createErrorRequestInvalid( "missing 'key.typename' for external macro definition")); return true; } @@ -1929,7 +1929,7 @@ static void handleRequestExpandMacroSyntactically( failed |= dict.getInt64(KeyLength, length, false); failed |= dict.getInt64(KeyArgIndex, paramIndex, false); if (failed) { - Rec(createErrorRequestInvalid( + rec(createErrorRequestInvalid( "macro replacement should have key.offset, key.length, and " "key.argindex")); return true; @@ -1951,7 +1951,7 @@ static void handleRequestExpandMacroSyntactically( LangSupport &Lang = getGlobalContext().getSwiftLangSupport(); Lang.expandMacroSyntactically( inputBuf.get(), args, expansions, - [&](const auto &Result) { Rec(createCategorizedEditsResponse(Result)); }); + [&](const auto &Result) { rec(createCategorizedEditsResponse(Result)); }); } void handleRequestImpl(sourcekitd_object_t ReqObj, From 858ece110d57ca1bc1b99b97d33ebae728195aca Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Mon, 5 Jun 2023 16:29:53 -0700 Subject: [PATCH 6/9] Tweaks (cherry picked from commit 1a4a72aa5fb56e6f31fda56943eb4bc77cd69e72) --- .../swift/IDETool/SyntacticMacroExpansion.h | 2 +- lib/IDETool/SyntacticMacroExpansion.cpp | 70 ++++++++++++------- .../Macros/syntactic_expansion.swift.expected | 16 ++--- 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/include/swift/IDETool/SyntacticMacroExpansion.h b/include/swift/IDETool/SyntacticMacroExpansion.h index 73b3c6fe3abaa..3c922b6d02758 100644 --- a/include/swift/IDETool/SyntacticMacroExpansion.h +++ b/include/swift/IDETool/SyntacticMacroExpansion.h @@ -46,7 +46,7 @@ class SyntacticMacroExpansionInstance { DiagnosticEngine Diags{SourceMgr}; std::unique_ptr Ctx; ModuleDecl *TheModule = nullptr; - llvm::DenseMap MacroDecls; + llvm::StringMap MacroDecls; std::mutex mtx; diff --git a/lib/IDETool/SyntacticMacroExpansion.cpp b/lib/IDETool/SyntacticMacroExpansion.cpp index ad72187424a6c..03ff55c1a94c0 100644 --- a/lib/IDETool/SyntacticMacroExpansion.cpp +++ b/lib/IDETool/SyntacticMacroExpansion.cpp @@ -71,16 +71,6 @@ bool SyntacticMacroExpansionInstance::setup( return true; } - // Setup filesystem. - auto FS = invocation.getSearchPathOptions().makeOverlayFileSystem( - SourceMgr.getFileSystem()); - if (!FS) { - llvm::consumeError(FS.takeError()); - error = "failed to setup overlay filesystem"; - return true; - } - SourceMgr.setFileSystem(FS.get()); - // Setup ASTContext. Ctx.reset(ASTContext::get( invocation.getLangOptions(), invocation.getTypeCheckerOptions(), @@ -132,9 +122,34 @@ MacroDecl *SyntacticMacroExpansionInstance::getSynthesizedMacroDecl( Identifier name, const MacroExpansionSpecifier &expansion) { auto &ctx = getASTContext(); + std::string macroID; + + switch (expansion.macroDefinition.kind) { + case MacroDefinition::Kind::External: { + // '.' + // It's safe to use without 'kind' because 'Expanded' always starts with a + // sigil '#' which can't be valid in a module name. + auto external = expansion.macroDefinition.getExternalMacro(); + macroID += external.moduleName.str(); + macroID += "."; + macroID += external.macroTypeName.str(); + break; + } + case MacroDefinition::Kind::Expanded: { + auto expanded = expansion.macroDefinition.getExpanded(); + macroID += expanded.getExpansionText(); + break; + } + case MacroDefinition::Kind::Builtin: + case MacroDefinition::Kind::Invalid: + case MacroDefinition::Kind::Undefined: + assert(false && "invalid macro definition for syntactic expansion"); + macroID += name.str(); + } + // Reuse cached MacroDecl of the same name if it's already created. MacroDecl *macro; - auto found = MacroDecls.find(name); + auto found = MacroDecls.find(macroID); if (found != MacroDecls.end()) { macro = found->second; } else { @@ -144,7 +159,7 @@ MacroDecl *SyntacticMacroExpansionInstance::getSynthesizedMacroDecl( /*arrowLoc=*/{}, /*resultType=*/nullptr, /*definition=*/nullptr, /*parent=*/TheModule); macro->setImplicit(); - MacroDecls.insert({name, macro}); + MacroDecls.insert({macroID, macro}); } // Add missing role attributes to MacroDecl. @@ -175,17 +190,12 @@ MacroDecl *SyntacticMacroExpansionInstance::getSynthesizedMacroDecl( /// Create a unique name of the expansion. The result is *appended* to \p out. static void addExpansionDiscriminator(SmallString<32> &out, const SourceFile *SF, SourceLoc loc, - MacroDecl *macro, + Optional supplementalLoc = None, Optional role = None) { SourceManager &SM = SF->getASTContext().SourceMgr; - auto lineColumn = SM.getLineAndColumnInBuffer(loc); StableHasher hasher = StableHasher::defaultHasher(); - // Macro name. - hasher.combine(macro->getName().getBaseIdentifier().str()); - hasher.combine(uint8_t{0}); - // Module name. hasher.combine(SF->getParentModule()->getName().str()); hasher.combine(uint8_t{0}); @@ -195,12 +205,20 @@ static void addExpansionDiscriminator(SmallString<32> &out, hasher.combine(llvm::sys::path::filename(SF->getFilename())); hasher.combine(uint8_t{0}); - // Line/column + // Line/column. + auto lineColumn = SM.getLineAndColumnInBuffer(loc); hasher.combine(lineColumn.first); hasher.combine(lineColumn.second); + // Supplemental line/column. + if (supplementalLoc.has_value()) { + auto supLineColumn = SM.getLineAndColumnInBuffer(*supplementalLoc); + hasher.combine(supLineColumn.first); + hasher.combine(supLineColumn.second); + } + // Macro role. - if (role) { + if (role.has_value()) { hasher.combine(*role); } @@ -218,7 +236,7 @@ expandFreestandingMacro(MacroDecl *macro, discriminator.append("macro_"); addExpansionDiscriminator(discriminator, expansion->getDeclContext()->getParentSourceFile(), - expansion->getPoundLoc(), macro); + expansion->getPoundLoc()); expansion->setMacroRef(macro); @@ -243,7 +261,7 @@ expandAttachedMacro(MacroDecl *macro, CustomAttr *attr, Decl *attachedDecl) { discriminator.append("macro_"); addExpansionDiscriminator(discriminator, target->getDeclContext()->getParentSourceFile(), - target->getLoc(), macro, role); + target->getLoc(), attr->getLocation(), role); SourceFile *expandedSource = swift::evaluateAttachedMacro( macro, target, attr, passParent, role, discriminator); @@ -267,13 +285,15 @@ expandAttachedMacro(MacroDecl *macro, CustomAttr *attr, Decl *attachedDecl) { } } if (roles.contains(MacroRole::Member)) { - evaluate(attachedDecl, /*passParent=*/false, MacroRole::Member); + if (isa(attachedDecl)) + evaluate(attachedDecl, /*passParent=*/false, MacroRole::Member); } if (roles.contains(MacroRole::Peer)) { evaluate(attachedDecl, /*passParent=*/false, MacroRole::Peer); } if (roles.contains(MacroRole::Conformance)) { - evaluate(attachedDecl, /*passParent=*/false, MacroRole::Conformance); + if (isa(attachedDecl)) + evaluate(attachedDecl, /*passParent=*/false, MacroRole::Conformance); } return bufferIDs; } @@ -325,7 +345,7 @@ class MacroExpansionFinder : public ASTWalker { PreWalkAction walkToDeclPre(Decl *D) override { // Visit all 'VarDecl' because 'getSourceRangeIncludingAttrs()' doesn't - // include attribute its ranges. + // include its attribute ranges (because attributes are part of PBD.) if (!isa(D) && !rangeContainsLocToResolve(D->getSourceRangeIncludingAttrs())) { return Action::SkipChildren(); diff --git a/test/SourceKit/Macros/syntactic_expansion.swift.expected b/test/SourceKit/Macros/syntactic_expansion.swift.expected index 727a9910f3a1a..a1a03a2172fa6 100644 --- a/test/SourceKit/Macros/syntactic_expansion.swift.expected +++ b/test/SourceKit/Macros/syntactic_expansion.swift.expected @@ -20,7 +20,7 @@ key.endline: 13, key.endcolumn: 1, key.text: "static func requirement() where Element : P {\n Element.requirement()\n}", - key.buffer_name: "macro_185a888f5c6c1a9445a25edf7028dc75.swift" + key.buffer_name: "macro_565056f2d01a68bdc1cc2ee8aa618595.swift" } ], key.category: source.edit.kind.active @@ -33,7 +33,7 @@ key.endline: 13, key.endcolumn: 2, key.text: "extension Generic : P where Element: P {}", - key.buffer_name: "macro_c5de351c406a933f1a952846b34e0639.swift" + key.buffer_name: "macro_a05c1290cb88fd731ba683e5aa86fdb7.swift" } ], key.category: source.edit.kind.active @@ -58,7 +58,7 @@ key.endline: 7, key.endcolumn: 17, key.text: "{\n get {\n _value.wrappedValue\n }\n\n set {\n _value.wrappedValue = newValue\n }\n}", - key.buffer_name: "macro_695ff4226d699e531ba7bb4cc103005a.swift" + key.buffer_name: "macro_f51f41c03929a32f838d53f437ec0a36.swift" } ], key.category: source.edit.kind.active @@ -71,7 +71,7 @@ key.endline: 7, key.endcolumn: 12, key.text: "var _value: MyWrapperThingy", - key.buffer_name: "macro_629ec828bcb8e81543f19a16c7f1ac1d.swift" + key.buffer_name: "macro_4cb3f1a23406c36f4ca3076cfc889d56.swift" } ], key.category: source.edit.kind.active @@ -96,7 +96,7 @@ key.endline: 7, key.endcolumn: 3, key.text: "@Wrapper", - key.buffer_name: "macro_cf98ea58703480a8a577ab40e66fb8e1.swift" + key.buffer_name: "macro_a4c2cd1a73caad3b1eb8f265e55461ee.swift" } ], key.category: source.edit.kind.active @@ -109,7 +109,7 @@ key.endline: 10, key.endcolumn: 3, key.text: "@Wrapper", - key.buffer_name: "macro_3ac1e34ba8396a85fb44db3e6f52cc26.swift" + key.buffer_name: "macro_8bd5a8e09442bf0ec36f456f59a93687.swift" } ], key.category: source.edit.kind.active @@ -121,8 +121,8 @@ key.column: 3, key.endline: 12, key.endcolumn: 35, - key.text: "struct blah8 {\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu_() {\n }\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu0_() {\n }\n}\nstruct blah16 {\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu1_() {\n }\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu2_() {\n }\n}\nstruct blah32 {\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu3_() {\n }\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu4_() {\n }\n}\nstruct blah64 {\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu5_() {\n }\n func macro_373e16cc0bde29e604b8bfcf27292b376methodfMu6_() {\n }\n}", - key.buffer_name: "macro_373e16cc0bde29e604b8bfcf27292b37.swift" + key.text: "struct blah8 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() {\n }\n}\nstruct blah16 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() {\n }\n}\nstruct blah32 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() {\n }\n}\nstruct blah64 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() {\n }\n}", + key.buffer_name: "macro_a01f07de3e9ee8585adf794ccd6dec8c.swift" } ], key.category: source.edit.kind.active From f30dd7839b253395e7a7a2b7ece43dbef2ff3f7f Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Tue, 6 Jun 2023 16:39:30 -0700 Subject: [PATCH 7/9] [SourceKit] Don't return buffer name in syntactic expansions (cherry picked from commit 5877c90e6f0d2614b1a9f47f03cb3ad99b0baa5d) --- include/swift/IDE/Utils.h | 2 +- lib/IDE/Utils.cpp | 10 +++++++-- lib/IDETool/SyntacticMacroExpansion.cpp | 3 ++- lib/Refactoring/Refactoring.cpp | 2 +- .../Macros/syntactic_expansion.swift.expected | 21 +++++++------------ 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/swift/IDE/Utils.h b/include/swift/IDE/Utils.h index 97dc26fa34f9b..a53e9e46c151a 100644 --- a/include/swift/IDE/Utils.h +++ b/include/swift/IDE/Utils.h @@ -580,7 +580,7 @@ class SourceEditConsumer { void remove(SourceManager &SM, CharSourceRange Range); void acceptMacroExpansionBuffer(SourceManager &SM, unsigned bufferID, SourceFile *containingSF, - bool adjustExpansion); + bool adjustExpansion, bool includeBufferName); }; /// This helper stream inserts text into a SourceLoc by calling functions in diff --git a/lib/IDE/Utils.cpp b/lib/IDE/Utils.cpp index 45dd6f5340c22..6db691f0879ee 100644 --- a/lib/IDE/Utils.cpp +++ b/lib/IDE/Utils.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "swift/IDE/Utils.h" +#include "swift/AST/SourceFile.h" #include "swift/Basic/Edit.h" #include "swift/Basic/Platform.h" #include "swift/Basic/SourceManager.h" @@ -659,7 +660,7 @@ adjustMacroExpansionWhitespace(GeneratedSourceInfo::Kind kind, void swift::ide::SourceEditConsumer::acceptMacroExpansionBuffer( SourceManager &SM, unsigned bufferID, SourceFile *containingSF, - bool adjustExpansion) { + bool adjustExpansion, bool includeBufferName) { auto generatedInfo = SM.getGeneratedSourceInfo(bufferID); if (!generatedInfo || generatedInfo->originalSourceRange.isInvalid()) return; @@ -706,9 +707,14 @@ void swift::ide::SourceEditConsumer::acceptMacroExpansionBuffer( originalPath = SM.getIdentifierForBuffer(*originalFile->getBufferID()); } + StringRef bufferName; + if (includeBufferName) { + bufferName = SM.getIdentifierForBuffer(bufferID); + } + accept(SM, {originalPath, originalSourceRange, - SM.getIdentifierForBuffer(bufferID), + bufferName, rewrittenBuffer, {}}); } diff --git a/lib/IDETool/SyntacticMacroExpansion.cpp b/lib/IDETool/SyntacticMacroExpansion.cpp index 03ff55c1a94c0..644739ea0d4a4 100644 --- a/lib/IDETool/SyntacticMacroExpansion.cpp +++ b/lib/IDETool/SyntacticMacroExpansion.cpp @@ -465,7 +465,8 @@ bool SyntacticMacroExpansionInstance::getExpansion( // Send all edits to the consumer. for (unsigned bufferID : bufferIDs) { consumer.acceptMacroExpansionBuffer(SourceMgr, bufferID, SF, - /*adjust=*/false); + /*adjust=*/false, + /*includeBufferName=*/false); } return false; diff --git a/lib/Refactoring/Refactoring.cpp b/lib/Refactoring/Refactoring.cpp index 1082ac6666cf8..5cda1ef0ccf58 100644 --- a/lib/Refactoring/Refactoring.cpp +++ b/lib/Refactoring/Refactoring.cpp @@ -8767,7 +8767,7 @@ static bool expandMacro(SourceManager &SM, ResolvedCursorInfoPtr cursorInfo, // Send all of the rewritten buffer snippets. for (auto bufferID: bufferIDs) { editConsumer.acceptMacroExpansionBuffer(SM, bufferID, containingSF, - adjustExpansion); + adjustExpansion, /*includeBufferName=*/true); } // For an attached macro, remove the custom attribute; it's been fully diff --git a/test/SourceKit/Macros/syntactic_expansion.swift.expected b/test/SourceKit/Macros/syntactic_expansion.swift.expected index a1a03a2172fa6..2863f79271c51 100644 --- a/test/SourceKit/Macros/syntactic_expansion.swift.expected +++ b/test/SourceKit/Macros/syntactic_expansion.swift.expected @@ -19,8 +19,7 @@ key.column: 1, key.endline: 13, key.endcolumn: 1, - key.text: "static func requirement() where Element : P {\n Element.requirement()\n}", - key.buffer_name: "macro_565056f2d01a68bdc1cc2ee8aa618595.swift" + key.text: "static func requirement() where Element : P {\n Element.requirement()\n}" } ], key.category: source.edit.kind.active @@ -32,8 +31,7 @@ key.column: 2, key.endline: 13, key.endcolumn: 2, - key.text: "extension Generic : P where Element: P {}", - key.buffer_name: "macro_a05c1290cb88fd731ba683e5aa86fdb7.swift" + key.text: "extension Generic : P where Element: P {}" } ], key.category: source.edit.kind.active @@ -57,8 +55,7 @@ key.column: 17, key.endline: 7, key.endcolumn: 17, - key.text: "{\n get {\n _value.wrappedValue\n }\n\n set {\n _value.wrappedValue = newValue\n }\n}", - key.buffer_name: "macro_f51f41c03929a32f838d53f437ec0a36.swift" + key.text: "{\n get {\n _value.wrappedValue\n }\n\n set {\n _value.wrappedValue = newValue\n }\n}" } ], key.category: source.edit.kind.active @@ -70,8 +67,7 @@ key.column: 12, key.endline: 7, key.endcolumn: 12, - key.text: "var _value: MyWrapperThingy", - key.buffer_name: "macro_4cb3f1a23406c36f4ca3076cfc889d56.swift" + key.text: "var _value: MyWrapperThingy" } ], key.category: source.edit.kind.active @@ -95,8 +91,7 @@ key.column: 3, key.endline: 7, key.endcolumn: 3, - key.text: "@Wrapper", - key.buffer_name: "macro_a4c2cd1a73caad3b1eb8f265e55461ee.swift" + key.text: "@Wrapper" } ], key.category: source.edit.kind.active @@ -108,8 +103,7 @@ key.column: 3, key.endline: 10, key.endcolumn: 3, - key.text: "@Wrapper", - key.buffer_name: "macro_8bd5a8e09442bf0ec36f456f59a93687.swift" + key.text: "@Wrapper" } ], key.category: source.edit.kind.active @@ -121,8 +115,7 @@ key.column: 3, key.endline: 12, key.endcolumn: 35, - key.text: "struct blah8 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() {\n }\n}\nstruct blah16 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() {\n }\n}\nstruct blah32 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() {\n }\n}\nstruct blah64 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() {\n }\n}", - key.buffer_name: "macro_a01f07de3e9ee8585adf794ccd6dec8c.swift" + key.text: "struct blah8 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() {\n }\n}\nstruct blah16 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() {\n }\n}\nstruct blah32 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() {\n }\n}\nstruct blah64 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() {\n }\n}" } ], key.category: source.edit.kind.active From 40790d70a2151c834b76ef47c175d2d46673ca63 Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 7 Jun 2023 08:16:19 -0700 Subject: [PATCH 8/9] [SourceKit] Syntactic macro expansion disable caching This doesn't support nested expansions for now. So there is not much to reuse. (cherry picked from commit 42435995c80a102035e394bc027f2a542d00a0b7) --- .../swift/IDETool/SyntacticMacroExpansion.h | 10 +- lib/IDETool/SyntacticMacroExpansion.cpp | 17 +- .../Macros/syntactic_expansion.swift | 18 +- .../Macros/syntactic_expansion.swift.expected | 230 ++++++++---------- .../tools/sourcekitd-test/TestOptions.cpp | 2 +- .../tools/sourcekitd-test/sourcekitd-test.cpp | 2 +- .../tools/sourcekitd/lib/Service/Requests.cpp | 8 +- 7 files changed, 131 insertions(+), 156 deletions(-) diff --git a/include/swift/IDETool/SyntacticMacroExpansion.h b/include/swift/IDETool/SyntacticMacroExpansion.h index 3c922b6d02758..85f4e2fe273d2 100644 --- a/include/swift/IDETool/SyntacticMacroExpansion.h +++ b/include/swift/IDETool/SyntacticMacroExpansion.h @@ -39,7 +39,6 @@ struct MacroExpansionSpecifier { /// list of compiler arguments (i.e. 'argHash'), and reused as long as the /// compiler arguments are not changed. class SyntacticMacroExpansionInstance { - const Fingerprint argHash; CompilerInvocation invocation; SourceManager SourceMgr; @@ -48,8 +47,6 @@ class SyntacticMacroExpansionInstance { ModuleDecl *TheModule = nullptr; llvm::StringMap MacroDecls; - std::mutex mtx; - /// Create 'SourceFile' using the buffer. swift::SourceFile *getSourceFile(llvm::MemoryBuffer *inputBuf); @@ -64,13 +61,12 @@ class SyntacticMacroExpansionInstance { SourceEditConsumer &consumer); public: - SyntacticMacroExpansionInstance(Fingerprint argHash) : argHash(argHash) {} + SyntacticMacroExpansionInstance() {} /// Setup the instance with \p args . bool setup(StringRef SwiftExecutablePath, ArrayRef args, std::shared_ptr plugins, std::string &error); - const Fingerprint &getArgHash() const { return argHash; } ASTContext &getASTContext() { return *Ctx; } /// Expand all macros in \p inputBuf and send the edit results to \p consumer. @@ -85,16 +81,12 @@ class SyntacticMacroExpansion { StringRef SwiftExecutablePath; std::shared_ptr Plugins; - /// Cached instance. - std::shared_ptr currentInstance; - public: SyntacticMacroExpansion(StringRef SwiftExecutablePath, std::shared_ptr Plugins) : SwiftExecutablePath(SwiftExecutablePath), Plugins(Plugins) {} /// Get instance configured with the specified compiler arguments. - /// If 'currentInstance' matches with the arguments, just return it. std::shared_ptr getInstance(ArrayRef args, std::string &error); }; diff --git a/lib/IDETool/SyntacticMacroExpansion.cpp b/lib/IDETool/SyntacticMacroExpansion.cpp index 644739ea0d4a4..a07d93fd7c7bf 100644 --- a/lib/IDETool/SyntacticMacroExpansion.cpp +++ b/lib/IDETool/SyntacticMacroExpansion.cpp @@ -26,27 +26,13 @@ using namespace ide; std::shared_ptr SyntacticMacroExpansion::getInstance(ArrayRef args, std::string &error) { - // Compute the signature of the invocation. - StableHasher argHasher = StableHasher::defaultHasher(); - for (auto arg : args) - argHasher.combine(StringRef(arg)); - Fingerprint argHash(std::move(argHasher)); - - // Check if the current instance is usable. - if (auto currentInstance = this->currentInstance) { - if (currentInstance->getArgHash() == argHash) { - return currentInstance; - } - } - // Create and configure a new instance. - auto instance = std::make_shared(argHash); + auto instance = std::make_shared(); bool failed = instance->setup(SwiftExecutablePath, args, Plugins, error); if (failed) return nullptr; - currentInstance = instance; return instance; } @@ -475,7 +461,6 @@ bool SyntacticMacroExpansionInstance::getExpansion( bool SyntacticMacroExpansionInstance::getExpansions( llvm::MemoryBuffer *inputBuf, ArrayRef expansions, SourceEditConsumer &consumer) { - std::scoped_lock lock(mtx); // Create a source file. SourceFile *SF = getSourceFile(inputBuf); diff --git a/test/SourceKit/Macros/syntactic_expansion.swift b/test/SourceKit/Macros/syntactic_expansion.swift index cae9c3c447a1d..17d3f7ae8b032 100644 --- a/test/SourceKit/Macros/syntactic_expansion.swift +++ b/test/SourceKit/Macros/syntactic_expansion.swift @@ -51,7 +51,10 @@ struct Generic { //##-- Prepare the macro plugin. // RUN: %host-build-swift -swift-version 5 -emit-library -o %t/plugins/%target-library-name(MacroDefinition) -module-name=MacroDefinition %S/../../Macros/Inputs/syntax_macro_definitions.swift -g -no-toolchain-stdlib-rpath -// RUN: %sourcekitd-test -req=syntactic-expandmacro \ +// RUN: %sourcekitd-test \ +// RUN: -shell -- echo '### 1' \ +// RUN: == \ +// RUN: -req=syntactic-expandmacro \ // RUN: -req-opts=1:1:%t/DelegatedConformance.json \ // RUN: -req-opts=5:3:%t/myPropertyWrapper.json \ // RUN: -req-opts=2:1:%t/wrapAllProperties.json \ @@ -61,6 +64,19 @@ struct Generic { // RUN: %t/test.swift \ // RUN: -plugin-path %t/plugins -Xfrontend -dump-macro-expansions \ // RUN: -module-name TestModule \ +// RUN: == \ +// RUN: -shell -- echo '### 2' \ +// RUN: == \ +// RUN: -req=syntactic-expandmacro \ +// RUN: -req-opts=12:3:%t/bitwidthNumberedStructs.json \ +// RUN: -req-opts=2:1:%t/wrapAllProperties.json \ +// RUN: -req-opts=5:3:%t/myPropertyWrapper.json \ +// RUN: -req-opts=1:1:%t/DelegatedConformance.json \ +// RUN: %t/test.swift \ +// RUN: -- \ +// RUN: %t/test.swift \ +// RUN: -plugin-path %t/plugins -Xfrontend -dump-macro-expansions \ +// RUN: -module-name TestModule \ // RUN: | tee %t.response // RUN: diff -u %s.expected %t.response diff --git a/test/SourceKit/Macros/syntactic_expansion.swift.expected b/test/SourceKit/Macros/syntactic_expansion.swift.expected index 2863f79271c51..221b99b8f0cab 100644 --- a/test/SourceKit/Macros/syntactic_expansion.swift.expected +++ b/test/SourceKit/Macros/syntactic_expansion.swift.expected @@ -1,124 +1,108 @@ -{ - key.categorizededits: [ - { - key.edits: [ - { - key.line: 1, - key.column: 1, - key.endline: 1, - key.endcolumn: 22, - key.text: "" - } - ], - key.category: source.edit.kind.active - }, - { - key.edits: [ - { - key.line: 13, - key.column: 1, - key.endline: 13, - key.endcolumn: 1, - key.text: "static func requirement() where Element : P {\n Element.requirement()\n}" - } - ], - key.category: source.edit.kind.active - }, - { - key.edits: [ - { - key.line: 13, - key.column: 2, - key.endline: 13, - key.endcolumn: 2, - key.text: "extension Generic : P where Element: P {}" - } - ], - key.category: source.edit.kind.active - }, - { - key.edits: [ - { - key.line: 5, - key.column: 3, - key.endline: 5, - key.endcolumn: 21, - key.text: "" - } - ], - key.category: source.edit.kind.active - }, - { - key.edits: [ - { - key.line: 7, - key.column: 17, - key.endline: 7, - key.endcolumn: 17, - key.text: "{\n get {\n _value.wrappedValue\n }\n\n set {\n _value.wrappedValue = newValue\n }\n}" - } - ], - key.category: source.edit.kind.active - }, - { - key.edits: [ - { - key.line: 7, - key.column: 12, - key.endline: 7, - key.endcolumn: 12, - key.text: "var _value: MyWrapperThingy" - } - ], - key.category: source.edit.kind.active - }, - { - key.edits: [ - { - key.line: 2, - key.column: 1, - key.endline: 2, - key.endcolumn: 19, - key.text: "" - } - ], - key.category: source.edit.kind.active - }, - { - key.edits: [ - { - key.line: 7, - key.column: 3, - key.endline: 7, - key.endcolumn: 3, - key.text: "@Wrapper" - } - ], - key.category: source.edit.kind.active - }, - { - key.edits: [ - { - key.line: 10, - key.column: 3, - key.endline: 10, - key.endcolumn: 3, - key.text: "@Wrapper" - } - ], - key.category: source.edit.kind.active - }, - { - key.edits: [ - { - key.line: 12, - key.column: 3, - key.endline: 12, - key.endcolumn: 35, - key.text: "struct blah8 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() {\n }\n}\nstruct blah16 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() {\n }\n}\nstruct blah32 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() {\n }\n}\nstruct blah64 {\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() {\n }\n func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() {\n }\n}" - } - ], - key.category: source.edit.kind.active - } - ] +### 1 +source.edit.kind.active: + 1:1-1:22 "" +source.edit.kind.active: + 13:1-13:1 "static func requirement() where Element : P { + Element.requirement() +}" +source.edit.kind.active: + 13:2-13:2 "extension Generic : P where Element: P {}" +source.edit.kind.active: + 5:3-5:21 "" +source.edit.kind.active: + 7:17-7:17 "{ + get { + _value.wrappedValue + } + + set { + _value.wrappedValue = newValue + } +}" +source.edit.kind.active: + 7:12-7:12 "var _value: MyWrapperThingy" +source.edit.kind.active: + 2:1-2:19 "" +source.edit.kind.active: + 7:3-7:3 "@Wrapper" +source.edit.kind.active: + 10:3-10:3 "@Wrapper" +source.edit.kind.active: + 12:3-12:35 "struct blah8 { + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() { + } + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() { + } } +struct blah16 { + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() { + } + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() { + } +} +struct blah32 { + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() { + } + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() { + } +} +struct blah64 { + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() { + } + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() { + } +}" +### 2 +source.edit.kind.active: + 12:3-12:35 "struct blah8 { + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() { + } + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() { + } +} +struct blah16 { + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() { + } + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() { + } +} +struct blah32 { + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() { + } + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() { + } +} +struct blah64 { + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() { + } + func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() { + } +}" +source.edit.kind.active: + 2:1-2:19 "" +source.edit.kind.active: + 7:3-7:3 "@Wrapper" +source.edit.kind.active: + 10:3-10:3 "@Wrapper" +source.edit.kind.active: + 5:3-5:21 "" +source.edit.kind.active: + 7:17-7:17 "{ + get { + _value.wrappedValue + } + + set { + _value.wrappedValue = newValue + } +}" +source.edit.kind.active: + 7:12-7:12 "var _value: MyWrapperThingy" +source.edit.kind.active: + 1:1-1:22 "" +source.edit.kind.active: + 13:1-13:1 "static func requirement() where Element : P { + Element.requirement() +}" +source.edit.kind.active: + 13:2-13:2 "extension Generic : P where Element: P {}" diff --git a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp index d138fb3932604..d6f97c5d446ef 100644 --- a/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/TestOptions.cpp @@ -156,7 +156,7 @@ bool TestOptions::parseArgs(llvm::ArrayRef Args) { .Case("syntactic-expandmacro", SourceKitRequest::SyntacticMacroExpansion) #define SEMANTIC_REFACTORING(KIND, NAME, ID) .Case("refactoring." #ID, SourceKitRequest::KIND) #include "swift/Refactoring/RefactoringKinds.def" - .Default(SourceKitRequest::None); + .Default(SourceKitRequest::None); if (Request == SourceKitRequest::None) { llvm::errs() << "error: invalid request '" << InputArg->getValue() diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index 1d9601bbef08e..32f41da359ff9 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -1412,7 +1412,6 @@ static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts, case SourceKitRequest::ConformingMethodList: case SourceKitRequest::DependencyUpdated: case SourceKitRequest::Diagnostics: - case SourceKitRequest::SyntacticMacroExpansion: printRawResponse(Resp); break; case SourceKitRequest::Compile: @@ -1568,6 +1567,7 @@ static bool handleResponse(sourcekitd_response_t Resp, const TestOptions &Opts, #define SEMANTIC_REFACTORING(KIND, NAME, ID) case SourceKitRequest::KIND: #include "swift/Refactoring/RefactoringKinds.def" case SourceKitRequest::SyntacticRename: + case SourceKitRequest::SyntacticMacroExpansion: printSyntacticRenameEdits(Info, llvm::outs()); break; case SourceKitRequest::FindRenameRanges: diff --git a/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp b/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp index aa4a2ec8c234e..5cb98e5e460b0 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp +++ b/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp @@ -1842,11 +1842,9 @@ handleRequestDiagnostics(const RequestDict &Req, /// key.macro_roles: [...] /// } /// -/// Sends the results as a 'CategorizedEdits'. Each edit object has -/// 'key.buffer_name' that can be used for recursive expansion. If the -/// client finds nested macro expansion in the expanded source, it can send -/// another request using the buffer name and the source text in the subsequent -/// request. +/// Sends the results as a 'CategorizedEdits'. +/// Note that, unlike refactoring, each edit doesn't have 'key.buffer_name'. +/// FIXME: Support nested expansion. static void handleRequestExpandMacroSyntactically( const RequestDict &req, SourceKitCancellationToken cancellationToken, ResponseReceiver rec) { From 5e61e929a970a514c0e2243f815aade72d728c7e Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Wed, 7 Jun 2023 12:58:59 -0700 Subject: [PATCH 9/9] Update for review (cherry picked from commit de41f455493fcfee5c318f74b31bedd5ddeff25e) --- .../swift/IDETool/SyntacticMacroExpansion.h | 4 +-- lib/IDETool/SyntacticMacroExpansion.cpp | 18 +++++------ .../Macros/syntactic_expansion.swift.expected | 32 +++++++++---------- .../include/SourceKit/Core/LangSupport.h | 6 +++- .../SwiftSyntacticMacroExpansion.cpp | 2 +- .../tools/sourcekitd-test/sourcekitd-test.cpp | 8 ++--- .../tools/sourcekitd/lib/Service/Requests.cpp | 6 ++-- utils/gyb_sourcekit_support/UIDs.py | 7 ++-- 8 files changed, 41 insertions(+), 42 deletions(-) diff --git a/include/swift/IDETool/SyntacticMacroExpansion.h b/include/swift/IDETool/SyntacticMacroExpansion.h index 85f4e2fe273d2..2f1c079ae9c28 100644 --- a/include/swift/IDETool/SyntacticMacroExpansion.h +++ b/include/swift/IDETool/SyntacticMacroExpansion.h @@ -56,7 +56,7 @@ class SyntacticMacroExpansionInstance { const MacroExpansionSpecifier &expansion); /// Expand single 'expansion' in SF. - bool getExpansion(swift::SourceFile *SF, + void expand(swift::SourceFile *SF, const MacroExpansionSpecifier &expansion, SourceEditConsumer &consumer); @@ -71,7 +71,7 @@ class SyntacticMacroExpansionInstance { /// Expand all macros in \p inputBuf and send the edit results to \p consumer. /// Expansions are specified by \p expansions . - bool getExpansions(llvm::MemoryBuffer *inputBuf, + void expandAll(llvm::MemoryBuffer *inputBuf, ArrayRef expansions, SourceEditConsumer &consumer); }; diff --git a/lib/IDETool/SyntacticMacroExpansion.cpp b/lib/IDETool/SyntacticMacroExpansion.cpp index a07d93fd7c7bf..afcffa672721b 100644 --- a/lib/IDETool/SyntacticMacroExpansion.cpp +++ b/lib/IDETool/SyntacticMacroExpansion.cpp @@ -219,7 +219,7 @@ expandFreestandingMacro(MacroDecl *macro, std::vector bufferIDs; SmallString<32> discriminator; - discriminator.append("macro_"); + discriminator.append("__syntactic_macro_"); addExpansionDiscriminator(discriminator, expansion->getDeclContext()->getParentSourceFile(), expansion->getPoundLoc()); @@ -293,7 +293,9 @@ static Identifier getCustomAttrName(ASTContext &ctx, const CustomAttr *attr) { } // If the attribute is not an identifier type, create an identifier with its - // textual representation. + // textual representation. This is *not* expected to be reachable. + // The only case is like `@Foo?` where the client should not send the + // expansion request on this in the first place. SmallString<32> name; llvm::raw_svector_ostream OS(name); tyR->print(OS); @@ -406,7 +408,7 @@ class MacroExpansionFinder : public ASTWalker { }; } // namespace -bool SyntacticMacroExpansionInstance::getExpansion( +void SyntacticMacroExpansionInstance::expand( SourceFile *SF, const MacroExpansionSpecifier &expansion, SourceEditConsumer &consumer) { @@ -417,7 +419,7 @@ bool SyntacticMacroExpansionInstance::getExpansion( SF->walk(expansionFinder); auto expansionNode = expansionFinder.getResult(); if (!expansionNode) - return true; + return; // Expand the macro. std::vector bufferIDs; @@ -454,20 +456,16 @@ bool SyntacticMacroExpansionInstance::getExpansion( /*adjust=*/false, /*includeBufferName=*/false); } - - return false; } -bool SyntacticMacroExpansionInstance::getExpansions( +void SyntacticMacroExpansionInstance::expandAll( llvm::MemoryBuffer *inputBuf, ArrayRef expansions, SourceEditConsumer &consumer) { // Create a source file. SourceFile *SF = getSourceFile(inputBuf); - bool hasError = false; for (const auto &expansion : expansions) { - hasError |= getExpansion(SF, expansion, consumer); + expand(SF, expansion, consumer); } - return hasError; } diff --git a/test/SourceKit/Macros/syntactic_expansion.swift.expected b/test/SourceKit/Macros/syntactic_expansion.swift.expected index 221b99b8f0cab..90a0ccf5b0f65 100644 --- a/test/SourceKit/Macros/syntactic_expansion.swift.expected +++ b/test/SourceKit/Macros/syntactic_expansion.swift.expected @@ -29,53 +29,53 @@ source.edit.kind.active: 10:3-10:3 "@Wrapper" source.edit.kind.active: 12:3-12:35 "struct blah8 { - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() { } - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() { } } struct blah16 { - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() { } - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() { } } struct blah32 { - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() { } - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() { } } struct blah64 { - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() { } - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() { } }" ### 2 source.edit.kind.active: 12:3-12:35 "struct blah8 { - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu_() { } - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu0_() { } } struct blah16 { - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu1_() { } - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu2_() { } } struct blah32 { - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu3_() { } - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu4_() { } } struct blah64 { - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu5_() { } - func macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() { + func __syntactic_macro_a01f07de3e9ee8585adf794ccd6dec8c6methodfMu6_() { } }" source.edit.kind.active: diff --git a/tools/SourceKit/include/SourceKit/Core/LangSupport.h b/tools/SourceKit/include/SourceKit/Core/LangSupport.h index 4f1d28b53ab3e..4203393ca53b2 100644 --- a/tools/SourceKit/include/SourceKit/Core/LangSupport.h +++ b/tools/SourceKit/include/SourceKit/Core/LangSupport.h @@ -244,6 +244,9 @@ struct MacroExpansionInfo { }; // See swift::ExpandedMacroDefinition. struct ExpandedMacroDefinition { + // 'Replacement.range' references some part of code in 'expansionText'. + // 'expansionText' will be replaced by the 'parameterIndex'-th argument of + // the macro. struct Replacement { RawCharSourceRange range; unsigned parameterIndex; @@ -257,7 +260,8 @@ struct MacroExpansionInfo { : expansionText(expansionText), replacements(){}; }; - // Offset of the macro expansion syntax (i.e. attribute or #) + // Offset of the macro expansion syntax (i.e. attribute or #) from + // the start of the source file. unsigned offset; // Macro roles. diff --git a/tools/SourceKit/lib/SwiftLang/SwiftSyntacticMacroExpansion.cpp b/tools/SourceKit/lib/SwiftLang/SwiftSyntacticMacroExpansion.cpp index b17c258415d4f..170ca176bc7f0 100644 --- a/tools/SourceKit/lib/SwiftLang/SwiftSyntacticMacroExpansion.cpp +++ b/tools/SourceKit/lib/SwiftLang/SwiftSyntacticMacroExpansion.cpp @@ -89,6 +89,6 @@ void SwiftLangSupport::expandMacroSyntactically( } RequestRefactoringEditConsumer consumer(receiver); - (void)instance->getExpansions(inputBuf, expansions, consumer); + instance->expandAll(inputBuf, expansions, consumer); // consumer automatically send the results on destruction. } diff --git a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp index 32f41da359ff9..84f4ae8482940 100644 --- a/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp +++ b/tools/SourceKit/tools/sourcekitd-test/sourcekitd-test.cpp @@ -422,10 +422,10 @@ static bool readPopularAPIList(StringRef filename, /// where {path} is a path to a JSON file that has macro roles and definition. /// {line} and {column} is resolved to 'offset' using \p inputBuf . static bool setSyntacticMacroExpansions(sourcekitd_object_t req, - TestOptions &Opts, + TestOptions &opts, llvm::MemoryBuffer *inputBuf) { SmallVector expansions; - for (std::string &opt : Opts.RequestOptions) { + for (std::string &opt : opts.RequestOptions) { SmallVector args; StringRef(opt).split(args, ":"); unsigned line, column; @@ -437,7 +437,7 @@ static bool setSyntacticMacroExpansions(sourcekitd_object_t req, } unsigned offset = resolveFromLineCol(line, column, inputBuf); - auto Buffer = getBufferForFilename(args[2], Opts.VFSFiles)->getBuffer(); + auto Buffer = getBufferForFilename(args[2], opts.VFSFiles)->getBuffer(); char *Err = nullptr; auto expansion = sourcekitd_request_create_from_yaml(Buffer.data(), &Err); if (!expansion) { @@ -1150,7 +1150,7 @@ static int handleTestInvocation(TestOptions Opts, TestOptions &InitOpts) { case SourceKitRequest::SyntacticMacroExpansion: sourcekitd_request_dictionary_set_uid(Req, KeyRequest, - RequestExpandMacroSyntactically); + RequestSyntacticMacroExpansion); setSyntacticMacroExpansions(Req, Opts, SourceBuf.get()); break; } diff --git a/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp b/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp index 5cb98e5e460b0..d0ad86c6ed704 100644 --- a/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp +++ b/tools/SourceKit/tools/sourcekitd/lib/Service/Requests.cpp @@ -1845,7 +1845,7 @@ handleRequestDiagnostics(const RequestDict &Req, /// Sends the results as a 'CategorizedEdits'. /// Note that, unlike refactoring, each edit doesn't have 'key.buffer_name'. /// FIXME: Support nested expansion. -static void handleRequestExpandMacroSyntactically( +static void handleRequestSyntacticMacroExpansion( const RequestDict &req, SourceKitCancellationToken cancellationToken, ResponseReceiver rec) { @@ -2055,8 +2055,8 @@ void handleRequestImpl(sourcekitd_object_t ReqObj, HANDLE_REQUEST(RequestRelatedIdents, handleRequestRelatedIdents) HANDLE_REQUEST(RequestActiveRegions, handleRequestActiveRegions) HANDLE_REQUEST(RequestDiagnostics, handleRequestDiagnostics) - HANDLE_REQUEST(RequestExpandMacroSyntactically, - handleRequestExpandMacroSyntactically) + HANDLE_REQUEST(RequestSyntacticMacroExpansion, + handleRequestSyntacticMacroExpansion) { SmallString<64> ErrBuf; diff --git a/utils/gyb_sourcekit_support/UIDs.py b/utils/gyb_sourcekit_support/UIDs.py index 6100167361bec..a660222a15665 100644 --- a/utils/gyb_sourcekit_support/UIDs.py +++ b/utils/gyb_sourcekit_support/UIDs.py @@ -276,12 +276,9 @@ def __init__(self, internal_name, external_name): REQUEST('Diagnostics', 'source.request.diagnostics'), REQUEST('Compile', 'source.request.compile'), REQUEST('CompileClose', 'source.request.compile.close'), -<<<<<<< HEAD REQUEST('EnableRequestBarriers', 'source.request.enable_request_barriers'), -======= - REQUEST('ExpandMacroSyntactically', - 'source.request.expand.macro.syntactically'), ->>>>>>> 309c87b56fa ([SourceKit] Add request to expand macros syntactically) + REQUEST('SyntacticMacroExpansion', + 'source.request.syntactic_macro_expansion'), ]