Files
swift-mirror/tools/SourceKit/lib/SwiftLang/SwiftEditorInterfaceGen.cpp
Xi Ge ae60159816 [ModulePrint] Add the initial implementation for printing synthesized extensions.
For a concrete type, members from its conforming protocols' extensions can be hard
to manually surface. In this commit, when printing Swift modules, we start to replicate these
extensions and synthesize them as if they are the concrete type's native extensions.

Credit to Doug for suggesting this practice.
2016-02-02 14:53:21 -08:00

768 lines
25 KiB
C++

//===--- SwiftEditorInterfaceGen.cpp --------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://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/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;
Module *Mod = nullptr;
SourceTextInfo Info;
// This is the non-typechecked AST for the generated interface source.
CompilerInstance TextCI;
};
typedef SwiftInterfaceGenContext::Implementation::TextRange TextRange;
typedef SwiftInterfaceGenContext::Implementation::TextReference TextReference;
typedef SwiftInterfaceGenContext::Implementation::TextDecl TextDecl;
typedef SwiftInterfaceGenContext::Implementation::SourceTextInfo SourceTextInfo;
static Module *getModuleByFullName(ASTContext &Ctx, StringRef ModuleName) {
SmallVector<std::pair<Identifier, SourceLoc>, 4>
AccessPath;
while (!ModuleName.empty()) {
StringRef SubModuleName;
std::tie(SubModuleName, ModuleName) = ModuleName.split('.');
AccessPath.push_back({ Ctx.getIdentifier(SubModuleName), SourceLoc() });
}
return Ctx.getModule(AccessPath);
}
static Module *getModuleByFullName(ASTContext &Ctx, Identifier ModuleName) {
return Ctx.getModule(std::make_pair(ModuleName, SourceLoc()));
}
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;
public:
AnnotatingPrinter(SourceTextInfo &Info, llvm::raw_ostream &OS)
: StreamPrinter(OS), Info(Info) { }
~AnnotatingPrinter() {
assert(DeclUSRs.empty() && "unmatched printDeclLoc call ?");
}
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)) {
StringRef USR = OS.str();
Info.USRMap[USR] = Entry;
DeclUSRs.emplace_back(VD, USR);
}
}
}
void printDeclNameEndLoc(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(const TypeDecl *TD, Identifier Name) override {
unsigned StartOffset = OS.tell();
Info.References.emplace_back(TD, StartOffset, Name.str().size());
StreamPrinter::printTypeRef(TD, Name);
}
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;
}
};
}
static bool makeParserAST(CompilerInstance &CI, StringRef Text) {
CompilerInvocation Invocation;
Invocation.setModuleName("main");
Invocation.setInputKind(InputFileKind::IFK_Swift);
std::unique_ptr<llvm::MemoryBuffer> Buf;
Buf = llvm::MemoryBuffer::getMemBuffer(Text, "<module-interface>");
Invocation.addInputBuffer(Buf.get());
if (CI.setup(Invocation))
return true;
CI.performParseOnly();
return false;
}
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,
SwiftInterfaceGenContext::Implementation &Impl,
std::string &ErrMsg) {
Module *&Mod = Impl.Mod;
SourceTextInfo &Info = Impl.Info;
if (ModuleName.empty()) {
ErrMsg = "Module name is empty";
return true;
}
// Get the (sub)module to generate.
Mod = getModuleByFullName(Ctx, ModuleName);
if (!Mod) {
ErrMsg = "Could not load module: ";
ErrMsg += ModuleName;
return true;
}
std::vector<StringRef> SplitModuleName;
while (!ModuleName.empty()) {
StringRef SubModuleName;
std::tie(SubModuleName, ModuleName) = ModuleName.split('.');
SplitModuleName.push_back(SubModuleName);
}
assert(!SplitModuleName.empty());
// FIXME: If this is a submodule, get its top-level module, which will be the
// DeclContext for all of its Decls since we don't have first-class submodules.
if (SplitModuleName.size() > 1) {
Mod = getModuleByFullName(Ctx, SplitModuleName[0]);
if (!Mod) {
ErrMsg = "Could not load module: ";
ErrMsg += ModuleName;
return true;
}
}
PrintOptions Options = PrintOptions::printInterface();
ModuleTraversalOptions TraversalOptions = None; // Don't print submodules.
SmallString<128> Text;
llvm::raw_svector_ostream OS(Text);
AnnotatingPrinter Printer(Info, OS);
printSubmoduleInterface(Mod, SplitModuleName,
TraversalOptions,
Printer, Options, false);
Info.Text = 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::printInterface();
SmallString<128> Text;
llvm::raw_svector_ostream OS(Text);
AnnotatingPrinter Printer(Info, OS);
printHeaderInterface(HeaderName, Ctx, Printer, Options);
Info.Text = OS.str();
return false;
}
SwiftInterfaceGenContextRef
SwiftInterfaceGenContext::createForSwiftSource(StringRef DocumentName,
StringRef SourceFileName,
ASTUnitRef AstUnit,
std::string &ErrMsg) {
SwiftInterfaceGenContextRef IFaceGenCtx{ new SwiftInterfaceGenContext() };
IFaceGenCtx->Impl.DocumentName = DocumentName;
IFaceGenCtx->Impl.IsModule = true;
IFaceGenCtx->Impl.ModuleOrHeaderName = SourceFileName;
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 = OS.str();
if (makeParserAST(IFaceGenCtx->Impl.TextCI, IFaceGenCtx->Impl.Info.Text)) {
ErrMsg = "Error during syntactic parsing";
return nullptr;
}
return IFaceGenCtx;
}
SwiftInterfaceGenContextRef
SwiftInterfaceGenContext::create(StringRef DocumentName,
bool IsModule,
StringRef ModuleOrHeaderName,
CompilerInvocation Invocation,
std::string &ErrMsg) {
SwiftInterfaceGenContextRef IFaceGenCtx{ new SwiftInterfaceGenContext() };
IFaceGenCtx->Impl.DocumentName = DocumentName;
IFaceGenCtx->Impl.IsModule = IsModule;
IFaceGenCtx->Impl.ModuleOrHeaderName = ModuleOrHeaderName;
IFaceGenCtx->Impl.Invocation = Invocation;
CompilerInstance &CI = IFaceGenCtx->Impl.Instance;
// Display diagnostics to stderr.
CI.addDiagnosticConsumer(&IFaceGenCtx->Impl.DiagConsumer);
Invocation.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 = getModuleByFullName(Ctx, Ctx.StdlibModuleName);
if (!Stdlib) {
ErrMsg = "Could not load the stdlib module";
return nullptr;
}
if (IsModule) {
if (getModuleInterfaceInfo(Ctx, ModuleOrHeaderName, IFaceGenCtx->Impl,
ErrMsg))
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)) {
ErrMsg = "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;
}
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();
}
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;
}
//===----------------------------------------------------------------------===//
// EditorOpenInterface
//===----------------------------------------------------------------------===//
void SwiftLangSupport::editorOpenInterface(EditorConsumer &Consumer,
StringRef Name,
StringRef ModuleName,
ArrayRef<const char *> Args) {
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;
}
trace::TracedOperation TracedOp;
if (trace::enabled()) {
trace::SwiftInvocation SwiftArgs;
SwiftArgs.Args.Args.assign(Args.begin(), Args.end());
// NOTE: do not use primary file
// NOTE: do not use files
TracedOp.start(trace::OperationKind::OpenInterface, SwiftArgs,
{std::make_pair("Name", Name),
std::make_pair("ModuleName", ModuleName)});
}
Invocation.getClangImporterOptions().ImportForwardDeclarations = true;
std::string ErrMsg;
auto IFaceGenRef = SwiftInterfaceGenContext::create(Name,
/*IsModule=*/true,
ModuleName,
Invocation,
ErrMsg);
if (!IFaceGenRef) {
Consumer.handleRequestError(ErrMsg.c_str());
return;
}
IFaceGenContexts.set(Name, IFaceGenRef);
IFaceGenRef->reportEditorInfo(Consumer);
}
class PrimaryFileInterfaceConsumer : public SwiftASTConsumer {
std::string Name;
std::string SourceFileName;
SwiftInterfaceGenMap &Contexts;
std::shared_ptr<EditorConsumer> Consumer;
public:
PrimaryFileInterfaceConsumer(StringRef Name, StringRef SourceFileName,
SwiftInterfaceGenMap &Contexts,
std::shared_ptr<EditorConsumer> Consumer) :
Name(Name), SourceFileName(SourceFileName), Contexts(Contexts),
Consumer(Consumer) {}
void failed(StringRef Error) override {
Consumer->handleRequestError(Error.data());
}
void handlePrimaryAST(ASTUnitRef AstUnit) override {
std::string Error;
auto IFaceGenRef = SwiftInterfaceGenContext::createForSwiftSource(Name,
SourceFileName, AstUnit, 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;
}
trace::TracedOperation TracedOp;
if (trace::enabled()) {
trace::SwiftInvocation SwiftArgs;
SwiftArgs.Args.Args.assign(Args.begin(), Args.end());
// NOTE: do not use primary file
// NOTE: do not use files
TracedOp.start(trace::OperationKind::OpenInterface, SwiftArgs,
{std::make_pair("Name", Name),
std::make_pair("SourceName", SourceName)});
}
auto AstConsumer = std::make_shared<PrimaryFileInterfaceConsumer>(Name,
SourceName, IFaceGenContexts, Consumer);
static const char OncePerASTToken = 0;
getASTManager().processASTAsync(Invocation, AstConsumer, &OncePerASTToken);
}
void SwiftLangSupport::editorOpenHeaderInterface(EditorConsumer &Consumer,
StringRef Name,
StringRef HeaderName,
ArrayRef<const char *> Args) {
CompilerInstance CI;
// Display diagnostics to stderr.
PrintingDiagnosticConsumer PrintDiags;
CI.addDiagnosticConsumer(&PrintDiags);
CompilerInvocation Invocation;
std::string Error;
if (getASTManager().initCompilerInvocation(Invocation, llvm::None, CI.getDiags(),
StringRef(), Error)) {
Consumer.handleRequestError(Error.c_str());
return;
}
if (initInvocationByClangArguments(Args, Invocation, Error)) {
Consumer.handleRequestError(Error.c_str());
return;
}
trace::TracedOperation TracedOp;
if (trace::enabled()) {
trace::SwiftInvocation SwiftArgs;
SwiftArgs.Args.Args.assign(Args.begin(), Args.end());
// NOTE: do not use primary file
// NOTE: do not use files
TracedOp.start(trace::OperationKind::OpenHeaderInterface, SwiftArgs,
{std::make_pair("Name", Name),
std::make_pair("HeaderName", HeaderName)});
}
Invocation.getClangImporterOptions().ImportForwardDeclarations = true;
auto IFaceGenRef = SwiftInterfaceGenContext::create(Name,
/*IsModule=*/false,
HeaderName,
Invocation,
Error);
if (!IFaceGenRef) {
Consumer.handleRequestError(Error.c_str());
return;
}
IFaceGenContexts.set(Name, IFaceGenRef);
IFaceGenRef->reportEditorInfo(Consumer);
}
void SwiftLangSupport::findInterfaceDocument(StringRef ModuleName,
ArrayRef<const char *> Args,
std::function<void(const 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)) {
Info.Error = Error;
return Receiver(Info);
}
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 &Path : SPOpts.FrameworkSearchPaths)
addArgPair("-F", 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(Info);
}