Refactoring ROOT & Cling code completion.
This commit is contained in:
parent
e3d5b485e9
commit
528b16faf6
@ -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
|
||||
|
@ -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
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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()).
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
294
lib/Interpreter/ExternalInterpreterSource.cpp
Normal file
294
lib/Interpreter/ExternalInterpreterSource.cpp
Normal 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
|
@ -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
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user