Refactoring ROOT & Cling code completion.

This commit is contained in:
CristinaCristescu 2016-07-07 10:47:58 +02:00 committed by sftnight
parent e3d5b485e9
commit 528b16faf6
16 changed files with 537 additions and 589 deletions

View File

@ -1,26 +1,33 @@
#ifndef CLINGCODECOMPLETECONSUMER_H
#define CLINGCODECOMPLETECONSUMER_H
//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Bianca-Cristina Cristescu <bianca-cristina.cristescu@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#ifndef CLING_CODE_COMPLETE_CONSUMER
#define CLING_CODE_COMPLETE_CONSUMER
#include "clang/Sema/CodeCompleteConsumer.h"
using namespace clang;
/// \brief Create a new printing code-completion consumer that prints its
/// results to the given raw output stream.
class ClingCodeCompleteConsumer : public CodeCompleteConsumer {
/// \brief The raw output stream.
raw_ostream &OS;
CodeCompletionTUInfo CCTUInfo;
raw_ostream &m_OS;
CodeCompletionTUInfo m_CCTUInfo;
/// \ brief Results of the completer to be printed by the text interface.
std::vector<std::string> m_completions;
std::vector<std::string> &m_Completions;
public:
/// \brief Create a new printing code-completion consumer that prints its
/// results to the given raw output stream.
ClingCodeCompleteConsumer(const CodeCompleteOptions &CodeCompleteOpts,
raw_ostream &OS)
: CodeCompleteConsumer(CodeCompleteOpts, false), OS(OS),
CCTUInfo(new GlobalCodeCompletionAllocator) {}
raw_ostream &OS, std::vector<std::string> &completions)
: CodeCompleteConsumer(CodeCompleteOpts, false), m_OS(OS),
m_CCTUInfo(new GlobalCodeCompletionAllocator), m_Completions(completions){}
~ClingCodeCompleteConsumer() {}
/// \brief Prints the finalized code-completion results.
@ -28,21 +35,17 @@ public:
CodeCompletionResult *Results,
unsigned NumResults) override;
void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
OverloadCandidate *Candidates,
unsigned NumCandidates) override {}
CodeCompletionAllocator &getAllocator() override {
return m_CCTUInfo.getAllocator();
}
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return m_CCTUInfo; }
bool isResultFilteredOut(StringRef Filter, CodeCompletionResult Results) override;
CodeCompletionAllocator &getAllocator() override {
return CCTUInfo.getAllocator();
}
CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
void getCompletions(std::vector<std::string>& completions) {
completions = m_completions;
completions = m_Completions;
}
};
#endif
#endif

View File

@ -1,23 +0,0 @@
#ifndef CLINGTABCOMPLETION_H
#define CLINGTABCOMPLETION_H
#include <string>
#include <vector>
namespace cling {
class Interpreter;
class ClingTabCompletion {
const cling::Interpreter& ParentInterp;
public:
ClingTabCompletion(cling::Interpreter& Parent) : ParentInterp(Parent) {}
~ClingTabCompletion() {}
bool Complete(const std::string& Line /*in+out*/,
size_t& Cursor /*in+out*/,
std::vector<std::string>& DisplayCompletions /*out*/);
};
}
#endif

View File

@ -221,6 +221,17 @@ namespace cling {
Value* V = 0,
Transaction** T = 0);
///\brief Worker function to code complete after all the mechanism
/// has been set up.
///
///\param [in] input - The input being completed.
///\param [in] offset - The offset for the completion point.
///
///\returns Whether the operation was fully successful.
///
CompilationResult CodeCompleteInternal(const std::string& input,
unsigned offset);
///\brief Decides whether the input line should be wrapped into a function
/// declaration that can later be executed.
///
@ -238,7 +249,8 @@ namespace cling {
///\param [out] input - The input to wrap.
///\param [out] fname - The wrapper function's name.
///
void WrapInput(std::string& input, std::string& fname);
void WrapInput(std::string& input, std::string& fnamem,
CompilationOptions &CO);
///\brief Runs given wrapper function.
///
@ -473,11 +485,13 @@ namespace cling {
/// code complete code.
///
/// @param[in] input - The input containing the string to be completed.
/// @param[out] T - The cling::Transaction of the input
/// @param[in] cursor - The offset for the completion point.
/// @param[out] completions - The results for teh completion
///
///\returns Whether the operation was fully successful.
///
CompilationResult codeComplete(const std::string& input, unsigned offset);
CompilationResult codeComplete(const std::string& line, size_t& cursor,
std::vector<std::string>& completions) const;
///\brief Compiles input line, which doesn't contain statements.
///
@ -689,9 +703,6 @@ namespace cling {
IgnoreFilesFunc_t ignoreFiles =
[](const clang::PresumedLoc&) { return false;}) const;
void CodeComplete(const std::string& line, size_t& cursor,
std::vector<std::string>& displayCompletions) const;
friend class runtime::internal::LifetimeHandler;
};

View File

@ -30,11 +30,9 @@ namespace clang {
class Token;
class FileEntry;
class Module;
class CodeCompleteConsumer;
}
namespace cling {
class ClingTabCompletion;
class Interpreter;
class InterpreterCallbacks;
class InterpreterDeserializationListener;
@ -46,7 +44,6 @@ namespace cling {
/// interpreter as it does its thing. Clients can define their hooks here to
/// implement interpreter level tools.
class InterpreterCallbacks {
protected:
///\brief Our interpreter instance.
@ -73,8 +70,6 @@ namespace cling {
///
bool m_IsRuntime;
protected:
void UpdateWithNewDecls(const clang::DeclContext *DC,
clang::DeclarationName Name,
@ -166,17 +161,6 @@ namespace cling {
/// for instance when throwing interpreter exceptions.
virtual void PrintStackTrace() {}
///\brief Cling creates the code complete consumer for its child interp.
virtual void CreateCodeCompleteConsumer(Interpreter* child) const;
///\brief Get the results of the code completion.
virtual void GetCompletionResults(Interpreter* child,
std::vector<std::string>&) const;
///\brief Get the results of the code completion.
virtual void CodeComplete(const std::string&, size_t&,
std::vector<std::string>&) const;
///\brief DynamicScopes only! Set to true if it is currently evaluating a
/// dynamic expr.
///

View File

@ -109,8 +109,6 @@ namespace cling {
const Interpreter& getInterpreter() const { return m_Interp; }
Interpreter& getInterpreter() { return m_Interp; }
///\brief Get the output stream used by the MetaProcessor for its output.
/// (in contrast to the interpreter's output which is redirected using
/// setStdStream()).

View File

@ -1,282 +0,0 @@
#include "ASTImportSource.h"
#include "cling/Interpreter/Interpreter.h"
#include "clang/Lex/Preprocessor.h"
using namespace clang;
namespace {
class ClingASTImporter : public ASTImporter {
private:
cling::ASTImportSource& m_source;
public:
ClingASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
ASTContext &FromContext, FileManager &FromFileManager,
bool MinimalImport, cling::ASTImportSource& source) :
ASTImporter(ToContext, ToFileManager, FromContext,
FromFileManager, MinimalImport), m_source(source) {}
Decl *Imported(Decl *From, Decl *To) override {
ASTImporter::Imported(From, To);
if (isa<TagDecl>(From)) {
clang::TagDecl* toTagDecl = dyn_cast<TagDecl>(To);
toTagDecl->setHasExternalVisibleStorage();
}
if (isa<NamespaceDecl>(From))
{
NamespaceDecl *to_namespace_decl = dyn_cast<NamespaceDecl>(To);
to_namespace_decl->setHasExternalVisibleStorage();
}
if (isa<ObjCContainerDecl>(From))
{
ObjCContainerDecl *to_container_decl = dyn_cast<ObjCContainerDecl>(To);
to_container_decl->setHasExternalLexicalStorage();
to_container_decl->setHasExternalVisibleStorage();
}
// Put the name of the Decl imported with the
// DeclarationName coming from the parent, in my map.
if (DeclContext *declContextParent = llvm::dyn_cast<DeclContext>(From)) {
DeclContext *declContextChild = llvm::dyn_cast<DeclContext>(To);
m_source.addToDeclContext(declContextChild, declContextParent);
}
return To;
}
};
}
namespace cling {
ASTImportSource::ASTImportSource(const cling::Interpreter *parent_interpreter,
cling::Interpreter *child_interpreter) :
m_parent_Interp(parent_interpreter), m_child_Interp(child_interpreter) {
clang::DeclContext *parentTUDeclContext =
clang::TranslationUnitDecl::castToDeclContext(
m_parent_Interp->getCI()->getASTContext().getTranslationUnitDecl());
clang::DeclContext *childTUDeclContext =
clang::TranslationUnitDecl::castToDeclContext(
m_child_Interp->getCI()->getASTContext().getTranslationUnitDecl());
// Also keep in the map of Decl Contexts the Translation Unit Decl Context
m_DeclContexts_map[childTUDeclContext] = parentTUDeclContext;
}
void ASTImportSource::ImportDecl(Decl *declToImport,
ASTImporter &importer,
DeclarationName &childDeclName,
DeclarationName &parentDeclName,
const DeclContext *childCurrentDeclContext) {
// Don't do the import if we have a Function Template.
// Not supported by clang.
// FIXME: This is also a temporary check. Will be de-activated
// once clang supports the import of function templates.
if (declToImport->isFunctionOrFunctionTemplate() && declToImport->isTemplateDecl())
return;
cling::Interpreter::PushTransactionRAII RAII(parent_int);
if (Decl *importedDecl = importer.Import(declToImport)) {
if (NamedDecl *importedNamedDecl = llvm::dyn_cast<NamedDecl>(importedDecl)) {
std::vector < NamedDecl * > declVector{importedNamedDecl};
llvm::ArrayRef < NamedDecl * > FoundDecls(declVector);
SetExternalVisibleDeclsForName(childCurrentDeclContext,
importedNamedDecl->getDeclName(),
FoundDecls);
}
// Put the name of the Decl imported with the
// DeclarationName coming from the parent, in my map.
m_DeclName_map[childDeclName] = parentDeclName;
}
}
void ASTImportSource::ImportDeclContext(DeclContext *declContextToImport,
ASTImporter &importer,
DeclarationName &childDeclName,
DeclarationName &parentDeclName,
const DeclContext *childCurrentDeclContext) {
if (DeclContext *importedDeclContext = importer.ImportContext(declContextToImport)) {
importedDeclContext->setHasExternalVisibleStorage(true);
if (NamedDecl *importedNamedDecl = llvm::dyn_cast<NamedDecl>(importedDeclContext)) {
std::vector < NamedDecl * > declVector{importedNamedDecl};
llvm::ArrayRef < NamedDecl * > FoundDecls(declVector);
SetExternalVisibleDeclsForName(childCurrentDeclContext,
importedNamedDecl->getDeclName(),
FoundDecls);
}
// Put the name of the DeclContext imported with the
// DeclarationName coming from the parent, in my map.
m_DeclName_map[childDeclName] = parentDeclName;
// And also put the declaration context I found from the parent Interpreter
// in the map of the child Interpreter to have it for the future.
m_DeclContexts_map[importedDeclContext] = declContextToImport;
}
}
bool ASTImportSource::Import(DeclContext::lookup_result lookup_result,
ASTContext &from_ASTContext,
ASTContext &to_ASTContext,
const DeclContext *childCurrentDeclContext,
DeclarationName &childDeclName,
DeclarationName &parentDeclName) {
// Prepare to import the Decl(Context) we found in the
// child interpreter by getting the file managers from
// each interpreter.
FileManager &child_FM = m_child_Interp->getCI()->getFileManager();
FileManager &parent_FM = m_parent_Interp->getCI()->getFileManager();
// Cling's ASTImporter
ClingASTImporter importer(to_ASTContext, child_FM,
from_ASTContext, parent_FM,
/*MinimalImport : ON*/ true, *this);
for (DeclContext::lookup_iterator I = lookup_result.begin(),
E = lookup_result.end();
I != E; ++I) {
// Check if this Name we are looking for is
// a DeclContext (for example a Namespace, function etc.).
if (DeclContext *declContextToImport = llvm::dyn_cast<DeclContext>(*I)) {
ImportDeclContext(declContextToImport, importer, childDeclName,
parentDeclName, childCurrentDeclContext);
} else if (Decl *declToImport = llvm::dyn_cast<Decl>(*I)) {
// else it is a Decl
ImportDecl(declToImport, importer, childDeclName,
parentDeclName, childCurrentDeclContext);
}
}
return true;
}
///\brief This is the most important function of the class ASTImportSource
/// since from here initiates the lookup and import part of the missing
/// Decl(s) (Contexts).
///
bool ASTImportSource::FindExternalVisibleDeclsByName(
const DeclContext *childCurrentDeclContext, DeclarationName childDeclName) {
assert(childDeclName && "Child Decl name is empty");
assert(childCurrentDeclContext->hasExternalVisibleStorage() &&
"DeclContext has no visible decls in storage");
//Check if we have already found this declaration Name before
DeclarationName parentDeclName;
std::map<clang::DeclarationName,
clang::DeclarationName>::iterator II = m_DeclName_map.find(childDeclName);
if (II != m_DeclName_map.end()) {
parentDeclName = II->second;
} else {
// Get the identifier info from the parent interpreter
// for this Name.
std::string name = childDeclName.getAsString();
if (!name.empty()) {
llvm::StringRef nameRef(name);
IdentifierTable &parentIdentifierTable =
m_parent_Interp->getCI()->getASTContext().Idents;
IdentifierInfo &parentIdentifierInfo =
parentIdentifierTable.get(nameRef);
parentDeclName = DeclarationName(&parentIdentifierInfo);
}
}
// Search in the map of the stored Decl Contexts for this
// Decl Context.
std::map<const clang::DeclContext *, clang::DeclContext *>::iterator I;
// If childCurrentDeclContext was found before and is already in the map,
// then do the lookup using the stored pointer.
if ((I = m_DeclContexts_map.find(childCurrentDeclContext))
!= m_DeclContexts_map.end()) {
DeclContext *parentDeclContext = I->second;
Decl *fromDeclContext = Decl::castFromDeclContext(parentDeclContext);
ASTContext &from_ASTContext = fromDeclContext->getASTContext();
Decl *toDeclContext = Decl::castFromDeclContext(childCurrentDeclContext);
ASTContext &to_ASTContext = toDeclContext->getASTContext();
DeclContext::lookup_result lookup_result =
parentDeclContext->lookup(parentDeclName);
// Check if we found this Name in the parent interpreter
if (!lookup_result.empty()) {
// Do the import
if (Import(lookup_result, from_ASTContext, to_ASTContext,
childCurrentDeclContext, childDeclName, parentDeclName))
return true;
}
}
return false;
}
///\brief Make available to child all decls in parent's decl context
/// that corresponds to child decl context.
void ASTImportSource::completeVisibleDeclsMap(
const clang::DeclContext *childDeclContext) {
assert (childDeclContext && "No child decl context!");
if (!childDeclContext->hasExternalVisibleStorage())
return;
// Search in the map of the stored Decl Contexts for this
// Decl Context.
std::map<const clang::DeclContext *, clang::DeclContext *>::iterator I;
// If childCurrentDeclContext was found before and is already in the map,
// then do the lookup using the stored pointer.
if ((I = m_DeclContexts_map.find(childDeclContext))
!= m_DeclContexts_map.end()) {
DeclContext *parentDeclContext = I->second;
Decl *fromDeclContext = Decl::castFromDeclContext(parentDeclContext);
ASTContext &from_ASTContext = fromDeclContext->getASTContext();
Decl *toDeclContext = Decl::castFromDeclContext(childDeclContext);
ASTContext &to_ASTContext = toDeclContext->getASTContext();
// Prepare to import the Decl(Context) we found in the
// child interpreter by getting the file managers from
// each interpreter.
FileManager &child_FM = m_child_Interp->getCI()->getFileManager();
FileManager &parent_FM = m_parent_Interp->getCI()->getFileManager();
// Cling's ASTImporter
ClingASTImporter importer(to_ASTContext, child_FM,
from_ASTContext, parent_FM,
/*MinimalImport : ON*/ true, *this);
StringRef filter = m_child_Interp->getCI()->getPreprocessor().getCodeCompletionFilter();
for (DeclContext::decl_iterator I_decl = parentDeclContext->decls_begin(),
E_decl = parentDeclContext->decls_end(); I_decl != E_decl; ++I_decl) {
if (NamedDecl* parentNamedDecl = llvm::dyn_cast<NamedDecl>(*I_decl)) {
// Filter using the stem from the input line
DeclarationName newDeclName = parentNamedDecl->getDeclName();
if (newDeclName.getAsIdentifierInfo()) {
StringRef name = newDeclName.getAsIdentifierInfo()->getName();
if (!name.empty() && name.startswith(filter))
ImportDecl(parentNamedDecl, importer, newDeclName, newDeclName,
childDeclContext);
}
}
}
const_cast<DeclContext *>(childDeclContext)->
setHasExternalVisibleStorage(false);
}
}
} // end namespace cling

View File

@ -20,14 +20,12 @@ set( LLVM_LINK_COMPONENTS
add_cling_library(clingInterpreter
AutoSynthesizer.cpp
AutoloadCallback.cpp
ASTImportSource.cpp
ASTTransformer.cpp
BackendPasses.cpp
CheckEmptyTransactionTransformer.cpp
CIFactory.cpp
ClangInternalState.cpp
ClingCodeCompleteConsumer.cpp
ClingTabCompletion.cpp
ClingPragmas.cpp
DeclCollector.cpp
DeclExtractor.cpp
@ -37,6 +35,7 @@ add_cling_library(clingInterpreter
DynamicExprInfo.cpp
Exception.cpp
ExceptionRTTI.cpp
ExternalInterpreterSource.cpp
ForwardDeclPrinter.cpp
IncrementalExecutor.cpp
IncrementalJIT.cpp

View File

@ -1,13 +1,19 @@
//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Bianca-Cristina Cristescu <bianca-cristina.cristescu@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#include "cling/Interpreter/ClingCodeCompleteConsumer.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Sema.h"
void
ClingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
void ClingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
CodeCompletionContext Context,
CodeCompletionResult *Results,
unsigned NumResults) {
@ -15,40 +21,38 @@ ClingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter();
// Print the results.
for (unsigned I = 0; I != NumResults; ++I) {
if(!Filter.empty() && isResultFilteredOut(Filter, Results[I]))
if (!Filter.empty() && isResultFilteredOut(Filter, Results[I]))
continue;
switch (Results[I].Kind) {
case CodeCompletionResult::RK_Declaration:
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, Context,
getAllocator(),
CCTUInfo,
includeBriefComments())) {
m_completions.push_back(CCS->getAsString());
}
break;
case CodeCompletionResult::RK_Keyword:
m_completions.push_back(Results[I].Keyword);
break;
case CodeCompletionResult::RK_Declaration:
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, Context,
getAllocator(),
m_CCTUInfo,
includeBriefComments())) {
m_Completions.push_back(CCS->getAsString());
}
break;
case CodeCompletionResult::RK_Macro: {
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, Context,
getAllocator(),
CCTUInfo,
includeBriefComments())) {
m_completions.push_back(CCS->getAsString());
}
break;
}
case CodeCompletionResult::RK_Pattern: {
m_completions.push_back(Results[I].Pattern->getAsString());
break;
}
case CodeCompletionResult::RK_Keyword:
m_Completions.push_back(Results[I].Keyword);
break;
case CodeCompletionResult::RK_Macro:
if (CodeCompletionString *CCS
= Results[I].CreateCodeCompletionString(SemaRef, Context,
getAllocator(),
m_CCTUInfo,
includeBriefComments())) {
m_Completions.push_back(CCS->getAsString());
}
break;
case CodeCompletionResult::RK_Pattern:
m_Completions.push_back(Results[I].Pattern->getAsString());
break;
}
}
}
@ -56,19 +60,19 @@ ClingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
bool ClingCodeCompleteConsumer::isResultFilteredOut(StringRef Filter,
CodeCompletionResult Result) {
switch (Result.Kind) {
case CodeCompletionResult::RK_Declaration: {
return !(Result.Declaration->getIdentifier() &&
(*Result.Declaration).getIdentifier()->getName().startswith(Filter));
}
case CodeCompletionResult::RK_Keyword: {
return !((StringRef(Result.Keyword)).startswith(Filter));
}
case CodeCompletionResult::RK_Macro: {
return !(Result.Macro->getName().startswith(Filter));
}
case CodeCompletionResult::RK_Pattern: {
return !(StringRef((Result.Pattern->getAsString())).startswith(Filter));
}
default: llvm_unreachable("Unknown code completion result Kind.");
case CodeCompletionResult::RK_Declaration: {
return !(Result.Declaration->getIdentifier() &&
Result.Declaration->getIdentifier()->getName().startswith(Filter));
}
case CodeCompletionResult::RK_Keyword: {
return !((StringRef(Result.Keyword)).startswith(Filter));
}
case CodeCompletionResult::RK_Macro: {
return !(Result.Macro->getName().startswith(Filter));
}
case CodeCompletionResult::RK_Pattern: {
return !(StringRef((Result.Pattern->getAsString())).startswith(Filter));
}
default: llvm_unreachable("Unknown code completion result Kind.");
}
}

View File

@ -1,49 +0,0 @@
#include "cling/Interpreter/ClingTabCompletion.h"
#include "cling/Interpreter/Interpreter.h"
#include "clang/Sema/Sema.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Frontend/CompilerInstance.h"
#include "cling/Interpreter/InterpreterCallbacks.h"
namespace cling {
bool ClingTabCompletion::Complete(const std::string& Line /*in+out*/,
size_t& Cursor /*in+out*/,
std::vector<std::string>& DisplayCompletions /*out*/) {
//Get the results
const char * const argV = "cling";
cling::Interpreter CodeCompletionInterp(ParentInterp, 1, &argV);
// Create the CodeCompleteConsumer with InterpreterCallbacks
// from the parent interpreter and set the consumer for the child
// interpreter
// Yuck! But I need the const/non-const to be fixed somehow.
const InterpreterCallbacks* callbacks = ParentInterp.getCallbacks();
callbacks->CreateCodeCompleteConsumer(&CodeCompletionInterp);
clang::CompilerInstance* codeCompletionCI = CodeCompletionInterp.getCI();
clang::Sema& codeCompletionSemaRef = codeCompletionCI->getSema();
// Ignore diagnostics when we tab complete
clang::IgnoringDiagConsumer* ignoringDiagConsumer = new clang::IgnoringDiagConsumer();
codeCompletionSemaRef.getDiagnostics().setClient(ignoringDiagConsumer, true);
auto Owner = ParentInterp.getCI()->getSema().getDiagnostics().takeClient();
auto Client = ParentInterp.getCI()->getSema().getDiagnostics().getClient();
ParentInterp.getCI()->getSema().getDiagnostics().setClient(ignoringDiagConsumer, false);
CodeCompletionInterp.codeComplete(Line, Cursor);
callbacks->GetCompletionResults(&CodeCompletionInterp, DisplayCompletions);
// Restore the original diag client for parent interpreter
ParentInterp.getCI()->getSema().getDiagnostics().setClient(Client, Owner.release() != nullptr);
// FIX-ME : Change it in the Incremental Parser
// It does not work even if I call unload in IncrementalParser, I think
// it would be to early.
CodeCompletionInterp.unload(1);
return true;
}
}

View File

@ -0,0 +1,294 @@
//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Elisavet Sakellari <elisavet.sakellari@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#include "ExternalInterpreterSource.h"
#include "cling/Interpreter/Interpreter.h"
#include "clang/Lex/Preprocessor.h"
using namespace clang;
namespace {
class ClingASTImporter : public ASTImporter {
private:
cling::ExternalInterpreterSource &m_Source;
public:
ClingASTImporter(ASTContext &ToContext, FileManager &ToFileManager,
ASTContext &FromContext, FileManager &FromFileManager,
bool MinimalImport, cling::ExternalInterpreterSource& source):
ASTImporter(ToContext, ToFileManager, FromContext, FromFileManager,
MinimalImport), m_Source(source) {}
Decl *Imported(Decl *From, Decl *To) override {
ASTImporter::Imported(From, To);
if (clang::TagDecl* toTagDecl = dyn_cast<TagDecl>(To)) {
toTagDecl->setHasExternalLexicalStorage();
toTagDecl->setMustBuildLookupTable();
}
if (NamespaceDecl *toNamespaceDecl = dyn_cast<NamespaceDecl>(To))
{
toNamespaceDecl->setHasExternalVisibleStorage();
}
if (ObjCContainerDecl *toContainerDecl = dyn_cast<ObjCContainerDecl>(To))
{
toContainerDecl->setHasExternalLexicalStorage();
toContainerDecl->setHasExternalVisibleStorage();
}
// Put the name of the Decl imported with the
// DeclarationName coming from the parent, in my map.
if (NamedDecl *fromNamedDecl = llvm::dyn_cast<NamedDecl>(From)) {
NamedDecl *toNamedDecl = llvm::dyn_cast<NamedDecl>(To);
m_Source.addToImportedDecls(toNamedDecl->getDeclName(),
fromNamedDecl->getDeclName());
}
if (DeclContext *fromDeclContext = llvm::dyn_cast<DeclContext>(From)) {
DeclContext *toDeclContext = llvm::dyn_cast<DeclContext>(To);
m_Source.addToImportedDeclContexts(toDeclContext, fromDeclContext);
}
return To;
}
};
}
namespace cling {
ExternalInterpreterSource::ExternalInterpreterSource(
const cling::Interpreter *parent, cling::Interpreter *child) :
m_ParentInterpreter(parent), m_ChildInterpreter(child) {
clang::DeclContext *parentTUDeclContext =
m_ParentInterpreter->getCI()->getASTContext().getTranslationUnitDecl();
clang::DeclContext *childTUDeclContext =
m_ChildInterpreter->getCI()->getASTContext().getTranslationUnitDecl();
// Also keep in the map of Decl Contexts the Translation Unit Decl Context
m_ImportedDeclContexts[childTUDeclContext] = parentTUDeclContext;
}
ClingASTImporter CreateClingASTImporter(ASTContext &toContext,
ASTContext &fromContext,
const Interpreter* child,
const Interpreter* parent,
ExternalInterpreterSource& source) {
FileManager &childFM = child->getCI()->getFileManager();
FileManager &parentFM = parent->getCI()->getFileManager();
return ClingASTImporter(toContext, childFM, fromContext, parentFM,
/*MinimalImport : ON*/ true, source);
}
void ExternalInterpreterSource::ImportDecl(Decl *declToImport,
ASTImporter &importer,
DeclarationName &childDeclName,
DeclarationName &parentDeclName,
const DeclContext *childCurrentDeclContext) {
// Don't do the import if we have a Function Template.
// Not supported by clang.
// FIXME: This is also a temporary check. Will be de-activated
// once clang supports the import of function templates.
if (declToImport->isFunctionOrFunctionTemplate()
&& declToImport->isTemplateDecl())
return;
if (Decl *importedDecl = importer.Import(declToImport)) {
if (NamedDecl *importedNamedDecl = llvm::dyn_cast<NamedDecl>(importedDecl)) {
llvm::ArrayRef <NamedDecl*> FoundDecls(importedNamedDecl);
SetExternalVisibleDeclsForName(childCurrentDeclContext,
importedNamedDecl->getDeclName(),
FoundDecls);
}
// Put the name of the Decl imported with the
// DeclarationName coming from the parent, in my map.
m_ImportedDecls[childDeclName] = parentDeclName;
}
}
void ExternalInterpreterSource::ImportDeclContext(
DeclContext *declContextToImport,
ASTImporter &importer,
DeclarationName &childDeclName,
DeclarationName &parentDeclName,
const DeclContext *childCurrentDeclContext) {
if (DeclContext *importedDeclContext =
importer.ImportContext(declContextToImport)) {
importedDeclContext->setHasExternalVisibleStorage(true);
if (NamedDecl *importedNamedDecl =
llvm::dyn_cast<NamedDecl>(importedDeclContext)) {
llvm::ArrayRef <NamedDecl*> FoundDecls(importedNamedDecl);
SetExternalVisibleDeclsForName(childCurrentDeclContext,
importedNamedDecl->getDeclName(),
FoundDecls);
}
// Put the name of the DeclContext imported with the
// DeclarationName coming from the parent, in my map.
m_ImportedDecls[childDeclName] = parentDeclName;
// And also put the declaration context I found from the parent Interpreter
// in the map of the child Interpreter to have it for the future.
m_ImportedDeclContexts[importedDeclContext] = declContextToImport;
}
}
bool ExternalInterpreterSource::Import(DeclContext::lookup_result lookup_result,
ASTContext &fromASTContext,
ASTContext &toASTContext,
const DeclContext *childCurrentDeclContext,
DeclarationName &childDeclName,
DeclarationName &parentDeclName) {
// Cling's ASTImporter
ClingASTImporter importer = CreateClingASTImporter(toASTContext,
fromASTContext,
m_ChildInterpreter,
m_ParentInterpreter,
*this);
for (DeclContext::lookup_iterator I = lookup_result.begin(),
E = lookup_result.end(); I != E; ++I) {
// Check if this Name we are looking for is
// a DeclContext (for example a Namespace, function etc.).
if (DeclContext *declContextToImport = llvm::dyn_cast<DeclContext>(*I)) {
ImportDeclContext(declContextToImport, importer, childDeclName,
parentDeclName, childCurrentDeclContext);
} else if (Decl *declToImport = llvm::dyn_cast<Decl>(*I)) {
// else it is a Decl
ImportDecl(declToImport, importer, childDeclName,
parentDeclName, childCurrentDeclContext);
}
}
return true;
}
///\brief This is the one of the most important function of the class
/// since from here initiates the lookup and import part of the missing
/// Decl(s) (Contexts).
///
bool ExternalInterpreterSource::FindExternalVisibleDeclsByName(
const DeclContext *childCurrentDeclContext, DeclarationName childDeclName) {
assert(childDeclName && "Child Decl name is empty");
assert(childCurrentDeclContext->hasExternalVisibleStorage() &&
"DeclContext has no visible decls in storage");
//Check if we have already found this declaration Name before
DeclarationName parentDeclName;
std::map<clang::DeclarationName,
clang::DeclarationName>::iterator IDecl =
m_ImportedDecls.find(childDeclName);
if (IDecl != m_ImportedDecls.end()) {
parentDeclName = IDecl->second;
} else {
// Get the identifier info from the parent interpreter
// for this Name.
std::string name = childDeclName.getAsString();
IdentifierTable &parentIdentifierTable =
m_ParentInterpreter->getCI()->getASTContext().Idents;
IdentifierInfo &parentIdentifierInfo =
parentIdentifierTable.get(name);
parentDeclName = DeclarationName(&parentIdentifierInfo);
}
// Search in the map of the stored Decl Contexts for this
// Decl Context.
std::map<const clang::DeclContext *, clang::DeclContext *>::iterator
IDeclContext = m_ImportedDeclContexts.find(childCurrentDeclContext);
// If childCurrentDeclContext was found before and is already in the map,
// then do the lookup using the stored pointer.
if (IDeclContext == m_ImportedDeclContexts.end()) return false;
DeclContext *parentDeclContext = IDeclContext->second;
DeclContext::lookup_result lookup_result =
parentDeclContext->lookup(parentDeclName);
// Check if we found this Name in the parent interpreter
if (!lookup_result.empty()) {
// Do the import
ASTContext &fromASTContext =
Decl::castFromDeclContext(parentDeclContext)->getASTContext();
ASTContext &toASTContext =
Decl::castFromDeclContext(childCurrentDeclContext)->getASTContext();
if (Import(lookup_result, fromASTContext, toASTContext,
childCurrentDeclContext, childDeclName, parentDeclName))
return true;
}
return false;
}
///\brief Make available to child all decls in parent's decl context
/// that corresponds to child decl context.
void ExternalInterpreterSource::completeVisibleDeclsMap(
const clang::DeclContext *childDeclContext) {
assert (childDeclContext && "No child decl context!");
if (!childDeclContext->hasExternalVisibleStorage())
return;
// Search in the map of the stored Decl Contexts for this
// Decl Context.
std::map<const clang::DeclContext *, clang::DeclContext *>::iterator
IDeclContext = m_ImportedDeclContexts.find(childDeclContext);
// If childCurrentDeclContext was found before and is already in the map,
// then do the lookup using the stored pointer.
if (IDeclContext == m_ImportedDeclContexts.end()) return ;
DeclContext *parentDeclContext = IDeclContext->second;
ASTContext &fromASTContext =
Decl::castFromDeclContext(parentDeclContext)->getASTContext();
ASTContext &toASTContext =
Decl::castFromDeclContext(childDeclContext)->getASTContext();
// Cling's ASTImporter
ClingASTImporter importer = CreateClingASTImporter(toASTContext,
fromASTContext,
m_ChildInterpreter,
m_ParentInterpreter,
*this);
// Filter the decls from the external source using the stem information
// stored in Sema.
StringRef filter =
m_ChildInterpreter->getCI()->getPreprocessor().getCodeCompletionFilter();
for (DeclContext::decl_iterator IDeclContext =
parentDeclContext->decls_begin(),
EDeclContext =
parentDeclContext->decls_end();
IDeclContext != EDeclContext; ++IDeclContext) {
if (NamedDecl* parentDecl = llvm::dyn_cast<NamedDecl>(*IDeclContext)) {
DeclarationName childDeclName = parentDecl->getDeclName();
if (auto II = childDeclName.getAsIdentifierInfo()) {
StringRef name = II->getName();
if (!name.empty() && name.startswith(filter))
ImportDecl(parentDecl, importer, childDeclName, childDeclName,
childDeclContext);
}
}
}
const_cast<DeclContext *>(childDeclContext)->
setHasExternalVisibleStorage(false);
}
} // end namespace cling

View File

@ -6,8 +6,9 @@
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#ifndef CLING_ASTIMPORTSOURCE_H
#define CLING_ASTIMPORTSOURCE_H
#ifndef CLING_EXTERNAL_INTERPRETER_SOURCE
#define CLING_EXTERNAL_INTERPRETER_SOURCE
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Sema/Sema.h"
@ -32,11 +33,11 @@ namespace cling {
namespace cling {
class ASTImportSource : public clang::ExternalASTSource {
class ExternalInterpreterSource : public clang::ExternalASTSource {
private:
const cling::Interpreter *m_parent_Interp;
cling::Interpreter *m_child_Interp;
const cling::Interpreter *m_ParentInterpreter;
cling::Interpreter *m_ChildInterpreter;
clang::Sema *m_Sema;
@ -45,7 +46,7 @@ namespace cling {
/// Key: imported DeclContext
/// Value: original DeclContext
///
std::map<const clang::DeclContext *, clang::DeclContext *> m_DeclContexts_map;
std::map<const clang::DeclContext *, clang::DeclContext *> m_ImportedDeclContexts;
///\brief A map for all the imported Decls (Contexts)
/// according to their names.
@ -53,26 +54,26 @@ namespace cling {
/// Value: The DeclarationName of this Decl(Context) is the one
/// that comes from the first Interpreter.
///
std::map <clang::DeclarationName, clang::DeclarationName > m_DeclName_map;
std::map <clang::DeclarationName, clang::DeclarationName > m_ImportedDecls;
public:
ASTImportSource(const cling::Interpreter *parent_interpreter,
cling::Interpreter *child_interpreter);
~ASTImportSource() { };
ExternalInterpreterSource(const cling::Interpreter *parent,
cling::Interpreter *child);
~ExternalInterpreterSource() { };
void completeVisibleDeclsMap(const clang::DeclContext *DC) override;
bool FindExternalVisibleDeclsByName(const clang::DeclContext *childCurrentDeclContext,
clang::DeclarationName childDeclName) override;
bool FindExternalVisibleDeclsByName(
const clang::DeclContext *childCurrentDeclContext,
clang::DeclarationName childDeclName) override;
void InitializeSema(clang::Sema &S) { m_Sema = &S; }
void ForgetSema() { m_Sema = nullptr; }
bool Import(clang::DeclContext::lookup_result lookup_result,
clang::ASTContext &from_ASTContext,
clang::ASTContext &to_ASTContext,
bool Import(clang::DeclContext::lookup_result lookupResult,
clang::ASTContext &parentASTContext,
clang::ASTContext &childASTContext,
const clang::DeclContext *childCurrentDeclContext,
clang::DeclarationName &childDeclName,
clang::DeclarationName &parentDeclName);
@ -89,10 +90,16 @@ namespace cling {
clang::DeclarationName &parentDeclName,
const clang::DeclContext *childCurrentDeclContext);
void addToDeclContext(clang::DeclContext *child,
void addToImportedDecls(clang::DeclarationName child,
clang::DeclarationName parent) {
m_ImportedDecls[child] = parent;
}
void addToImportedDeclContexts(clang::DeclContext *child,
clang::DeclContext *parent) {
m_DeclContexts_map[child] = parent;
m_ImportedDeclContexts[child] = parent;
}
};
} // end namespace cling
#endif //CLING_ASTIMPORTSOURCE_H

View File

@ -714,18 +714,26 @@ namespace cling {
llvm::MemoryBuffer* MBNonOwn = MB.get();
// Create FileEntry and FileID for the current buffer
const clang::FileEntry* FE
= SM.getFileManager().getVirtualFile("vfile for " + source_name.str(),
InputSize, 0 /* mod time*/);
SM.overrideFileContents(FE, std::move(MB));
FileID FID = SM.createFileID(FE, NewLoc, SrcMgr::C_User);
// Create FileID for the current buffer.
FileID FID;
if (CO.CodeCompletionOffset == -1)
{
FID = SM.createFileID(std::move(MB), SrcMgr::C_User,
/*LoadedID*/0,
/*LoadedOffset*/0, NewLoc);
} else {
// Create FileEntry and FileID for the current buffer.
// Enabling the completion point only works on FileEntries.
const clang::FileEntry* FE
= SM.getFileManager().getVirtualFile("vfile for " + source_name.str(),
InputSize, 0 /* mod time*/);
SM.overrideFileContents(FE, std::move(MB));
FID = SM.createFileID(FE, NewLoc, SrcMgr::C_User);
// Set the code completion point if completion is enabled.
if (CO.CodeCompletionOffset != -1) {
printf("Is it really the completion point?\n");
PP.SetCodeCompletionPoint(FE, 1, 45 + CO.CodeCompletionOffset);
m_Interpreter->unload(1);
// The completion point is set one a 1-based line/column numbering.
// It relies on the implementation to account for the wrapper extra line.
PP.SetCodeCompletionPoint(FE, 1/* start point 1-based line*/,
CO.CodeCompletionOffset+1/* 1-based column*/);
}
m_MemoryBuffers.push_back(std::make_pair(MBNonOwn, FID));
@ -778,7 +786,11 @@ namespace cling {
};
if (CO.CodeCompletionOffset != -1) {
assert(PP.isCodeCompletionReached() && "Code completion set but not reached!");
SourceLocation completionLoc = PP.getCodeCompletionLoc();
assert (SM.getFileOffset(completionLoc) == CO.CodeCompletionOffset
&& "Completion point wrongly set!");
assert(PP.isCodeCompletionReached()
&& "Code completion set but not reached!");
return kSuccess;
}

View File

@ -13,6 +13,7 @@
#include "cling-compiledata.h"
#include "ASTImportSource.h"
#include "DynamicLookup.h"
#include "ExternalInterpreterSource.h"
#include "ForwardDeclPrinter.h"
#include "IncrementalExecutor.h"
#include "IncrementalParser.h"
@ -21,6 +22,7 @@
#include "cling/Interpreter/CIFactory.h"
#include "cling/Interpreter/ClangInternalState.h"
#include "cling/Interpreter/ClingCodeCompleteConsumer.h"
#include "cling/Interpreter/CompilationOptions.h"
#include "cling/Interpreter/DynamicLibraryManager.h"
#include "cling/Interpreter/LookupHelper.h"
@ -245,8 +247,8 @@ namespace cling {
// its parent interpreter.
// The "bridge" between the interpreters.
ASTImportSource *myExternalSource =
new ASTImportSource(&parentInterpreter, this);
ExternalInterpreterSource *myExternalSource =
new ExternalInterpreterSource(&parentInterpreter, this);
llvm::IntrusiveRefCntPtr <ExternalASTSource>
astContextExternalSource(myExternalSource);
@ -641,7 +643,7 @@ namespace cling {
Interpreter::CompilationResult
Interpreter::codeComplete(const std::string& input, unsigned offset) {
Interpreter::CodeCompleteInternal(const std::string& input, unsigned offset) {
CompilationOptions CO;
CO.DeclarationExtraction = 0;
@ -656,7 +658,7 @@ namespace cling {
std::string wrappedInput = input;
std::string wrapperName;
if (ShouldWrapInput(input))
WrapInput(wrappedInput, wrapperName);
WrapInput(wrappedInput, wrapperName, CO);
StateDebuggerRAII stateDebugger(this);
@ -694,6 +696,65 @@ namespace cling {
return EvaluateInternal(input, CO, &V);
}
Interpreter::CompilationResult
Interpreter::codeComplete(const std::string& line, size_t& cursor,
std::vector<std::string>& completions) const {
const char * const argV = "cling";
std::string llvmdir = this->getCI()->getHeaderSearchOpts().ResourceDir;
StringRef Dir = llvm::sys::path::parent_path(
llvm::sys::path::parent_path(
llvm::sys::path::parent_path(llvmdir)));
/*std::string extra_part = "/lib/clang/3.9.0";
std::string::size_type i = llvmdir.find(extra_part);
if (i != std::string::npos)
llvmdir.erase(i, extra_part.length());*/
cling::Interpreter childInterpreter(*this, 1, &argV, llvmdir.c_str());
auto childCI = childInterpreter.getCI();
clang::Sema &childSemaRef = childCI->getSema();
// Create the CodeCompleteConsumer with InterpreterCallbacks
// from the parent interpreter and set the consumer for the child
// interpreter.
ClingCodeCompleteConsumer* consumer = new ClingCodeCompleteConsumer(
this->getCI()->getFrontendOpts().CodeCompleteOpts, llvm::errs(),
completions);
// Child interpreter CI will own consumer!
childCI->setCodeCompletionConsumer(consumer);
childSemaRef.CodeCompleter = consumer;
// Ignore diagnostics when we tab complete.
// This is because we get redefinition errors due to the import of the decls.
clang::IgnoringDiagConsumer* ignoringDiagConsumer =
new clang::IgnoringDiagConsumer();
childSemaRef.getDiagnostics().setClient(ignoringDiagConsumer, true);
DiagnosticsEngine& parentDiagnostics = this->getCI()->getSema().getDiagnostics();
std::unique_ptr<DiagnosticConsumer> ownerDiagConsumer =
parentDiagnostics.takeClient();
auto clientDiagConsumer = parentDiagnostics.getClient();
parentDiagnostics.setClient(ignoringDiagConsumer, /*owns*/ false);
// The child will desirialize decls from *this. We need a transaction RAII.
PushTransactionRAII RAII(this);
// Triger the code completion.
childInterpreter.CodeCompleteInternal(line, cursor);
// Restore the original diagnostics client for parent interpreter.
parentDiagnostics.setClient(clientDiagConsumer,
ownerDiagConsumer.release() != nullptr);
// FIX-ME : Change it in the Incremental Parser
// It does not work by call unload in IncrementalParser, might be to early.
childInterpreter.unload(1);
return kSuccess;
}
Interpreter::CompilationResult
Interpreter::echo(const std::string& input, Value* V /* = 0 */) {
CompilationOptions CO;
@ -815,9 +876,14 @@ namespace cling {
return true;
}
void Interpreter::WrapInput(std::string& input, std::string& fname) {
void Interpreter::WrapInput(std::string& input, std::string& fname,
CompilationOptions &CO) {
fname = createUniqueWrapper();
input.insert(0, "void " + fname + "(void* vpClingValue) {\n ");
std::string wrapperHeader = "void " + fname + "(void* vpClingValue) {\n ";
if (CO.CodeCompletionOffset != -1) {
CO.CodeCompletionOffset += wrapperHeader.size();
}
input.insert(0, wrapperHeader);
input.append("\n;\n}");
}
@ -1069,7 +1135,7 @@ namespace cling {
// Wrap the expression
std::string WrapperName;
std::string Wrapper = input;
WrapInput(Wrapper, WrapperName);
WrapInput(Wrapper, WrapperName, CO);
// We have wrapped and need to disable warnings that are caused by
// non-default C++ at the prompt:
@ -1440,46 +1506,6 @@ namespace cling {
T.setState(Transaction::kCommitted);
}
void Interpreter::CodeComplete(const std::string& Line, size_t& Cursor,
std::vector<std::string>& DisplayCompletions) const {
//Get the results
const char * const argV = "cling";
std::string llvmdir = this->getCI()->getHeaderSearchOpts().ResourceDir;
std::string extra_part = "/lib/clang/3.9.0";
std::string::size_type i = llvmdir.find(extra_part);
if (i != std::string::npos)
llvmdir.erase(i, extra_part.length());
cling::Interpreter CodeCompletionInterp(*this, 1, &argV, llvmdir.c_str());
// Create the CodeCompleteConsumer with InterpreterCallbacks
// from the parent interpreter and set the consumer for the child
// interpreter
// Yuck! But I need the const/non-const to be fixed somehow.
const InterpreterCallbacks* callbacks = this->getCallbacks();
callbacks->CreateCodeCompleteConsumer(&CodeCompletionInterp);
clang::CompilerInstance* codeCompletionCI = CodeCompletionInterp.getCI();
clang::Sema& codeCompletionSemaRef = codeCompletionCI->getSema();
// Ignore diagnostics when we tab complete
clang::IgnoringDiagConsumer* ignoringDiagConsumer = new clang::IgnoringDiagConsumer();
codeCompletionSemaRef.getDiagnostics().setClient(ignoringDiagConsumer, true);
auto Owner = this->getCI()->getSema().getDiagnostics().takeClient();
auto Client = this->getCI()->getSema().getDiagnostics().getClient();
this->getCI()->getSema().getDiagnostics().setClient(ignoringDiagConsumer, false);
// The child will desirialize decls from *this, we need a transaction
PushTransactionRAII RAII(this);
CodeCompletionInterp.codeComplete(Line, Cursor);
callbacks->GetCompletionResults(&CodeCompletionInterp, DisplayCompletions);
// Restore the original diag client for parent interpreter
this->getCI()->getSema().getDiagnostics().setClient(Client, Owner.release() != nullptr);
// FIX-ME : Change it in the Incremental Parser
// It does not work even if I call unload in IncrementalParser, I think
// it would be to early.
CodeCompletionInterp.unload(1);
}
} //end namespace cling

View File

@ -9,8 +9,6 @@
#include "cling/Interpreter/InterpreterCallbacks.h"
#include "cling/Interpreter/ClingTabCompletion.h"
#include "cling/Interpreter/ClingCodeCompleteConsumer.h"
#include "cling/Interpreter/Interpreter.h"
#include "clang/AST/ASTContext.h"
@ -242,32 +240,6 @@ namespace cling {
return false;
}
void InterpreterCallbacks::CreateCodeCompleteConsumer(Interpreter* child) const {
ClingCodeCompleteConsumer* consumer = new ClingCodeCompleteConsumer(
m_Interpreter->getCI()->getFrontendOpts().CodeCompleteOpts,
llvm::outs());
CompilerInstance* childCI = child->getCI();
//codeCompletionCI will own consumer!
childCI->setCodeCompletionConsumer(consumer);
clang::Sema& childSemaRef = childCI->getSema();
childSemaRef.CodeCompleter = consumer;
}
void InterpreterCallbacks::GetCompletionResults(Interpreter* child,
std::vector<std::string>& completions) const {
// Which cast to use , fno-rtti
ClingCodeCompleteConsumer* consumer =
(ClingCodeCompleteConsumer*)(
child->getCI()->getSema().CodeCompleter);
if (consumer)
consumer->getCompletions(completions);
}
void InterpreterCallbacks::CodeComplete(const std::string& line, size_t& cursor,
std::vector<std::string>& displayCompletions) const {
m_Interpreter->CodeComplete(line, cursor, displayCompletions);
}
void InterpreterCallbacks::UpdateWithNewDecls(const DeclContext *DC,
DeclarationName Name,
llvm::ArrayRef<NamedDecl*> Decls) {

View File

@ -1,30 +0,0 @@
#ifndef TABCOMPLETION_H
#define TABCOMPLETION_H
#include "textinput/Callbacks.h"
namespace textinput {
class TabCompletion;
class Text;
class EditorRange;
}
namespace cling {
class TabCompletion : public textinput::TabCompletion {
const cling::Interpreter& ParentInterp;
public:
TabCompletion(cling::Interpreter& Parent) : ParentInterp(Parent) {}
~TabCompletion() {}
bool Complete(textinput::Text& Line /*in+out*/,
size_t& Cursor /*in+out*/,
textinput::EditorRange& R /*out*/,
std::vector<std::string>& DisplayCompletions /*out*/) override {
const InterpreterCallbacks* callbacks = ParentInterp.getCallbacks();
callbacks->Complete(Line.GetText(), Cursor, DisplayCompletions);
}
};
}
#endif

View File

@ -86,6 +86,28 @@ namespace {
#endif
}
namespace {
///\brief Class that specialises the textinput TabCompletion to allow Cling
/// to code complete through its own textinput mechanism which is part of the
/// UserInterface.
///
class TabCompletion : public textinput::TabCompletion {
const Interpreter& m_ParentInterpreter;
public:
TabCompletion(const Interpreter& Parent) : m_ParentInterpreter(Parent) {}
~TabCompletion() {}
bool Complete(textinput::Text& Line /*in+out*/,
size_t& Cursor /*in+out*/,
textinput::EditorRange& R /*out*/,
std::vector<std::string>& DisplayCompletions /*out*/) override {
m_ParentInterpreter->codeComplete(Line.GetText(), Cursor,
DisplayCompletions);
}
};
}
namespace cling {
// Declared in CompilationException.h; vtable pinned here.
CompilationException::~CompilationException() throw() {}
@ -120,10 +142,10 @@ namespace cling {
TextInput TI(*R, *D, histfilePath.empty() ? 0 : histfilePath.c_str());
// Inform text input about the code complete consumer
cling::TabCompletion* Completion = new cling::TabCompletion(m_MetaProcessor->getInterpreter());
// TextInput owns the TabCompletion.
TabCompletion* Completion = new cling::TabCompletion(m_MetaProcessor->getInterpreter());
TI.SetCompletion(Completion);
TI.SetPrompt("[cling]$ ");
std::string line;
while (true) {