mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
IDE functionality needs some internal type checking logics, e.g. checking whether an extension is applicable to a concrete type. We used to directly expose an header from sema called IDETypeChecking.h so that IDE functionalities could invoke these APIs. The goal of the commit and following commits is to expose evaluator requests instead of directly exposing function entry points from sema so that we could later move IDETypeChecking.h to libIDE and implement these functions by internally evaluating these requests.
911 lines
32 KiB
C++
911 lines
32 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/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;
|
|
|
|
static ModuleDecl *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 ModuleDecl *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;
|
|
|
|
// 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 = 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) override {
|
|
unsigned StartOffset = OS.tell();
|
|
Info.References.emplace_back(TD, StartOffset, Name.str().size());
|
|
StreamPrinter::printTypeRef(T, 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;
|
|
}
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
static bool makeParserAST(CompilerInstance &CI, StringRef Text,
|
|
CompilerInvocation Invocation) {
|
|
Invocation.getFrontendOptions().InputsAndOutputs.clearInputs();
|
|
Invocation.setModuleName("main");
|
|
Invocation.setInputKind(InputFileKind::Swift);
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> Buf;
|
|
Buf = llvm::MemoryBuffer::getMemBuffer(Text, "<module-interface>");
|
|
Invocation.getFrontendOptions().InputsAndOutputs.addInput(
|
|
InputFile(Buf.get()->getBufferIdentifier(), false, 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,
|
|
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 = 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::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());
|
|
}
|
|
printSubmoduleInterface(Mod, SplitModuleName,
|
|
Group.hasValue() ? llvm::makeArrayRef(Group.getValue()) : ArrayRef<StringRef>(),
|
|
TraversalOptions,
|
|
Printer, Options,
|
|
Group.hasValue() && SynthesizedExtensions);
|
|
|
|
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::printModuleInterface();
|
|
|
|
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,
|
|
CompilerInvocation Invocation,
|
|
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,
|
|
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;
|
|
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.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 = getModuleByFullName(Ctx, 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;
|
|
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 = getModuleByFullName(Ctx, 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 = 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;
|
|
}
|
|
|
|
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));
|
|
}
|