Files
swift-mirror/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp
Egor Zhdan a610bcd752 [cxx-interop] Avoid trying to generate module interfaces twice
This reverts most of 72050c5385, which led to decreased performance of jump-to-definition.

Instead of re-attempting to generate a module interface with C++ interop enabled, Swift should rely on the IDE to pass the correct `-cxx-interoperability-mode=` value to SourceKit.

rdar://149061322
2025-09-22 18:48:20 +01:00

986 lines
35 KiB
C++

//===--- SwiftEditorInterfaceGen.cpp --------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 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 "SwiftInterfaceGenContext.h"
#include "SwiftASTManager.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/ASTWalker.h"
#include "swift/Basic/Version.h"
#include "swift/Frontend/Frontend.h"
#include "swift/Frontend/PrintingDiagnosticConsumer.h"
#include "swift/IDE/ModuleInterfacePrinting.h"
#include "swift/IDE/SyntaxModel.h"
#include "swift/IDETool/CompilerInvocation.h"
#include "swift/Parse/ParseVersion.h"
#include "swift/Strings.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/ConvertUTF.h"
using namespace SourceKit;
using namespace swift;
using namespace ide;
class SwiftInterfaceGenContext::Implementation {
public:
struct TextRange {
unsigned Offset;
unsigned Length;
};
struct TextReference {
/// The declaration from the module.
const ValueDecl *Dcl = nullptr;
const ModuleEntity Mod;
TextRange Range;
TextReference(const ValueDecl *D, unsigned Offset, unsigned Length)
: Dcl(D), Mod(), Range{Offset, Length} {}
TextReference(const ModuleEntity Mod, unsigned Offset, unsigned Length)
: Mod(Mod), Range{Offset, Length} {}
};
struct TextDecl {
/// The declaration from the module.
const Decl *Dcl = nullptr;
/// The range in the interface source.
TextRange Range;
/// The USR, if the declaration has one
StringRef USR;
TextDecl(const Decl *D, TextRange Range)
: Dcl(D), Range(Range) {}
TextDecl() = default;
};
struct SourceTextInfo {
std::string Text;
std::vector<TextReference> References;
std::vector<TextDecl> Decls;
/// Do not clear the map or erase elements,
/// without keeping the Decls vector in sync
llvm::StringMap<TextDecl> USRMap;
};
// Hold an AstUnit so that the Decl* we have are always valid.
ASTUnitRef AstUnit;
std::string DocumentName;
bool IsModule = false;
std::string ModuleOrHeaderName;
CompilerInvocation Invocation;
PrintingDiagnosticConsumer DiagConsumer;
CompilerInstance Instance;
ModuleDecl *Mod = nullptr;
SourceTextInfo Info;
// This is the non-typechecked AST for the generated interface source.
CompilerInstance TextCI;
// Synchronize access to the embedded compiler instance (if we don't have an
// ASTUnit).
WorkQueue Queue{WorkQueue::Dequeuing::Serial,
"sourcekit.swift.InterfaceGenContext"};
};
typedef SwiftInterfaceGenContext::Implementation::TextRange TextRange;
typedef SwiftInterfaceGenContext::Implementation::TextReference TextReference;
typedef SwiftInterfaceGenContext::Implementation::TextDecl TextDecl;
typedef SwiftInterfaceGenContext::Implementation::SourceTextInfo SourceTextInfo;
namespace {
class AnnotatingPrinter : public StreamPrinter {
SourceTextInfo &Info;
struct DeclUSR {
const Decl *Dcl = nullptr;
std::string USR;
DeclUSR(const Decl *D, StringRef USR) : Dcl(D), USR(USR) {}
};
std::vector<DeclUSR> DeclUSRs;
// For members of a synthesized extension, we should append the USR of the
// synthesize target to the original USR.
std::string TargetUSR;
public:
AnnotatingPrinter(SourceTextInfo &Info, llvm::raw_ostream &OS)
: StreamPrinter(OS), Info(Info) { }
~AnnotatingPrinter() override {
assert(DeclUSRs.empty() && "unmatched printDeclLoc call ?");
}
void
printSynthesizedExtensionPre(const ExtensionDecl *ED,
TypeOrExtensionDecl Target,
std::optional<BracketOptions> Bracket) override {
// When we start print a synthesized extension, record the target's USR.
llvm::SmallString<64> Buf;
llvm::raw_svector_ostream OS(Buf);
auto TargetNTD = Target.getBaseNominal();
if (!SwiftLangSupport::printUSR(TargetNTD, OS)) {
TargetUSR = std::string(OS.str());
}
}
void printSynthesizedExtensionPost(
const ExtensionDecl *ED, TypeOrExtensionDecl Target,
std::optional<BracketOptions> Bracket) override {
// When we leave a synthesized extension, clear target's USR.
TargetUSR = "";
}
void printDeclLoc(const Decl *D) override {
unsigned LocOffset = OS.tell();
TextDecl Entry(D, TextRange{LocOffset, 0});
Info.Decls.emplace_back(Entry);
if (auto VD = dyn_cast<ValueDecl>(D)) {
// Only record non-local USRs.
if (D->getDeclContext()->getLocalContext())
return;
llvm::SmallString<64> Buf;
llvm::raw_svector_ostream OS(Buf);
if (!SwiftLangSupport::printUSR(VD, OS)) {
// Append target's USR if this is a member of a synthesized extension.
if (!TargetUSR.empty()) {
OS << LangSupport::SynthesizedUSRSeparator;
OS << TargetUSR;
}
StringRef USR = OS.str();
DeclUSRs.emplace_back(VD, USR);
auto iterator = Info.USRMap.insert_or_assign(USR, Entry).first;
// Set the USR in the declarations to the key in the USRMap, because the
// lifetime of that matches/exceeds the lifetime of Decls. String keys
// in the StringMap are heap allocated and only get destroyed on
// explicit erase() or clear() calls, or on destructor calls (the
// Programmer's Manual description itself also states that StringMap
// "only ever copies a string if a value is inserted").
// Thus this never results in a dangling reference, as the USRMap is
// never cleared and no elements are erased in its lifetime.
Info.Decls.back().USR = iterator->getKey();
}
}
}
void printDeclNameOrSignatureEndLoc(const Decl *D) override {
unsigned Offset = OS.tell();
if (!Info.Decls.empty() && Info.Decls.back().Dcl == D) {
TextDecl &Entry = Info.Decls.back();
Entry.Range.Length = Offset - Entry.Range.Offset;
}
if (!DeclUSRs.empty() && DeclUSRs.back().Dcl == D) {
TextDecl &Entry = Info.USRMap[DeclUSRs.back().USR];
assert(Entry.Dcl == D);
Entry.Range.Length = Offset - Entry.Range.Offset;
DeclUSRs.pop_back();
}
}
void printTypeRef(
Type T, const TypeDecl *TD, Identifier Name,
PrintNameContext NameContext = PrintNameContext::Normal) override {
unsigned StartOffset = OS.tell();
Info.References.emplace_back(TD, StartOffset, Name.str().size());
StreamPrinter::printTypeRef(T, TD, Name, NameContext);
}
void printModuleRef(ModuleEntity Mod, Identifier Name) override {
unsigned StartOffset = OS.tell();
Info.References.emplace_back(Mod, StartOffset, Name.str().size());
StreamPrinter::printModuleRef(Mod, Name);
}
};
class DocSyntaxWalker : public SyntaxModelWalker {
SourceManager &SM;
unsigned BufferID;
EditorConsumer &Consumer;
public:
DocSyntaxWalker(SourceManager &SM, unsigned BufferID,
EditorConsumer &Consumer)
: SM(SM), BufferID(BufferID), Consumer(Consumer) {}
bool walkToNodePre(SyntaxNode Node) override {
unsigned Offset = SM.getLocOffsetInBuffer(Node.Range.getStart(), BufferID);
unsigned Length = Node.Range.getByteLength();
UIdent UID = SwiftLangSupport::getUIDForSyntaxNodeKind(Node.Kind);
if (UID.isValid())
Consumer.handleSyntaxMap(Offset, Length, UID);
return true;
}
};
} // end anonymous namespace
static bool makeParserAST(CompilerInstance &CI, StringRef Text,
CompilerInvocation Invocation) {
Invocation.getFrontendOptions().InputsAndOutputs.clearInputs();
Invocation.setModuleName("main");
Invocation.getLangOptions().DisablePoundIfEvaluation = true;
std::unique_ptr<llvm::MemoryBuffer> Buf;
Buf = llvm::MemoryBuffer::getMemBuffer(Text, "<module-interface>");
Invocation.getFrontendOptions().InputsAndOutputs.addInput(
InputFile(Buf.get()->getBufferIdentifier(), /*isPrimary*/false, Buf.get(),
file_types::TY_Swift));
std::string InstanceSetupError;
return CI.setup(Invocation, InstanceSetupError);
}
static void reportSyntacticAnnotations(CompilerInstance &CI,
EditorConsumer &Consumer) {
auto SF = dyn_cast<SourceFile>(CI.getMainModule()->getFiles()[0]);
SyntaxModelContext SyntaxContext(*SF);
DocSyntaxWalker SyntaxWalker(CI.getSourceMgr(), SF->getBufferID(),
Consumer);
SyntaxContext.walk(SyntaxWalker);
}
static void reportDocumentStructure(CompilerInstance &CI,
EditorConsumer &Consumer) {
auto SF = dyn_cast<SourceFile>(CI.getMainModule()->getFiles()[0]);
SwiftEditorDocument::reportDocumentStructure(*SF, Consumer);
}
static void reportSemanticAnnotations(const SourceTextInfo &IFaceInfo,
EditorConsumer &Consumer) {
for (auto &Ref : IFaceInfo.References) {
UIdent Kind;
bool IsSystem;
if (Ref.Mod) {
Kind = SwiftLangSupport::getUIDForModuleRef();
IsSystem = Ref.Mod.isNonUserModule();
} else if (Ref.Dcl) {
Kind = SwiftLangSupport::getUIDForDecl(Ref.Dcl, /*IsRef=*/true);
IsSystem = Ref.Dcl->getModuleContext()->isNonUserModule();
}
if (Kind.isInvalid())
continue;
unsigned Offset = Ref.Range.Offset;
unsigned Length = Ref.Range.Length;
Consumer.handleSemanticAnnotation(Offset, Length, Kind, IsSystem);
}
}
/// Create the declarations array (sourcekitd::DeclarationsArrayBuilder) from
/// the SourceTextInfo about declarations
static void reportDeclarations(const SourceTextInfo &IFaceInfo,
EditorConsumer &Consumer) {
for (auto &Dcl : IFaceInfo.Decls) {
if (!Dcl.Dcl)
continue;
UIdent Kind = SwiftLangSupport::getUIDForDecl(Dcl.Dcl);
if (Kind.isInvalid())
continue;
Consumer.handleDeclaration(Dcl.Range.Offset, Dcl.Range.Length, Kind,
Dcl.USR);
}
}
namespace {
/// A diagnostic consumer that picks up module loading errors.
class ModuleLoadingErrorConsumer final : public DiagnosticConsumer {
llvm::SmallVector<std::string, 2> DiagMessages;
void handleDiagnostic(SourceManager &SM,
const DiagnosticInfo &Info) override {
// Only record errors for now. In the future it might be useful to pick up
// some notes, but some notes are just noise.
if (Info.Kind != DiagnosticKind::Error)
return;
std::string Message;
{
llvm::raw_string_ostream Out(Message);
DiagnosticEngine::formatDiagnosticText(Out, Info.FormatString,
Info.FormatArgs);
}
// We're only interested in the first and last errors. For a clang module
// failure, the first error will be the reason why the module failed to
// load, and the last error will be a generic "could not build Obj-C module"
// error. For a Swift module, we'll typically only emit one error.
//
// NOTE: Currently when loading transitive dependencies for a Swift module,
// we'll only diagnose the root failure, and not record the error for the
// top-level module failure, as we stop emitting errors after a fatal error
// has been recorded. This is currently fine for our use case though, as
// we already include the top-level module name in the error we hand back.
if (DiagMessages.size() < 2) {
DiagMessages.emplace_back(std::move(Message));
} else {
DiagMessages.back() = std::move(Message);
}
}
public:
ArrayRef<std::string> getDiagMessages() { return DiagMessages; }
};
} // end anonymous namespace
static bool getModuleInterfaceInfo(
ASTContext &Ctx, StringRef ModuleName, std::optional<StringRef> Group,
SwiftInterfaceGenContext::Implementation &Impl, std::string &ErrMsg,
bool SynthesizedExtensions, std::optional<StringRef> InterestedUSR) {
ModuleDecl *&Mod = Impl.Mod;
SourceTextInfo &Info = Impl.Info;
if (ModuleName.empty()) {
ErrMsg = "Module name is empty";
return true;
}
// Get the (sub)module to generate, recording the errors emitted.
ModuleLoadingErrorConsumer DiagConsumer;
{
DiagnosticConsumerRAII R(Ctx.Diags, DiagConsumer);
Mod = Ctx.getModuleByName(ModuleName);
}
// Check to see if we either couldn't find the module, or we failed to load
// it, and report an error message back that includes the diagnostics we
// collected, which should help pinpoint what the issue was. Note we do this
// even if `Mod` is null, as the clang importer currently returns nullptr
// when a module fails to load, and there may be interesting errors to
// collect there.
// Note that us failing here also means the caller may retry with e.g C++
// interoperability enabled.
if (!Mod || Mod->failedToLoad()) {
llvm::raw_string_ostream OS(ErrMsg);
OS << "Could not load module: ";
OS << ModuleName;
auto ModuleErrs = DiagConsumer.getDiagMessages();
if (!ModuleErrs.empty()) {
// We print the errors in reverse, as they are typically emitted in
// a bottom-up manner by module loading, and a top-down presentation
// makes more sense.
OS << " (";
llvm::interleaveComma(llvm::reverse(ModuleErrs), OS);
OS << ")";
}
return true;
}
PrintOptions Options = PrintOptions::printModuleInterface(
Ctx.TypeCheckerOpts.PrintFullConvention);
if (Mod->findUnderlyingClangModule()) {
if (Ctx.LangOpts.EnableCXXInterop) {
// Show unavailable C++ APIs.
Options.SkipUnavailable = false;
// Skip over inline namespaces.
Options.SkipInlineCXXNamespace = true;
}
}
// Skip submodules but include any exported modules that have the same public
// module name as this module.
ModuleTraversalOptions TraversalOptions =
ModuleTraversal::VisitMatchingExported;
SmallString<128> Text;
llvm::raw_svector_ostream OS(Text);
AnnotatingPrinter Printer(Info, OS);
if (!Group && InterestedUSR) {
Group = findGroupNameForUSR(Mod, InterestedUSR.value());
}
printModuleInterface(Mod,
Group.has_value() ? llvm::ArrayRef(Group.value())
: ArrayRef<StringRef>(),
TraversalOptions, Printer, Options,
Group.has_value() && SynthesizedExtensions);
Info.Text = std::string(OS.str());
return false;
}
static bool getHeaderInterfaceInfo(ASTContext &Ctx,
StringRef HeaderName,
SourceTextInfo &Info,
std::string &ErrMsg) {
if (HeaderName.empty()) {
ErrMsg = "Header name is empty";
return true;
}
PrintOptions Options = PrintOptions::printModuleInterface(
Ctx.TypeCheckerOpts.PrintFullConvention);
SmallString<128> Text;
llvm::raw_svector_ostream OS(Text);
AnnotatingPrinter Printer(Info, OS);
printHeaderInterface(HeaderName, Ctx, Printer, Options);
Info.Text = std::string(OS.str());
return false;
}
SwiftInterfaceGenContextRef
SwiftInterfaceGenContext::createForSwiftSource(StringRef DocumentName,
StringRef SourceFileName,
ASTUnitRef AstUnit,
CompilerInvocation Invocation,
std::string &ErrMsg) {
SwiftInterfaceGenContextRef IFaceGenCtx{ new SwiftInterfaceGenContext() };
IFaceGenCtx->Impl.DocumentName = DocumentName.str();
IFaceGenCtx->Impl.IsModule = true;
IFaceGenCtx->Impl.ModuleOrHeaderName = SourceFileName.str();
IFaceGenCtx->Impl.AstUnit = AstUnit;
PrintOptions Options = PrintOptions::printSwiftFileInterface(
Invocation.getFrontendOptions().PrintFullConvention);
SmallString<128> Text;
llvm::raw_svector_ostream OS(Text);
AnnotatingPrinter Printer(IFaceGenCtx->Impl.Info, OS);
printSwiftSourceInterface(AstUnit->getPrimarySourceFile(), Printer, Options);
IFaceGenCtx->Impl.Info.Text = std::string(OS.str());
if (makeParserAST(IFaceGenCtx->Impl.TextCI, IFaceGenCtx->Impl.Info.Text,
Invocation)) {
ErrMsg = "Error during syntactic parsing";
return nullptr;
}
return IFaceGenCtx;
}
SwiftInterfaceGenContextRef SwiftInterfaceGenContext::create(
StringRef DocumentName, bool IsModule, StringRef ModuleOrHeaderName,
std::optional<StringRef> Group, CompilerInvocation Invocation,
std::string &ErrMsg, bool SynthesizedExtensions,
std::optional<StringRef> InterestedUSR) {
SwiftInterfaceGenContextRef IFaceGenCtx{ new SwiftInterfaceGenContext() };
IFaceGenCtx->Impl.DocumentName = DocumentName.str();
IFaceGenCtx->Impl.IsModule = IsModule;
IFaceGenCtx->Impl.ModuleOrHeaderName = ModuleOrHeaderName.str();
IFaceGenCtx->Impl.Invocation = Invocation;
CompilerInstance &CI = IFaceGenCtx->Impl.Instance;
// Display diagnostics to stderr.
CI.addDiagnosticConsumer(&IFaceGenCtx->Impl.DiagConsumer);
Invocation.getFrontendOptions().InputsAndOutputs.clearInputs();
if (CI.setup(Invocation, ErrMsg)) {
return nullptr;
}
ASTContext &Ctx = CI.getASTContext();
CloseClangModuleFiles scopedCloseFiles(*Ctx.getClangModuleLoader());
// Load implicit imports so that Clang importer can use them.
for (auto unloadedImport :
CI.getMainModule()->getImplicitImportInfo().AdditionalUnloadedImports) {
(void)Ctx.getModule(unloadedImport.module.getModulePath());
}
if (IsModule) {
if (getModuleInterfaceInfo(Ctx, ModuleOrHeaderName, Group, IFaceGenCtx->Impl,
ErrMsg, SynthesizedExtensions, InterestedUSR))
return nullptr;
} else {
auto &FEOpts = Invocation.getFrontendOptions();
if (FEOpts.ImplicitObjCHeaderPath.empty()) {
ErrMsg = "Implicit ObjC header path is empty";
return nullptr;
}
auto &Importer = static_cast<ClangImporter &>(*Ctx.getClangModuleLoader());
Importer.importBridgingHeader(FEOpts.ImplicitObjCHeaderPath,
CI.getMainModule(),
/*diagLoc=*/{},
/*trackParsedSymbols=*/true);
if (getHeaderInterfaceInfo(Ctx, ModuleOrHeaderName,
IFaceGenCtx->Impl.Info, ErrMsg))
return nullptr;
}
if (makeParserAST(IFaceGenCtx->Impl.TextCI, IFaceGenCtx->Impl.Info.Text,
Invocation)) {
ErrMsg = "Error during syntactic parsing";
return nullptr;
}
return IFaceGenCtx;
}
SwiftInterfaceGenContextRef
SwiftInterfaceGenContext::createForTypeInterface(CompilerInvocation Invocation,
StringRef TypeUSR,
std::string &ErrorMsg) {
SwiftInterfaceGenContextRef IFaceGenCtx{ new SwiftInterfaceGenContext() };
IFaceGenCtx->Impl.IsModule = false;
IFaceGenCtx->Impl.ModuleOrHeaderName = TypeUSR.str();
IFaceGenCtx->Impl.Invocation = Invocation;
CompilerInstance &CI = IFaceGenCtx->Impl.Instance;
SourceTextInfo &Info = IFaceGenCtx->Impl.Info;
// Display diagnostics to stderr.
CI.addDiagnosticConsumer(&IFaceGenCtx->Impl.DiagConsumer);
if (CI.setup(Invocation, ErrorMsg)) {
return nullptr;
}
registerIDETypeCheckRequestFunctions(CI.getASTContext().evaluator);
CI.performSema();
ASTContext &Ctx = CI.getASTContext();
CloseClangModuleFiles scopedCloseFiles(*Ctx.getClangModuleLoader());
// Load standard library so that Clang importer can use it.
auto *Stdlib = Ctx.getModuleByIdentifier(Ctx.StdlibModuleName);
if (!Stdlib) {
ErrorMsg = "Could not load the stdlib module";
return nullptr;
}
auto *Module = CI.getMainModule();
if (!Module) {
ErrorMsg = "Could not load the main module";
return nullptr;
}
SmallString<128> Text;
llvm::raw_svector_ostream OS(Text);
AnnotatingPrinter Printer(Info, OS);
if (ide::printTypeInterface(Module, TypeUSR, Printer,
IFaceGenCtx->Impl.DocumentName, ErrorMsg))
return nullptr;
IFaceGenCtx->Impl.Info.Text = std::string(OS.str());
if (makeParserAST(IFaceGenCtx->Impl.TextCI, IFaceGenCtx->Impl.Info.Text,
Invocation)) {
ErrorMsg = "Error during syntactic parsing";
return nullptr;
}
return IFaceGenCtx;
}
SwiftInterfaceGenContext::SwiftInterfaceGenContext()
: Impl(*new Implementation) {
}
SwiftInterfaceGenContext::~SwiftInterfaceGenContext() {
delete &Impl;
}
StringRef SwiftInterfaceGenContext::getDocumentName() const {
return Impl.DocumentName;
}
StringRef SwiftInterfaceGenContext::getModuleOrHeaderName() const {
return Impl.ModuleOrHeaderName;
}
bool SwiftInterfaceGenContext::isModule() const {
return Impl.IsModule;
}
ModuleDecl *SwiftInterfaceGenContext::getModuleDecl() const {
return Impl.Mod;
}
bool SwiftInterfaceGenContext::matches(StringRef ModuleName,
const swift::CompilerInvocation &Invok) {
if (!Impl.IsModule)
return false;
if (ModuleName != Impl.ModuleOrHeaderName)
return false;
if (Invok.getTargetTriple() != Impl.Invocation.getTargetTriple())
return false;
if (ModuleName == STDLIB_NAME)
return true;
if (Invok.getSDKPath() != Impl.Invocation.getSDKPath())
return false;
if (Impl.Mod->isNonUserModule())
return true;
const SearchPathOptions &SPOpts = Invok.getSearchPathOptions();
const SearchPathOptions &ImplSPOpts = Impl.Invocation.getSearchPathOptions();
if (SPOpts.getImportSearchPaths() != ImplSPOpts.getImportSearchPaths())
return false;
if (SPOpts.getFrameworkSearchPaths() != ImplSPOpts.getFrameworkSearchPaths())
return false;
if (Invok.getClangImporterOptions().ExtraArgs !=
Impl.Invocation.getClangImporterOptions().ExtraArgs)
return false;
return true;
}
void SwiftInterfaceGenContext::reportEditorInfo(EditorConsumer &Consumer) const {
Consumer.handleSourceText(Impl.Info.Text);
reportSyntacticAnnotations(Impl.TextCI, Consumer);
reportDocumentStructure(Impl.TextCI, Consumer);
reportSemanticAnnotations(Impl.Info, Consumer);
reportDeclarations(Impl.Info, Consumer);
Consumer.finished();
}
void SwiftInterfaceGenContext::accessASTAsync(std::function<void()> Fn) {
if (Impl.AstUnit) {
Impl.AstUnit->performAsync(std::move(Fn));
} else {
Impl.Queue.dispatch(std::move(Fn));
}
}
SwiftInterfaceGenContext::ResolvedEntity
SwiftInterfaceGenContext::resolveEntityForOffset(unsigned Offset) const {
// Search among the references.
{
auto Pos = std::upper_bound(Impl.Info.References.begin(),
Impl.Info.References.end(),
Offset,
[&](unsigned Offset, const TextReference &RHS) -> bool {
return Offset < RHS.Range.Offset+RHS.Range.Length;
});
if (Pos != Impl.Info.References.end() && Pos->Range.Offset <= Offset) {
if (Pos->Mod)
return ResolvedEntity(Pos->Mod, true);
else
return ResolvedEntity(Pos->Dcl, true);
}
}
SourceManager &SM = Impl.TextCI.getSourceMgr();
auto SF = dyn_cast<SourceFile>(Impl.TextCI.getMainModule()->getFiles()[0]);
unsigned BufferID = SF->getBufferID();
SourceLoc Loc = Lexer::getLocForStartOfToken(SM, BufferID, Offset);
Offset = SM.getLocOffsetInBuffer(Loc, BufferID);
// Search among the declarations.
{
auto Pos = std::lower_bound(Impl.Info.Decls.begin(),
Impl.Info.Decls.end(),
Offset,
[&](const TextDecl &LHS, unsigned Offset) -> bool {
return LHS.Range.Offset < Offset;
});
if (Pos != Impl.Info.Decls.end() && Pos->Range.Offset == Offset)
return ResolvedEntity(dyn_cast<ValueDecl>(Pos->Dcl), false);
}
return ResolvedEntity();
}
std::optional<std::pair<unsigned, unsigned>>
SwiftInterfaceGenContext::findUSRRange(StringRef USR) const {
auto Pos = Impl.Info.USRMap.find(USR);
if (Pos == Impl.Info.USRMap.end())
return std::nullopt;
return std::make_pair(Pos->getValue().Range.Offset,
Pos->getValue().Range.Length);
}
void SwiftInterfaceGenContext::applyTo(
swift::CompilerInvocation &CompInvok) const {
CompInvok = Impl.Invocation;
}
SwiftInterfaceGenContextRef SwiftInterfaceGenMap::get(StringRef Name) const {
llvm::sys::ScopedLock L(Mtx);
auto It = IFaceGens.find(Name);
if (It == IFaceGens.end())
return nullptr;
return It->second;
}
void SwiftInterfaceGenMap::set(StringRef Name,
SwiftInterfaceGenContextRef IFaceGen) {
llvm::sys::ScopedLock L(Mtx);
IFaceGens[Name] = IFaceGen;
}
bool SwiftInterfaceGenMap::remove(StringRef Name) {
llvm::sys::ScopedLock L(Mtx);
return IFaceGens.erase(Name);
}
SwiftInterfaceGenContextRef
SwiftInterfaceGenMap::find(StringRef ModuleName,
const CompilerInvocation &Invok) {
llvm::sys::ScopedLock L(Mtx);
for (auto &Entry : IFaceGens) {
if (Entry.getValue()->matches(ModuleName, Invok))
return Entry.getValue();
}
return nullptr;
}
//===----------------------------------------------------------------------===//
// EditorOpenTypeInterface
//===----------------------------------------------------------------------===//
void SwiftLangSupport::editorOpenTypeInterface(EditorConsumer &Consumer,
ArrayRef<const char *> Args,
StringRef TypeUSR) {
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
CompilerInvocation Invocation;
std::string Error;
if (getASTManager()->initCompilerInvocation(
Invocation, Args, FrontendOptions::ActionType::Typecheck,
CI.getDiags(), StringRef(), Error)) {
Consumer.handleRequestError(Error.c_str());
return;
}
Invocation.getClangImporterOptions().ImportForwardDeclarations = true;
std::string ErrMsg;
auto IFaceGenRef = SwiftInterfaceGenContext::createForTypeInterface(
Invocation,
TypeUSR,
ErrMsg);
if (!IFaceGenRef) {
Consumer.handleRequestError(ErrMsg.c_str());
return;
}
IFaceGenRef->reportEditorInfo(Consumer);
// reportEditorInfo requires exclusive access to the AST, so don't add this
// to the service cache until it has returned.
IFaceGenContexts.set(TypeUSR, IFaceGenRef);
}
//===----------------------------------------------------------------------===//
// EditorOpenInterface
//===----------------------------------------------------------------------===//
void SwiftLangSupport::editorOpenInterface(
EditorConsumer &Consumer, StringRef Name, StringRef ModuleName,
std::optional<StringRef> Group, ArrayRef<const char *> Args,
bool SynthesizedExtensions, std::optional<StringRef> InterestedUSR) {
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
CompilerInvocation Invocation;
std::string Error;
if (getASTManager()->initCompilerInvocationNoInputs(
Invocation, Args, FrontendOptions::ActionType::Typecheck,
CI.getDiags(), Error)) {
Consumer.handleRequestError(Error.c_str());
return;
}
Invocation.getClangImporterOptions().ImportForwardDeclarations = true;
std::string ErrMsg;
auto IFaceGenRef = SwiftInterfaceGenContext::create(Name,
/*IsModule=*/true,
ModuleName,
Group,
Invocation,
ErrMsg,
SynthesizedExtensions,
InterestedUSR);
if (!IFaceGenRef) {
Consumer.handleRequestError(ErrMsg.c_str());
return;
}
IFaceGenRef->reportEditorInfo(Consumer);
// reportEditorInfo requires exclusive access to the AST, so don't add this
// to the service cache until it has returned.
IFaceGenContexts.set(Name, IFaceGenRef);
}
class PrimaryFileInterfaceConsumer : public SwiftASTConsumer {
std::string Name;
std::string SourceFileName;
SwiftInterfaceGenMap &Contexts;
std::shared_ptr<EditorConsumer> Consumer;
SwiftInvocationRef ASTInvok;
public:
PrimaryFileInterfaceConsumer(StringRef Name, StringRef SourceFileName,
SwiftInterfaceGenMap &Contexts,
std::shared_ptr<EditorConsumer> Consumer,
SwiftInvocationRef ASTInvok) :
Name(Name), SourceFileName(SourceFileName), Contexts(Contexts),
Consumer(Consumer), ASTInvok(ASTInvok) {}
void failed(StringRef Error) override {
Consumer->handleRequestError(Error.data());
}
void handlePrimaryAST(ASTUnitRef AstUnit) override {
CompilerInvocation CompInvok;
ASTInvok->applyTo(CompInvok);
std::string Error;
auto IFaceGenRef = SwiftInterfaceGenContext::createForSwiftSource(Name,
SourceFileName, AstUnit, CompInvok, Error);
if (!Error.empty())
Consumer->handleRequestError(Error.data());
Contexts.set(Name, IFaceGenRef);
IFaceGenRef->reportEditorInfo(*Consumer);
}
};
void SwiftLangSupport::editorOpenSwiftSourceInterface(
StringRef Name, StringRef SourceName, ArrayRef<const char *> Args,
bool CancelOnSubsequentRequest,
SourceKitCancellationToken CancellationToken,
std::shared_ptr<EditorConsumer> Consumer) {
std::string Error;
auto Invocation = ASTMgr->getTypecheckInvocation(Args, SourceName, Error);
if (!Invocation) {
Consumer->handleRequestError(Error.c_str());
return;
}
auto AstConsumer = std::make_shared<PrimaryFileInterfaceConsumer>(Name,
SourceName, IFaceGenContexts, Consumer, Invocation);
static const char OncePerASTToken = 0;
const void *Once = CancelOnSubsequentRequest ? &OncePerASTToken : nullptr;
getASTManager()->processASTAsync(Invocation, AstConsumer, Once,
CancellationToken,
llvm::vfs::getRealFileSystem());
}
void SwiftLangSupport::editorOpenHeaderInterface(EditorConsumer &Consumer,
StringRef Name,
StringRef HeaderName,
ArrayRef<const char *> Args,
bool UsingSwiftArgs,
bool SynthesizedExtensions,
StringRef swiftVersion) {
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
CompilerInvocation Invocation;
std::string Error;
auto SwiftArgs = UsingSwiftArgs ? Args : ArrayRef<const char *>();
if (getASTManager()->initCompilerInvocationNoInputs(
Invocation, SwiftArgs, FrontendOptions::ActionType::Typecheck,
CI.getDiags(), Error)) {
Consumer.handleRequestError(Error.c_str());
return;
}
if (!UsingSwiftArgs && initInvocationByClangArguments(Args, Invocation, Error)) {
Consumer.handleRequestError(Error.c_str());
return;
}
Invocation.getClangImporterOptions().ImportForwardDeclarations = true;
if (!swiftVersion.empty()) {
auto swiftVer =
VersionParser::parseVersionString(swiftVersion, SourceLoc(), nullptr);
if (swiftVer.has_value())
Invocation.getLangOptions().EffectiveLanguageVersion =
swiftVer.value();
}
auto IFaceGenRef = SwiftInterfaceGenContext::create(
Name,
/*IsModule=*/false, HeaderName, std::nullopt, Invocation, Error,
SynthesizedExtensions, std::nullopt);
if (!IFaceGenRef) {
Consumer.handleRequestError(Error.c_str());
return;
}
IFaceGenRef->reportEditorInfo(Consumer);
// reportEditorInfo requires exclusive access to the AST, so don't add this
// to the service cache until it has returned.
IFaceGenContexts.set(Name, IFaceGenRef);
}
void SwiftLangSupport::findInterfaceDocument(StringRef ModuleName,
ArrayRef<const char *> Args,
std::function<void(const RequestResult<InterfaceDocInfo> &)> Receiver) {
InterfaceDocInfo Info;
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
CompilerInvocation Invocation;
std::string Error;
if (getASTManager()->initCompilerInvocation(
Invocation, Args, FrontendOptions::ActionType::Typecheck,
CI.getDiags(), StringRef(), Error)) {
return Receiver(RequestResult<InterfaceDocInfo>::fromError(Error));
}
if (auto IFaceGenRef = IFaceGenContexts.find(ModuleName, Invocation))
Info.ModuleInterfaceName = IFaceGenRef->getDocumentName();
SmallString<128> Buf;
SmallVector<std::pair<unsigned, unsigned>, 16> ArgOffs;
auto addArgPair = [&](StringRef Arg, StringRef Val) {
assert(!Arg.empty());
if (Val.empty())
return;
unsigned ArgBegin = Buf.size();
Buf += Arg;
unsigned ArgEnd = Buf.size();
unsigned ValBegin = Buf.size();
Buf += Val;
unsigned ValEnd = Buf.size();
ArgOffs.push_back(std::make_pair(ArgBegin, ArgEnd));
ArgOffs.push_back(std::make_pair(ValBegin, ValEnd));
};
auto addSingleArg = [&](StringRef Arg) {
assert(!Arg.empty());
unsigned ArgBegin = Buf.size();
Buf += Arg;
unsigned ArgEnd = Buf.size();
ArgOffs.push_back(std::make_pair(ArgBegin, ArgEnd));
};
addArgPair("-target", Invocation.getTargetTriple());
const auto &SPOpts = Invocation.getSearchPathOptions();
addArgPair("-sdk", SPOpts.getSDKPath());
for (const auto &FramePath : SPOpts.getFrameworkSearchPaths()) {
if (FramePath.IsSystem)
addArgPair("-Fsystem", FramePath.Path);
else
addArgPair("-F", FramePath.Path);
}
for (const auto &Path : SPOpts.getImportSearchPaths()) {
if (Path.IsSystem)
addArgPair("-Isystem", Path.Path);
else
addArgPair("-I", Path.Path);
}
const auto &ClangOpts = Invocation.getClangImporterOptions();
addArgPair("-module-cache-path", ClangOpts.ModuleCachePath);
for (auto &ExtraArg : ClangOpts.ExtraArgs)
addArgPair("-Xcc", ExtraArg);
if (Invocation.getFrontendOptions().ImportUnderlyingModule)
addSingleArg("-import-underlying-module");
addArgPair("-import-objc-header",
Invocation.getFrontendOptions().ImplicitObjCHeaderPath);
SmallVector<StringRef, 16> NewArgs;
for (auto Pair : ArgOffs) {
NewArgs.push_back(StringRef(Buf.begin()+Pair.first, Pair.second-Pair.first));
}
Info.CompilerArgs = NewArgs;
return Receiver(RequestResult<InterfaceDocInfo>::fromResult(Info));
}