blob: b60d42d32c27b6eb0ceedb3024508914c81d17bc [file] [log] [blame]
//===--- 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/IDE/Utils.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;
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;
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,
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,
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();
Info.USRMap[USR] = Entry;
DeclUSRs.emplace_back(VD, USR);
}
}
}
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));
return CI.setup(Invocation);
}
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.isSystemModule();
} else if (Ref.Dcl) {
Kind = SwiftLangSupport::getUIDForDecl(Ref.Dcl, /*IsRef=*/true);
IsSystem = Ref.Dcl->getModuleContext()->isSystemModule();
}
if (Kind.isInvalid())
continue;
unsigned Offset = Ref.Range.Offset;
unsigned Length = Ref.Range.Length;
Consumer.handleSemanticAnnotation(Offset, Length, Kind, IsSystem);
}
}
static bool getModuleInterfaceInfo(ASTContext &Ctx,
StringRef ModuleName,
Optional<StringRef> Group,
SwiftInterfaceGenContext::Implementation &Impl,
std::string &ErrMsg,
bool SynthesizedExtensions,
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.
Mod = Ctx.getModuleByName(ModuleName);
if (!Mod) {
ErrMsg = "Could not load module: ";
ErrMsg += ModuleName;
return true;
}
PrintOptions Options = PrintOptions::printModuleInterface();
ModuleTraversalOptions TraversalOptions = None; // Don't print submodules.
SmallString<128> Text;
llvm::raw_svector_ostream OS(Text);
AnnotatingPrinter Printer(Info, OS);
if (!Group && InterestedUSR) {
Group = findGroupNameForUSR(Mod, InterestedUSR.getValue());
}
printModuleInterface(Mod, Group.hasValue()
? llvm::makeArrayRef(Group.getValue())
: ArrayRef<StringRef>(),
TraversalOptions, Printer, Options,
Group.hasValue() && 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();
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();
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,
Optional<StringRef> Group,
CompilerInvocation Invocation,
std::string &ErrMsg,
bool SynthesizedExtensions,
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 = "Error during invocation setup";
return nullptr;
}
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) {
ErrMsg = "Could not load the stdlib module";
return nullptr;
}
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 = "Error during invocation setup";
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->isSystemModule())
return true;
const SearchPathOptions &SPOpts = Invok.getSearchPathOptions();
const SearchPathOptions &ImplSPOpts = Impl.Invocation.getSearchPathOptions();
if (SPOpts.ImportSearchPaths != ImplSPOpts.ImportSearchPaths)
return false;
if (SPOpts.FrameworkSearchPaths != ImplSPOpts.FrameworkSearchPaths)
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);
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();
}
llvm::Optional<std::pair<unsigned, unsigned>>
SwiftInterfaceGenContext::findUSRRange(StringRef USR) const {
auto Pos = Impl.Info.USRMap.find(USR);
if (Pos == Impl.Info.USRMap.end())
return None;
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, 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,
Optional<StringRef> Group,
ArrayRef<const char *> Args,
bool SynthesizedExtensions,
Optional<StringRef> InterestedUSR) {
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
CompilerInvocation Invocation;
std::string Error;
if (getASTManager()->initCompilerInvocationNoInputs(Invocation, Args,
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,
std::shared_ptr<EditorConsumer> Consumer) {
std::string Error;
auto Invocation = ASTMgr->getInvocation(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;
getASTManager()->processASTAsync(Invocation, AstConsumer, &OncePerASTToken,
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;
ArrayRef<const char *> SwiftArgs = UsingSwiftArgs ? Args : llvm::None;
if (getASTManager()->initCompilerInvocationNoInputs(Invocation, SwiftArgs,
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 = version::Version::parseVersionString(swiftVersion,
SourceLoc(), nullptr);
if (swiftVer.hasValue())
Invocation.getLangOptions().EffectiveLanguageVersion =
swiftVer.getValue();
}
auto IFaceGenRef = SwiftInterfaceGenContext::create(Name,
/*IsModule=*/false,
HeaderName,
None,
Invocation,
Error,
SynthesizedExtensions,
None);
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, 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.SDKPath);
for (auto &FramePath : SPOpts.FrameworkSearchPaths) {
if (FramePath.IsSystem)
addArgPair("-Fsystem", FramePath.Path);
else
addArgPair("-F", FramePath.Path);
}
for (auto &Path : SPOpts.ImportSearchPaths)
addArgPair("-I", 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));
}