Files
swift-mirror/include/swift/IDETool/IDEInspectionInstance.h

240 lines
9.9 KiB
C++

//===--- IDEInspectionInstance.h ------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2019 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 SWIFT_IDE_IDEINSPECTIONINSTANCE_H
#define SWIFT_IDE_IDEINSPECTIONINSTANCE_H
#include "swift/Frontend/Frontend.h"
#include "swift/IDE/CancellableResult.h"
#include "swift/IDE/CodeCompletionContext.h"
#include "swift/IDE/CodeCompletionResult.h"
#include "swift/IDE/CodeCompletionResultSink.h"
#include "swift/IDE/ConformingMethodList.h"
#include "swift/IDE/CursorInfo.h"
#include "swift/IDE/ImportDepth.h"
#include "swift/IDE/SignatureHelp.h"
#include "swift/IDE/SwiftCompletionInfo.h"
#include "swift/IDE/TypeContextInfo.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/VirtualFileSystem.h"
namespace swift {
class CompilerInstance;
class CompilerInvocation;
class DiagnosticConsumer;
class PluginRegistry;
namespace ide {
/// Copy a memory buffer inserting '\0' at the position of \c origBuf.
std::unique_ptr<llvm::MemoryBuffer>
makeCodeCompletionMemoryBuffer(const llvm::MemoryBuffer *origBuf,
unsigned &Offset,
llvm::StringRef bufferIdentifier);
/// The result returned via the callback from the perform*Operation methods.
struct IDEInspectionInstanceResult {
/// The compiler instance that is prepared for the second pass.
std::shared_ptr<CompilerInstance> CI;
/// Whether an AST was reused.
bool DidReuseAST;
/// Whether the IDEInspectionInstance target could be found in the source
/// file. If this is \c false, the user will most likely want to return
/// empty results.
bool DidFindIDEInspectionTarget;
};
/// The results returned from \c IDEInspectionInstance::codeComplete.
struct CodeCompleteResult {
CodeCompletionResultSink &ResultSink;
SwiftCompletionInfo &Info;
ImportDepth ImportDep;
};
/// The results returned from \c IDEInspectionInstance::typeContextInfo.
struct TypeContextInfoResult {
/// The actual results. If empty, no results were found.
ArrayRef<TypeContextInfoItem> Results;
/// Whether an AST was reused to produce the results.
bool DidReuseAST;
};
/// The results returned from \c IDEInspectionInstance::conformingMethodList.
struct ConformingMethodListResults {
/// The actual results. If \c nullptr, no results were found.
const ConformingMethodListResult *Result;
/// Whether an AST was reused to produce the results.
bool DidReuseAST;
};
/// The results returned from \c IDEInspectionInstance::signatures.
struct SignatureHelpResults {
/// The actual results. If \c nullptr, no results were found.
const SignatureHelpResult *Result;
/// Whether an AST was reused to produce the results.
bool DidReuseAST;
};
/// The results returned from \c IDEInspectionInstance::cursorInfo.
struct CursorInfoResults {
/// The actual results.
std::vector<ResolvedCursorInfoPtr> ResolvedCursorInfos;
/// Whether an AST was reused to produce the results.
bool DidReuseAST;
};
/// Manages \c CompilerInstance for completion like operations.
class IDEInspectionInstance {
struct Options {
unsigned MaxASTReuseCount = 100;
unsigned DependencyCheckIntervalSecond = 5;
} Opts;
std::mutex mtx;
std::shared_ptr<PluginRegistry> Plugins;
std::shared_ptr<CompilerInstance> CachedCI;
llvm::hash_code CachedArgHash;
llvm::sys::TimePoint<> DependencyCheckedTimestamp;
llvm::StringMap<llvm::hash_code> InMemoryDependencyHash;
unsigned CachedReuseCount = 0;
std::atomic<bool> CachedCIShouldBeInvalidated;
void cacheCompilerInstance(std::shared_ptr<CompilerInstance> CI,
llvm::hash_code ArgsHash);
bool shouldCheckDependencies() const;
/// Calls \p Callback with cached \c CompilerInstance if it's usable for the
/// specified completion request.
/// Returns \c true if performing the cached operation was possible. Returns
/// \c false if the compiler argument has changed, primary file is not the
/// same, the \c Offset is not in function bodies, or the interface hash of
/// the file has changed.
/// \p Callback will be called if and only if this function returns \c true.
bool performCachedOperationIfPossible(
llvm::hash_code ArgsHash,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
const SearchPathOptions &SearchPathOpts,
llvm::MemoryBuffer *ideInspectionTargetBuffer, unsigned int Offset,
DiagnosticConsumer *DiagC,
std::shared_ptr<std::atomic<bool>> CancellationFlag,
llvm::function_ref<void(CancellableResult<IDEInspectionInstanceResult>)>
Callback);
/// Calls \p Callback with new \c CompilerInstance for the completion
/// request. The \c CompilerInstace passed to the callback already performed
/// the first pass.
/// Returns \c false if it fails to setup the \c CompilerInstance.
void performNewOperation(
std::optional<llvm::hash_code> ArgsHash,
swift::CompilerInvocation &Invocation,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
llvm::MemoryBuffer *ideInspectionTargetBuffer, unsigned int Offset,
DiagnosticConsumer *DiagC,
std::shared_ptr<std::atomic<bool>> CancellationFlag,
llvm::function_ref<void(CancellableResult<IDEInspectionInstanceResult>)>
Callback);
/// Calls \p Callback with a \c CompilerInstance which is prepared for the
/// second pass. \p Callback is resposible to perform the second pass on it.
/// The \c CompilerInstance may be reused from the previous completions,
/// and may be cached for the next completion.
/// In case of failure or cancellation, the callback receives the
/// corresponding failed or cancelled result.
///
/// If \p CancellationFlag is not \c nullptr, code completion can be cancelled
/// by setting the flag to \c true.
/// IMPORTANT: If \p CancellationFlag is not \c nullptr, then completion might
/// be cancelled in the secon pass that's invoked inside \p Callback.
/// Therefore, \p Callback MUST check whether completion was cancelled before
/// interpreting the results, since invalid results may be returned in case
/// of cancellation.
///
/// NOTE: \p Args is only used for checking the equaity of the invocation.
/// Since this function assumes that it is already normalized, exact the same
/// arguments including their order is considered as the same invocation.
void performOperation(
swift::CompilerInvocation &Invocation, llvm::ArrayRef<const char *> Args,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
llvm::MemoryBuffer *ideInspectionTargetBuffer, unsigned int Offset,
DiagnosticConsumer *DiagC,
std::shared_ptr<std::atomic<bool>> CancellationFlag,
llvm::function_ref<void(CancellableResult<IDEInspectionInstanceResult>)>
Callback);
public:
IDEInspectionInstance(std::shared_ptr<PluginRegistry> Plugins = nullptr)
: Plugins(Plugins), CachedCIShouldBeInvalidated(false) {}
// Mark the cached compiler instance "should be invalidated". In the next
// completion, new compiler instance will be used. (Thread safe.)
void markCachedCompilerInstanceShouldBeInvalidated();
// Update options with \c NewOpts. (Thread safe.)
void setOptions(Options NewOpts);
void codeComplete(
swift::CompilerInvocation &Invocation, llvm::ArrayRef<const char *> Args,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
llvm::MemoryBuffer *ideInspectionTargetBuffer, unsigned int Offset,
DiagnosticConsumer *DiagC, ide::CodeCompletionContext &CompletionContext,
std::shared_ptr<std::atomic<bool>> CancellationFlag,
llvm::function_ref<void(CancellableResult<CodeCompleteResult>)> Callback);
void typeContextInfo(
swift::CompilerInvocation &Invocation, llvm::ArrayRef<const char *> Args,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
llvm::MemoryBuffer *ideInspectionTargetBuffer, unsigned int Offset,
DiagnosticConsumer *DiagC,
std::shared_ptr<std::atomic<bool>> CancellationFlag,
llvm::function_ref<void(CancellableResult<TypeContextInfoResult>)>
Callback);
void conformingMethodList(
swift::CompilerInvocation &Invocation, llvm::ArrayRef<const char *> Args,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
llvm::MemoryBuffer *ideInspectionTargetBuffer, unsigned int Offset,
DiagnosticConsumer *DiagC, ArrayRef<const char *> ExpectedTypeNames,
std::shared_ptr<std::atomic<bool>> CancellationFlag,
llvm::function_ref<void(CancellableResult<ConformingMethodListResults>)>
Callback);
void signatureHelp(
swift::CompilerInvocation &Invocation, llvm::ArrayRef<const char *> Args,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
llvm::MemoryBuffer *ideInspectionTargetBuffer, unsigned int Offset,
DiagnosticConsumer *DiagC,
std::shared_ptr<std::atomic<bool>> CancellationFlag,
llvm::function_ref<void(CancellableResult<SignatureHelpResults>)>
Callback);
void cursorInfo(
swift::CompilerInvocation &Invocation, llvm::ArrayRef<const char *> Args,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
llvm::MemoryBuffer *ideInspectionTargetBuffer, unsigned int Offset,
DiagnosticConsumer *DiagC,
std::shared_ptr<std::atomic<bool>> CancellationFlag,
llvm::function_ref<void(CancellableResult<CursorInfoResults>)> Callback);
};
} // namespace ide
} // namespace swift
#endif // SWIFT_IDE_IDEINSPECTIONINSTANCE_H