Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion interpreter/cling/include/cling/Interpreter/CIFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ namespace cling {
clang::CompilerInstance*
createCI(llvm::StringRef Code, const InvocationOptions& Opts,
const char* LLVMDir, std::unique_ptr<clang::ASTConsumer> consumer,
const ModuleFileExtensions& moduleExtensions);
const ModuleFileExtensions& moduleExtensions,
bool AutoComplete = false);

clang::CompilerInstance*
createCI(MemBufPtr_t Buffer, int Argc, const char* const* Argv,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@

using namespace clang;

namespace clang {
class CompilerInstance;
}

namespace cling {
/// \brief Create a new printing code-completion consumer that prints its
/// results to the given raw output stream.
Expand Down Expand Up @@ -50,6 +54,23 @@ namespace cling {
completions = m_Completions;
}
};

struct ClingCodeCompleter {
ClingCodeCompleter() = default;
std::string Prefix;

/// \param[in] InterpCI The compiler instance that is used to trigger code
/// completion.
/// \param[in] Content The string where code completion is triggered.
/// \param[in] Line The line number of the code completion point.
/// \param[in] Col The column number of the code completion point.
/// \param[in] ParentCI The running interpreter compiler instance that
/// provides ASTContexts.
/// \param[out] CCResults The completion results.
void codeComplete(CompilerInstance* InterpCI, llvm::StringRef Content,
unsigned Line, unsigned Col, CompilerInstance* ParentCI,
std::vector<std::string>& CCResults);
};
}

#endif
155 changes: 91 additions & 64 deletions interpreter/cling/lib/Interpreter/CIFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
Expand Down Expand Up @@ -1252,13 +1253,60 @@ namespace {
}
}

// Goal is to make this as close to the function in
// clang/lib/Interpreter/Interpreter.cpp taking only clang arguments
static llvm::Expected<std::unique_ptr<CompilerInstance>>
CreateCI(const std::vector<const char*>& ClangArgv,
const std::string& ExeName,
std::unique_ptr<clang::driver::Compilation>& Compilation) {
auto InvocationPtr = std::make_shared<clang::CompilerInvocation>();

// The compiler invocation is the owner of the diagnostic options.
// Everything else points to them.
DiagnosticOptions& DiagOpts = InvocationPtr->getDiagnosticOpts();
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
SetupDiagnostics(DiagOpts, ExeName);
if (!Diags)
return llvm::createStringError(llvm::errc::not_supported,
"Could not setup diagnostic engine.");

llvm::Triple TheTriple(llvm::sys::getProcessTriple());
clang::driver::Driver Drvr(ClangArgv[0], TheTriple.getTriple(), *Diags);
// Drvr.setWarnMissingInput(false);
Drvr.setCheckInputsExist(false); // think foo.C(12)
llvm::ArrayRef<const char*> RF(&(ClangArgv[0]), ClangArgv.size());
Compilation.reset(Drvr.BuildCompilation(RF));
if (!Compilation)
return llvm::createStringError(
llvm::errc::not_supported,
"Couldn't create clang::driver::Compilation.");

const llvm::opt::ArgStringList* CC1Args =
GetCC1Arguments(Compilation.get());
if (!CC1Args)
return llvm::createStringError(llvm::errc::not_supported,
"Could not get cc1 arguments.");

clang::CompilerInvocation::CreateFromArgs(*InvocationPtr, *CC1Args, *Diags);
// We appreciate the error message about an unknown flag (or do we? if not
// we should switch to a different DiagEngine for parsing the flags).
// But in general we'll happily go on.
Diags->Reset();

// Create and setup a compiler instance.
std::unique_ptr<CompilerInstance> CI(new CompilerInstance());
CI->setInvocation(InvocationPtr);
CI->setDiagnostics(Diags.get()); // Diags is ref-counted

return CI;
}

static CompilerInstance*
createCIImpl(std::unique_ptr<llvm::MemoryBuffer> Buffer,
const CompilerOptions& COpts,
const char* LLVMDir,
const CompilerOptions& COpts, const char* LLVMDir,
std::unique_ptr<clang::ASTConsumer> customConsumer,
const CIFactory::ModuleFileExtensions& moduleExtensions,
bool OnlyLex, bool HasInput = false) {
bool OnlyLex, bool HasInput = false, bool AutoComplete = false) {
// Follow clang -v convention of printing version on first line
if (COpts.Verbose)
cling::log() << "cling version " << ClingStringify(CLING_VERSION) << '\n';
Expand Down Expand Up @@ -1405,58 +1453,37 @@ namespace {
#endif
}
#endif

if (!COpts.HasOutput || !HasInput) {
if ((!COpts.HasOutput || !HasInput) && !AutoComplete) {
argvCompile.push_back("-");
}

auto InvocationPtr = std::make_shared<clang::CompilerInvocation>();
if (AutoComplete) {
// Put a dummy C++ file on to ensure there's at least one compile job for
// the driver to construct.
argvCompile.push_back("<<< cling interactive line includer >>>");
}

// The compiler invocation is the owner of the diagnostic options.
// Everything else points to them.
DiagnosticOptions& DiagOpts = InvocationPtr->getDiagnosticOpts();
// add prefix to diagnostic messages if second compiler instance is existing
// e.g. in CUDA mode
std::string ExeName = "";
if (COpts.CUDAHost)
ExeName = "cling";
if (COpts.CUDADevice)
ExeName = "cling-ptx";
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
SetupDiagnostics(DiagOpts, ExeName);
if (!Diags) {
cling::errs() << "Could not setup diagnostic engine.\n";
return nullptr;
}

llvm::Triple TheTriple(llvm::sys::getProcessTriple());
clang::driver::Driver Drvr(argv[0], TheTriple.getTriple(), *Diags);
//Drvr.setWarnMissingInput(false);
Drvr.setCheckInputsExist(false); // think foo.C(12)
llvm::ArrayRef<const char*>RF(&(argvCompile[0]), argvCompile.size());
std::unique_ptr<clang::driver::Compilation>
Compilation(Drvr.BuildCompilation(RF));
if (!Compilation) {
cling::errs() << "Couldn't create clang::driver::Compilation.\n";
return nullptr;
}
std::unique_ptr<clang::driver::Compilation> Compilation;

const llvm::opt::ArgStringList* CC1Args = GetCC1Arguments(Compilation.get());
if (!CC1Args) {
cling::errs() << "Could not get cc1 arguments.\n";
auto CIOrErr = CreateCI(argvCompile, ExeName, Compilation);
if (auto Err = CIOrErr.takeError()) {
llvm::logAllUnhandledErrors(std::move(Err), cling::errs());
return nullptr;
}
std::unique_ptr<clang::CompilerInstance> CI = std::move(*CIOrErr);

clang::CompilerInvocation::CreateFromArgs(*InvocationPtr, *CC1Args, *Diags);
// We appreciate the error message about an unknown flag (or do we? if not
// we should switch to a different DiagEngine for parsing the flags).
// But in general we'll happily go on.
Diags->Reset();
DiagnosticsEngine& Diags = CI->getDiagnostics();
CompilerInvocation& Invocation = CI->getInvocation();
DiagnosticOptions& DiagOpts = Invocation.getDiagnosticOpts();

// Create and setup a compiler instance.
std::unique_ptr<CompilerInstance> CI(new CompilerInstance());
CI->setInvocation(InvocationPtr);
CI->setDiagnostics(Diags.get()); // Diags is ref-counted
if (!OnlyLex)
CI->getDiagnosticOpts().ShowColors =
llvm::sys::Process::StandardOutIsDisplayed() ||
Expand All @@ -1469,9 +1496,9 @@ namespace {
// Copied from CompilerInstance::createDiagnostics:
// Chain in -verify checker, if requested.
if (DiagOpts.VerifyDiagnostics)
Diags->setClient(new clang::VerifyDiagnosticConsumer(*Diags));
Diags.setClient(new clang::VerifyDiagnosticConsumer(Diags));
// Configure our handling of diagnostics.
ProcessWarningOptions(*Diags, DiagOpts);
ProcessWarningOptions(Diags, DiagOpts);

if (COpts.HasOutput && !OnlyLex) {
ActionScan scan(clang::driver::Action::PrecompileJobClass,
Expand All @@ -1484,14 +1511,13 @@ namespace {
if (!SetupCompiler(CI.get(), COpts))
return nullptr;

ProcessWarningOptions(*Diags, DiagOpts);
ProcessWarningOptions(Diags, DiagOpts);
return CI.release();
}

IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> Overlay =
new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem());
CI->createFileManager(Overlay);
clang::CompilerInvocation& Invocation = CI->getInvocation();
std::string& PCHFile = Invocation.getPreprocessorOpts().ImplicitPCHInclude;
bool InitLang = true, InitTarget = true;
if (!PCHFile.empty()) {
Expand Down Expand Up @@ -1543,14 +1569,14 @@ namespace {
// When running interactively pass on the info that the PCH
// has failed so that IncrmentalParser::Initialize won't try again.
if (!HasInput && llvm::sys::Process::StandardInIsUserInput()) {
const unsigned ID = Diags->getCustomDiagID(
clang::DiagnosticsEngine::Level::Error,
"Problems loading PCH: '%0'.");
Diags->Report(ID) << PCHFile;
const unsigned ID =
Diags.getCustomDiagID(clang::DiagnosticsEngine::Level::Error,
"Problems loading PCH: '%0'.");

Diags.Report(ID) << PCHFile;
// If this was the only error, then don't let it stop anything
if (Diags->getClient()->getNumErrors() == 1)
Diags->Reset(true);
if (Diags.getClient()->getNumErrors() == 1)
Diags.Reset(true);
// Clear the include so no one else uses it.
std::string().swap(PCHFile);
}
Expand Down Expand Up @@ -1606,13 +1632,13 @@ namespace {
SM->setFileIsTransient(FE);
FileID MainFileID = SM->createFileID(FE, SourceLocation(), SrcMgr::C_User);
SM->setMainFileID(MainFileID);
const SrcMgr::SLocEntry& MainFileSLocE = SM->getSLocEntry(MainFileID);
const SrcMgr::FileInfo& MainFileFI = MainFileSLocE.getFile();
SrcMgr::ContentCache& MainFileCC
= const_cast<SrcMgr::ContentCache&>(MainFileFI.getContentCache());
if (!Buffer)
Buffer = llvm::MemoryBuffer::getMemBuffer("/*CLING DEFAULT MEMBUF*/;\n");
MainFileCC.setBuffer(std::move(Buffer));

// Adapted from upstream clang/lib/Interpreter/Interpreter.cpp
// FIXME: Merge with CompilerInstance::ExecuteAction.
llvm::MemoryBuffer* MB = Buffer.release();
CI->getPreprocessorOpts().addRemappedFile(Filename, MB);

// Create TargetInfo for the other side of CUDA and OpenMP compilation.
if ((CI->getLangOpts().CUDA || CI->getLangOpts().OpenMPIsTargetDevice) &&
Expand Down Expand Up @@ -1780,16 +1806,17 @@ namespace {

namespace cling {

CompilerInstance*
CIFactory::createCI(llvm::StringRef Code, const InvocationOptions& Opts,
const char* LLVMDir,
std::unique_ptr<clang::ASTConsumer> consumer,
const ModuleFileExtensions& moduleExtensions) {
return createCIImpl(llvm::MemoryBuffer::getMemBuffer(Code), Opts.CompilerOpts,
LLVMDir, std::move(consumer), moduleExtensions,
false /*OnlyLex*/,
!Opts.IsInteractive());
}
CompilerInstance*
CIFactory::createCI(llvm::StringRef Code, const InvocationOptions& Opts,
const char* LLVMDir,
std::unique_ptr<clang::ASTConsumer> consumer,
const ModuleFileExtensions& moduleExtensions,
bool AutoComplete /*false*/) {
return createCIImpl(llvm::MemoryBuffer::getMemBuffer(Code),
Opts.CompilerOpts, LLVMDir, std::move(consumer),
moduleExtensions, false /*OnlyLex*/,
!Opts.IsInteractive(), AutoComplete);
}

CompilerInstance* CIFactory::createCI(
MemBufPtr_t Buffer, int argc, const char* const* argv, const char* LLVMDir,
Expand Down
Loading
Loading