//===--- SwiftLangSupport.h - -----------------------------------*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// #ifndef LLVM_SOURCEKIT_LIB_SWIFTLANG_SWIFTLANGSUPPORT_H #define LLVM_SOURCEKIT_LIB_SWIFTLANG_SWIFTLANGSUPPORT_H #include "CodeCompletion.h" #include "SwiftInterfaceGenContext.h" #include "SourceKit/Core/LangSupport.h" #include "SourceKit/Support/Concurrency.h" #include "SourceKit/Support/Statistic.h" #include "SourceKit/Support/ThreadSafeRefCntPtr.h" #include "SourceKit/Support/Tracing.h" #include "swift/Basic/ThreadSafeRefCounted.h" #include "swift/IDE/Formatting.h" #include "swift/IDE/Refactoring.h" #include "swift/Index/IndexSymbol.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/Mutex.h" #include #include namespace swift { class ASTContext; class ClangModuleLoader; class CompilerInstance; class CompilerInvocation; class Decl; class Type; class AbstractStorageDecl; class SourceFile; class SILOptions; class ValueDecl; class GenericSignature; enum class AccessorKind; namespace syntax { class SourceFileSyntax; } namespace ide { class CodeCompletionCache; class OnDiskCodeCompletionCache; class SourceEditConsumer; enum class CodeCompletionDeclKind; enum class SyntaxNodeKind : uint8_t; enum class SyntaxStructureKind : uint8_t; enum class SyntaxStructureElementKind : uint8_t; enum class RangeKind : int8_t; class CodeCompletionConsumer; enum class NameKind { ObjC, Swift, }; } } namespace SourceKit { class ImmutableTextSnapshot; typedef RefPtr ImmutableTextSnapshotRef; class SwiftASTManager; class SwiftLangSupport; class Context; class NotificationCenter; using TypeContextKind = swift::ide::CodeCompletionContext::TypeContextKind; class SwiftEditorDocument : public ThreadSafeRefCountedBase { struct Implementation; Implementation &Impl; public: SwiftEditorDocument(StringRef FilePath, SwiftLangSupport &LangSupport, swift::ide::CodeFormatOptions Options = swift::ide::CodeFormatOptions()); ~SwiftEditorDocument(); ImmutableTextSnapshotRef initializeText(llvm::MemoryBuffer *Buf, ArrayRef Args, bool ProvideSemanticInfo); ImmutableTextSnapshotRef replaceText(unsigned Offset, unsigned Length, llvm::MemoryBuffer *Buf, bool ProvideSemanticInfo, std::string &error); void updateSemaInfo(); void removeCachedAST(); ImmutableTextSnapshotRef getLatestSnapshot() const; void parse(ImmutableTextSnapshotRef Snapshot, SwiftLangSupport &Lang, bool BuildSyntaxTree, swift::SyntaxParsingCache *SyntaxCache = nullptr); void readSyntaxInfo(EditorConsumer &consumer); void readSemanticInfo(ImmutableTextSnapshotRef Snapshot, EditorConsumer& Consumer); void applyFormatOptions(OptionsDictionary &FmtOptions); void formatText(unsigned Line, unsigned Length, EditorConsumer &Consumer); void expandPlaceholder(unsigned Offset, unsigned Length, EditorConsumer &Consumer); const swift::ide::CodeFormatOptions &getFormatOptions(); static void reportDocumentStructure(swift::SourceFile &SrcFile, EditorConsumer &Consumer); const llvm::Optional &getSyntaxTree() const; std::string getFilePath() const; /// Whether or not the AST stored for this document is up-to-date or just an /// artifact of incremental syntax parsing bool hasUpToDateAST() const; }; typedef IntrusiveRefCntPtr SwiftEditorDocumentRef; class SwiftEditorDocumentFileMap { WorkQueue Queue{ WorkQueue::Dequeuing::Concurrent, "sourcekit.swift.EditorDocFileMap" }; struct DocInfo { SwiftEditorDocumentRef DocRef; std::string ResolvedPath; }; llvm::StringMap Docs; public: bool getOrUpdate(StringRef FilePath, SwiftLangSupport &LangSupport, SwiftEditorDocumentRef &EditorDoc); /// Looks up the document only by the path name that was given initially. SwiftEditorDocumentRef getByUnresolvedName(StringRef FilePath); /// Looks up the document by resolving symlinks in the paths. SwiftEditorDocumentRef findByPath(StringRef FilePath); SwiftEditorDocumentRef remove(StringRef FilePath); }; namespace CodeCompletion { /// Provides a thread-safe cache for code completion results that remain valid /// for the duration of a 'session' - for example, from the point that a user /// invokes code completion until they accept a completion, or otherwise close /// the list of completions. /// /// The contents of the cache can be modified asynchronously during the session, /// but the contained objects are immutable. class SessionCache : public ThreadSafeRefCountedBase { std::unique_ptr buffer; std::vector args; CompletionSink sink; std::vector sortedCompletions; CompletionKind completionKind; TypeContextKind typeContextKind; bool completionMayUseImplicitMemberExpr; FilterRules filterRules; llvm::sys::Mutex mtx; public: SessionCache(CompletionSink &&sink, std::unique_ptr &&buffer, std::vector &&args, CompletionKind completionKind, TypeContextKind typeContextKind, bool mayUseImplicitMemberExpr, FilterRules filterRules) : buffer(std::move(buffer)), args(std::move(args)), sink(std::move(sink)), completionKind(completionKind), typeContextKind(typeContextKind), completionMayUseImplicitMemberExpr(mayUseImplicitMemberExpr), filterRules(std::move(filterRules)) {} void setSortedCompletions(std::vector &&completions); ArrayRef getSortedCompletions(); llvm::MemoryBuffer *getBuffer(); ArrayRef getCompilerArgs(); const FilterRules &getFilterRules(); CompletionKind getCompletionKind(); TypeContextKind getCompletionTypeContextKind(); bool getCompletionMayUseImplicitMemberExpr(); }; typedef RefPtr SessionCacheRef; /// A thread-safe map from (buffer, code complete offset) to \c SessionCache. class SessionCacheMap { mutable unsigned nextBufferID = 0; mutable llvm::StringMap nameToBufferMap; typedef std::pair Key; llvm::DenseMap sessions; mutable llvm::sys::Mutex mtx; // Should only be called with Mtx locked. unsigned getBufferID(StringRef name) const; public: SessionCacheRef get(StringRef name, unsigned offset) const; bool set(StringRef name, unsigned offset, SessionCacheRef session); bool remove(StringRef name, unsigned offset); }; } // end namespace CodeCompletion class SwiftInterfaceGenMap { llvm::StringMap IFaceGens; mutable llvm::sys::Mutex Mtx; public: SwiftInterfaceGenContextRef get(StringRef Name) const; void set(StringRef Name, SwiftInterfaceGenContextRef IFaceGen); bool remove(StringRef Name); SwiftInterfaceGenContextRef find(StringRef ModuleName, const swift::CompilerInvocation &Invok); }; struct SwiftCompletionCache : public ThreadSafeRefCountedBase { std::unique_ptr inMemory; std::unique_ptr onDisk; swift::ide::CodeCompletionCache &getCache(); SwiftCompletionCache() = default; ~SwiftCompletionCache(); }; struct SwiftPopularAPI : public ThreadSafeRefCountedBase { llvm::StringMap nameToFactor; }; struct SwiftCustomCompletions : public ThreadSafeRefCountedBase { std::vector customCompletions; }; class RequestRefactoringEditConsumer: public swift::ide::SourceEditConsumer, public swift::DiagnosticConsumer { class Implementation; Implementation &Impl; public: RequestRefactoringEditConsumer(CategorizedEditsReceiver Receiver); ~RequestRefactoringEditConsumer(); void accept(swift::SourceManager &SM, swift::ide::RegionType RegionType, ArrayRef Replacements) override; void handleDiagnostic(swift::SourceManager &SM, swift::SourceLoc Loc, swift::DiagnosticKind Kind, StringRef FormatString, ArrayRef FormatArgs, const swift::DiagnosticInfo &Info) override; }; class RequestRenameRangeConsumer : public swift::ide::FindRenameRangesConsumer, public swift::DiagnosticConsumer { class Implementation; Implementation &Impl; public: RequestRenameRangeConsumer(CategorizedRenameRangesReceiver Receiver); ~RequestRenameRangeConsumer(); void accept(swift::SourceManager &SM, swift::ide::RegionType RegionType, ArrayRef Ranges) override; void handleDiagnostic(swift::SourceManager &SM, swift::SourceLoc Loc, swift::DiagnosticKind Kind, StringRef FormatString, ArrayRef FormatArgs, const swift::DiagnosticInfo &Info) override; }; struct SwiftStatistics { #define SWIFT_STATISTIC(VAR, UID, DESC) \ Statistic VAR{UIdent{"source.statistic." #UID}, DESC}; #include "SwiftStatistics.def" }; class SwiftLangSupport : public LangSupport { std::shared_ptr NotificationCtr; std::string RuntimeResourcePath; std::shared_ptr ASTMgr; std::shared_ptr EditorDocuments; SwiftInterfaceGenMap IFaceGenContexts; ThreadSafeRefCntPtr CCCache; ThreadSafeRefCntPtr PopularAPI; CodeCompletion::SessionCacheMap CCSessions; ThreadSafeRefCntPtr CustomCompletions; std::shared_ptr Stats; public: explicit SwiftLangSupport(SourceKit::Context &SKCtx); ~SwiftLangSupport(); std::shared_ptr getNotificationCenter() const { return NotificationCtr; } StringRef getRuntimeResourcePath() const { return RuntimeResourcePath; } std::shared_ptr getASTManager() { return ASTMgr; } std::shared_ptr getEditorDocuments() { return EditorDocuments; } SwiftInterfaceGenMap &getIFaceGenContexts() { return IFaceGenContexts; } IntrusiveRefCntPtr getCodeCompletionCache() { return CCCache; } /// Copy a memory buffer inserting '0' at the position of \c origBuf. // TODO: Share with code completion. static std::unique_ptr makeCodeCompletionMemoryBuffer(const llvm::MemoryBuffer *origBuf, unsigned &Offset, const std::string bufferIdentifier); static SourceKit::UIdent getUIDForDecl(const swift::Decl *D, bool IsRef = false); static SourceKit::UIdent getUIDForExtensionOfDecl(const swift::Decl *D); static SourceKit::UIdent getUIDForLocalVar(bool IsRef = false); static SourceKit::UIdent getUIDForRefactoringKind( swift::ide::RefactoringKind Kind); static SourceKit::UIdent getUIDForCodeCompletionDeclKind( swift::ide::CodeCompletionDeclKind Kind, bool IsRef = false); static SourceKit::UIdent getUIDForAccessor(const swift::ValueDecl *D, swift::AccessorKind AccKind, bool IsRef = false); static SourceKit::UIdent getUIDForModuleRef(); static SourceKit::UIdent getUIDForObjCAttr(); static SourceKit::UIdent getUIDForSyntaxNodeKind( swift::ide::SyntaxNodeKind Kind); static SourceKit::UIdent getUIDForSyntaxStructureKind( swift::ide::SyntaxStructureKind Kind); static SourceKit::UIdent getUIDForSyntaxStructureElementKind( swift::ide::SyntaxStructureElementKind Kind); static SourceKit::UIdent getUIDForSymbol(swift::index::SymbolInfo sym, bool isRef); static SourceKit::UIdent getUIDForRangeKind(swift::ide::RangeKind Kind); static SourceKit::UIdent getUIDForRegionType(swift::ide::RegionType Type); static SourceKit::UIdent getUIDForRefactoringRangeKind(swift::ide::RefactoringRangeKind Kind); static Optional getUIDForDeclAttribute(const swift::DeclAttribute *Attr); static std::vector UIDsFromDeclAttributes(const swift::DeclAttributes &Attrs); static SourceKit::UIdent getUIDForNameKind(swift::ide::NameKind Kind); static swift::ide::NameKind getNameKindForUID(SourceKit::UIdent Id); static bool printDisplayName(const swift::ValueDecl *D, llvm::raw_ostream &OS); /// Generate a USR for a Decl, including the prefix. /// \returns true if the results should be ignored, false otherwise. static bool printUSR(const swift::ValueDecl *D, llvm::raw_ostream &OS); /// Generate a USR for the Type of a given decl. /// \returns true if the results should be ignored, false otherwise. static bool printDeclTypeUSR(const swift::ValueDecl *D, llvm::raw_ostream &OS); /// Generate a USR for of a given type. /// \returns true if the results should be ignored, false otherwise. static bool printTypeUSR(swift::Type Ty, llvm::raw_ostream &OS); /// Generate a USR for an accessor, including the prefix. /// \returns true if the results should be ignored, false otherwise. static bool printAccessorUSR(const swift::AbstractStorageDecl *D, swift::AccessorKind AccKind, llvm::raw_ostream &OS); /// Annotates a declaration with XML tags that describe the key substructure /// of the declaration for CursorInfo/DocInfo. /// /// Prints declarations with decl- and type-specific tags derived from the /// UIDs used for decl/refs. /// /// FIXME: This move to libIDE, but currently depends on the UIdentVisitor. static void printFullyAnnotatedDeclaration(const swift::ValueDecl *VD, swift::Type BaseTy, llvm::raw_ostream &OS); static void printFullyAnnotatedSynthesizedDeclaration(const swift::ValueDecl *VD, swift::TypeOrExtensionDecl Target, llvm::raw_ostream &OS); static void printFullyAnnotatedGenericReq(const swift::GenericSignature *Sig, llvm::raw_ostream &OS); /// Print 'description' or 'sourcetext' the given \p VD to \p OS. If /// \p usePlaceholder is \c true, call argument positions are substituted with /// a typed editor placeholders which is suitable for 'sourcetext'. static void printMemberDeclDescription(const swift::ValueDecl *VD, swift::Type baseTy, bool usePlaceholder, llvm::raw_ostream &OS); /// Tries to resolve the path to the real file-system path. If it fails it /// returns the original path; static std::string resolvePathSymlinks(StringRef FilePath); //==========================================================================// // LangSupport Interface //==========================================================================// void indexSource(StringRef Filename, IndexingConsumer &Consumer, ArrayRef Args, StringRef Hash) override; void codeComplete(llvm::MemoryBuffer *InputBuf, unsigned Offset, SourceKit::CodeCompletionConsumer &Consumer, ArrayRef Args) override; void codeCompleteOpen(StringRef name, llvm::MemoryBuffer *inputBuf, unsigned offset, OptionsDictionary *options, ArrayRef rawFilterRules, GroupedCodeCompletionConsumer &consumer, ArrayRef args) override; void codeCompleteClose(StringRef name, unsigned offset, GroupedCodeCompletionConsumer &consumer) override; void codeCompleteUpdate(StringRef name, unsigned offset, OptionsDictionary *options, GroupedCodeCompletionConsumer &consumer) override; void codeCompleteCacheOnDisk(StringRef path) override; void codeCompleteSetPopularAPI(ArrayRef popularAPI, ArrayRef unpopularAPI) override; void codeCompleteSetCustom(ArrayRef completions) override; void editorOpen(StringRef Name, llvm::MemoryBuffer *Buf, EditorConsumer &Consumer, ArrayRef Args) override; void editorOpenInterface(EditorConsumer &Consumer, StringRef Name, StringRef ModuleName, Optional Group, ArrayRef Args, bool SynthesizedExtensions, Optional InterestedUSR) override; void editorOpenTypeInterface(EditorConsumer &Consumer, ArrayRef Args, StringRef TypeUSR) override; void editorOpenHeaderInterface(EditorConsumer &Consumer, StringRef Name, StringRef HeaderName, ArrayRef Args, bool UsingSwiftArgs, bool SynthesizedExtensions, StringRef swiftVersion) override; void editorOpenSwiftSourceInterface(StringRef Name, StringRef SourceName, ArrayRef Args, std::shared_ptr Consumer) override; void editorClose(StringRef Name, bool RemoveCache) override; void editorReplaceText(StringRef Name, llvm::MemoryBuffer *Buf, unsigned Offset, unsigned Length, EditorConsumer &Consumer) override; void editorApplyFormatOptions(StringRef Name, OptionsDictionary &FmtOptions) override; void editorFormatText(StringRef Name, unsigned Line, unsigned Length, EditorConsumer &Consumer) override; void editorExtractTextFromComment(StringRef Source, EditorConsumer &Consumer) override; void editorConvertMarkupToXML(StringRef Source, EditorConsumer &Consumer) override; void editorExpandPlaceholder(StringRef Name, unsigned Offset, unsigned Length, EditorConsumer &Consumer) override; void getCursorInfo(StringRef Filename, unsigned Offset, unsigned Length, bool Actionables, bool CancelOnSubsequentRequest, ArrayRef Args, std::function Receiver) override; void getNameInfo(StringRef Filename, unsigned Offset, NameTranslatingInfo &Input, ArrayRef Args, std::function Receiver) override; void getRangeInfo(StringRef Filename, unsigned Offset, unsigned Length, bool CancelOnSubsequentRequest, ArrayRef Args, std::function Receiver) override; void getCursorInfoFromUSR( StringRef Filename, StringRef USR, bool CancelOnSubsequentRequest, ArrayRef Args, std::function Receiver) override; void findRelatedIdentifiersInFile(StringRef Filename, unsigned Offset, bool CancelOnSubsequentRequest, ArrayRef Args, std::function Receiver) override; void syntacticRename(llvm::MemoryBuffer *InputBuf, ArrayRef RenameLocations, ArrayRef Args, CategorizedEditsReceiver Receiver) override; void findRenameRanges(llvm::MemoryBuffer *InputBuf, ArrayRef RenameLocations, ArrayRef Args, CategorizedRenameRangesReceiver Receiver) override; void findLocalRenameRanges(StringRef Filename, unsigned Line, unsigned Column, unsigned Length, ArrayRef Args, CategorizedRenameRangesReceiver Receiver) override; void collectExpressionTypes(StringRef FileName, ArrayRef Args, ArrayRef ExpectedProtocols, std::function Receiver) override; void semanticRefactoring(StringRef Filename, SemanticRefactoringInfo Info, ArrayRef Args, CategorizedEditsReceiver Receiver) override; void getDocInfo(llvm::MemoryBuffer *InputBuf, StringRef ModuleName, ArrayRef Args, DocInfoConsumer &Consumer) override; llvm::Optional> findUSRRange(StringRef DocumentName, StringRef USR) override; void findInterfaceDocument(StringRef ModuleName, ArrayRef Args, std::function Receiver) override; void findModuleGroups(StringRef ModuleName, ArrayRef Args, std::function, StringRef Error)> Receiver) override; void getExpressionContextInfo(llvm::MemoryBuffer *inputBuf, unsigned Offset, ArrayRef Args, TypeContextInfoConsumer &Consumer) override; void getConformingMethodList(llvm::MemoryBuffer *inputBuf, unsigned Offset, ArrayRef Args, ArrayRef ExpectedTypes, ConformingMethodListConsumer &Consumer) override; void getStatistics(StatisticsReceiver) override; private: swift::SourceFile *getSyntacticSourceFile(llvm::MemoryBuffer *InputBuf, ArrayRef Args, swift::CompilerInstance &ParseCI, std::string &Error); }; namespace trace { void initTraceInfo(trace::SwiftInvocation &SwiftArgs, StringRef InputFile, ArrayRef Args); void initTraceInfo(trace::SwiftInvocation &SwiftArgs, StringRef InputFile, ArrayRef Args); } /// When we cannot build any more clang modules, close the .pcm / files to /// prevent fd leaks in clients that cache the AST. // FIXME: Remove this once rdar://problem/19720334 is complete. class CloseClangModuleFiles { swift::ClangModuleLoader &loader; public: CloseClangModuleFiles(swift::ClangModuleLoader &loader) : loader(loader) {} ~CloseClangModuleFiles(); }; /// Disable expensive SIL options which do not affect indexing or diagnostics. void disableExpensiveSILOptions(swift::SILOptions &Opts); } // namespace SourceKit #endif